feat: Support labels for arrow 🔥 (#5723)

* feat: support arrow with text

* render arrow -> clear rect-> render text

* move bound text when linear elements move

* fix centering cursor when linear element rotated

* fix y coord when new line added and container has 3 points

* update text position when 2nd point moved

* support adding label on top of 2nd point when 3 points are present

* change linear element editor shortcut to cmd+enter and fix tests

* scale bound text points when resizing via bounding box

* ohh yeah rotation works :)

* fix coords when updating text properties

* calculate new position after rotation always from original position

* rotate the bound text by same angle as parent

* don't rotate text and make sure dimensions and coords are always calculated from original point

* hardcoding the text width for now

* Move the linear element when bound text hit

* Rotation working yaay

* consider text element angle when editing

* refactor

* update x2 coords if needed when text updated

* simplify

* consider bound text to be part of bounding box when hit

* show bounding box correctly when multiple element selected

* fix typo

* support rotating multiple elements

* support multiple element resizing

* shift bound text to mid point when odd points

* Always render linear element handles inside editor after element rendered so point is visible for bound text

* Delete bound text when point attached to it deleted

* move bound to mid segement mid point when points are even

* shift bound text when points nearby deleted and handle segment deletion

* Resize working :)

* more resize fixes

* don't update cache-its breaking delete points, look for better soln

* update mid point cache for bound elements when updated

* introduce wrapping when resizing

* wrap when resize for 2 pointer linear elements

* support adding text for linear elements with more than 3 points

* export to svg  working :)

* clip from nearest enclosing element with non transparent color if present when exporting and fill with correct color in canvas

* fix snap

* use visible elements

* Make export to svg work with Mask :)

* remove id

* mask canvas linear element area where label is added

* decide the position of bound text during render

* fix coords when editing

* fix multiple resize

* update cache when bound text version changes

* fix masking when rotated

* render text in correct position in preview

* remove unnecessary code

* fix masking when rotating linear element

* fix masking with zoom

* fix mask in preview for export

* fix offsets in export view

* fix coords on svg export

* fix mask when element rotated in svg

* enable double-click to enter text

* fix hint

* Position cursor correctly and text dimensiosn when height of element is negative

* don't allow 2 pointer linear element with bound text width to go beyond min width

* code cleanup

* fix freedraw

* Add padding

* don't show vertical align action for linear element containers

* Add specs for getBoundTextElementPosition

* more specs

* move some utils to linearElementEditor.ts

* remove only :p

* check absoulte coods in test

* Add test to hide vertical align for linear eleemnt with bound text

* improve export preview

* support labels only for arrows

* spec

* fix large texts

* fix tests

* fix zooming

* enter line editor with cmd+double click

* Allow points to move beyond min width/height for 2 pointer arrow with bound text

* fix hint for line editing

* attempt to fix arrow getting deselected

* fix hint and shortcut

* Add padding of 5px when creating bound text and add spec

* Wrap bound text when arrow binding containers moved

* Add spec

* remove

* set boundTextElementVersion to null if not present

* dont use cache when version mismatch

* Add a padding of 5px vertically when creating text

* Add box sizing content box

* Set bound elements when text element created to fix the padding

* fix zooming in editor

* fix zoom in export

* remove globalCompositeOperation and use clearRect instead of fillRect
This commit is contained in:
Aakansha Doshi 2022-12-05 21:03:13 +05:30 committed by GitHub
parent 1933116261
commit 760fd7b3a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 1668 additions and 363 deletions

View file

@ -348,7 +348,6 @@ export const _renderScene = ({
context.setTransform(1, 0, 0, 1, 0, 0);
context.save();
context.scale(scale, scale);
// When doing calculations based on canvas width we should used normalized one
const normalizedCanvasWidth = canvas.width / scale;
const normalizedCanvasHeight = canvas.height / scale;
@ -410,7 +409,7 @@ export const _renderScene = ({
undefined;
visibleElements.forEach((element) => {
try {
renderElement(element, rc, context, renderConfig);
renderElement(element, rc, context, renderConfig, appState);
// Getting the element using LinearElementEditor during collab mismatches version - being one head of visible elements due to
// ShapeCache returns empty hence making sure that we get the
// correct element from visible elements
@ -440,7 +439,13 @@ export const _renderScene = ({
// Paint selection element
if (appState.selectionElement) {
try {
renderElement(appState.selectionElement, rc, context, renderConfig);
renderElement(
appState.selectionElement,
rc,
context,
renderConfig,
appState,
);
} catch (error: any) {
console.error(error);
}
@ -453,6 +458,22 @@ export const _renderScene = ({
renderBindingHighlight(context, renderConfig, suggestedBinding!);
});
}
const locallySelectedElements = getSelectedElements(elements, appState);
// Getting the element using LinearElementEditor during collab mismatches version - being one head of visible elements due to
// ShapeCache returns empty hence making sure that we get the
// correct element from visible elements
if (
locallySelectedElements.length === 1 &&
appState.editingLinearElement?.elementId === locallySelectedElements[0].id
) {
renderLinearPointHandles(
context,
appState,
renderConfig,
locallySelectedElements[0] as NonDeleted<ExcalidrawLinearElement>,
);
}
if (
appState.selectedLinearElement &&
@ -466,7 +487,6 @@ export const _renderScene = ({
!appState.multiElement &&
!appState.editingLinearElement
) {
const locallySelectedElements = getSelectedElements(elements, appState);
const showBoundingBox = shouldShowBoundingBox(
locallySelectedElements,
appState,
@ -515,8 +535,8 @@ export const _renderScene = ({
}
if (selectionColors.length) {
const [elementX1, elementY1, elementX2, elementY2] =
getElementAbsoluteCoords(element);
const [elementX1, elementY1, elementX2, elementY2, cx, cy] =
getElementAbsoluteCoords(element, true);
acc.push({
angle: element.angle,
elementX1,
@ -525,10 +545,12 @@ export const _renderScene = ({
elementY2,
selectionColors,
dashed: !!renderConfig.remoteSelectedElementIds[element.id],
cx,
cy,
});
}
return acc;
}, [] as { angle: number; elementX1: number; elementY1: number; elementX2: number; elementY2: number; selectionColors: string[]; dashed?: boolean }[]);
}, [] as { angle: number; elementX1: number; elementY1: number; elementX2: number; elementY2: number; selectionColors: string[]; dashed?: boolean; cx: number; cy: number }[]);
const addSelectionForGroupId = (groupId: GroupId) => {
const groupElements = getElementsInGroup(elements, groupId);
@ -540,8 +562,10 @@ export const _renderScene = ({
elementX2,
elementY1,
elementY2,
selectionColors: [selectionColor],
selectionColors: [oc.black],
dashed: true,
cx: elementX1 + (elementX2 - elementX1) / 2,
cy: elementY1 + (elementY2 - elementY1) / 2,
});
};
@ -600,7 +624,7 @@ export const _renderScene = ({
context.lineWidth = lineWidth;
context.setLineDash(initialLineDash);
const transformHandles = getTransformHandlesFromCoords(
[x1, y1, x2, y2],
[x1, y1, x2, y2, (x1 + x2) / 2, (y1 + y2) / 2],
0,
renderConfig.zoom,
"mouse",
@ -861,6 +885,8 @@ const renderSelectionBorder = (
elementY2: number;
selectionColors: string[];
dashed?: boolean;
cx: number;
cy: number;
},
padding = DEFAULT_SPACING * 2,
) => {
@ -871,6 +897,8 @@ const renderSelectionBorder = (
elementX2,
elementY2,
selectionColors,
cx,
cy,
dashed,
} = elementProperties;
const elementWidth = elementX2 - elementX1;
@ -900,8 +928,8 @@ const renderSelectionBorder = (
elementY1 - linePadding,
elementWidth + linePadding * 2,
elementHeight + linePadding * 2,
elementX1 + elementWidth / 2,
elementY1 + elementHeight / 2,
cx,
cy,
angle,
);
}
@ -1117,7 +1145,7 @@ export const renderSceneToSvg = (
return;
}
// render elements
elements.forEach((element) => {
elements.forEach((element, index) => {
if (!element.isDeleted) {
try {
renderElementToSvg(