From d8c901e0c1d12e0d1716adbec91d06292b99c9ac Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Mon, 22 May 2023 21:22:36 +0530 Subject: [PATCH] support arrow bindings via start and end in api --- src/data/types.ts | 18 +++++++ src/element/binding.ts | 2 +- src/element/newElement.ts | 98 ++++++++++++++++++++++++++++++++++++-- src/element/textElement.ts | 8 +--- 4 files changed, 114 insertions(+), 12 deletions(-) diff --git a/src/data/types.ts b/src/data/types.ts index 58cb421e2e..396116d9d9 100644 --- a/src/data/types.ts +++ b/src/data/types.ts @@ -1,5 +1,7 @@ import { + ExcalidrawBindableElement, ExcalidrawElement, + ExcalidrawLinearElement, FontFamilyValues, TextAlign, VerticalAlign, @@ -71,6 +73,22 @@ export interface ImportedDataState { type: "text"; text: string; } & ElementConstructorOpts) + | ({ + type: "arrow"; + label?: { + text: string; + fontSize?: number; + fontFamily?: FontFamilyValues; + textAlign?: TextAlign; + verticalAlign?: VerticalAlign; + } & MarkOptional; + start?: { + type: ExcalidrawBindableElement["type"] & ElementConstructorOpts; + }; + end?: { + type: ExcalidrawBindableElement["type"] & ElementConstructorOpts; + }; + } & ElementConstructorOpts) )[] | null; appState?: Readonly< diff --git a/src/element/binding.ts b/src/element/binding.ts index b5ae041bdf..5e2875e549 100644 --- a/src/element/binding.ts +++ b/src/element/binding.ts @@ -190,7 +190,7 @@ export const maybeBindLinearElement = ( } }; -const bindLinearElement = ( +export const bindLinearElement = ( linearElement: NonDeleted, hoveredElement: ExcalidrawBindableElement, startOrEnd: "start" | "end", diff --git a/src/element/newElement.ts b/src/element/newElement.ts index cbb42a2097..bd3123a4cd 100644 --- a/src/element/newElement.ts +++ b/src/element/newElement.ts @@ -12,6 +12,7 @@ import { ExcalidrawFreeDrawElement, FontFamilyValues, ExcalidrawTextContainer, + ExcalidrawBindableElement, } from "../element/types"; import { arrayToMap, @@ -49,6 +50,7 @@ import { import { isArrowElement } from "./typeChecks"; import { MarkOptional, Merge, Mutable } from "../utility-types"; import { ImportedDataState } from "../data/types"; +import { bindLinearElement } from "./binding"; export const ELEMENTS_SUPPORTING_PROGRAMMATIC_API = [ "rectangle", @@ -670,30 +672,116 @@ export const convertToExcalidrawElements = ( res.push(element as ExcalidrawElement); return; } + let startBoundElement; + let endBoundElement; //@ts-ignore if (VALID_CONTAINER_TYPES.has(element.type) && element?.label?.text) { //@ts-ignore const elements = bindTextToContainer(element, element.label); - res.push(...elements); + const [container, text] = elements; + + if (container.type === "arrow") { + //@ts-ignore + const { start, end } = element; + if (start) { + const width = start?.width ?? 100; + const height = start?.height ?? 100; + + startBoundElement = newElement({ + x: start.x || container.x - width, + y: start.y || container.y - height / 2, + width, + height, + ...start, + }) as ExcalidrawBindableElement; + bindLinearElement( + container as ExcalidrawLinearElement, + startBoundElement, + "start", + ); + } + if (end) { + const height = end?.height ?? 100; + + endBoundElement = newElement({ + x: end.x || container.x + container.width, + y: end.y || container.y - height / 2, + width: end?.width ?? 100, + height, + ...end, + }) as ExcalidrawBindableElement; + bindLinearElement( + container as ExcalidrawLinearElement, + endBoundElement, + "end", + ); + } + } + res.push(container); + res.push(text); + if (startBoundElement) { + res.push(startBoundElement); + } + if (endBoundElement) { + res.push(endBoundElement); + } } else { let excalidrawElement; - const { type, ...rest } = element; if (element.type === "text") { excalidrawElement = { ...element, } as ExcalidrawTextElement; - } else if (type === "arrow" || type === "line") { + res.push(excalidrawElement); + } else if (element.type === "arrow" || element.type === "line") { + //@ts-ignore + const { start, end, type, endArrowHead, ...rest } = element; + excalidrawElement = { type, width: 200, height: 24, - endArrowhead: element.type === "arrow" ? "arrow" : null, points: [ [0, 0], [200, 0], ], + endArrowhead: endArrowHead || type === "arrow" ? "arrow" : null, ...rest, } as ExcalidrawLinearElement; + + let startBoundElement; + let endBoundElement; + if (start) { + const width = start?.width ?? 100; + const height = start?.height ?? 100; + startBoundElement = newElement({ + x: start.x || excalidrawElement.x - width, + y: start.y || excalidrawElement.y - height / 2, + width, + height, + ...start, + }) as ExcalidrawBindableElement; + bindLinearElement(excalidrawElement, startBoundElement, "start"); + } + if (end) { + const height = end?.height ?? 100; + + endBoundElement = newElement({ + x: end.x || excalidrawElement.x + excalidrawElement.width, + y: end.y || excalidrawElement.y - height / 2, + width: end?.width ?? 100, + height, + ...end, + }) as ExcalidrawBindableElement; + bindLinearElement(excalidrawElement, endBoundElement, "end"); + } + + res.push(excalidrawElement); + if (startBoundElement) { + res.push(startBoundElement); + } + if (endBoundElement) { + res.push(endBoundElement); + } } else { excalidrawElement = { ...element, @@ -708,8 +796,8 @@ export const convertToExcalidrawElements = ( ? 100 : 0), } as ExcalidrawGenericElement; + res.push(excalidrawElement); } - res.push(excalidrawElement); } }); return res; diff --git a/src/element/textElement.ts b/src/element/textElement.ts index fc9ea561dc..dddd82aa1f 100644 --- a/src/element/textElement.ts +++ b/src/element/textElement.ts @@ -993,10 +993,8 @@ export const bindTextToContainer = ( let container; if (containerProps.type === "arrow") { container = newLinearElement({ - //@ts-ignore - x: 0, - //@ts-ignore - y: 0, + width: containerProps.width || 300, + height: containerProps.height || 24, //@ts-ignore type: containerProps.type, //@ts-ignore, @@ -1011,8 +1009,6 @@ export const bindTextToContainer = ( } else { //@ts-ignore container = newElement({ - x: 0, - y: 0, ...containerProps, }); }