|
@@ -1,6 +1,9 @@
|
|
import { type ReactNode, useEffect, useMemo, useRef, useState } from "react";
|
|
import { type ReactNode, useEffect, useMemo, useRef, useState } from "react";
|
|
|
|
|
|
-import { updateElbowArrowPoints } from "@excalidraw/element";
|
|
|
|
|
|
+import {
|
|
|
|
+ getLinearElementSubType,
|
|
|
|
+ updateElbowArrowPoints,
|
|
|
|
+} from "@excalidraw/element";
|
|
|
|
|
|
import { pointFrom, pointRotateRads, type LocalPoint } from "@excalidraw/math";
|
|
import { pointFrom, pointRotateRads, type LocalPoint } from "@excalidraw/math";
|
|
|
|
|
|
@@ -8,10 +11,8 @@ import {
|
|
hasBoundTextElement,
|
|
hasBoundTextElement,
|
|
isArrowBoundToElement,
|
|
isArrowBoundToElement,
|
|
isArrowElement,
|
|
isArrowElement,
|
|
- isCurvedArrow,
|
|
|
|
isElbowArrow,
|
|
isElbowArrow,
|
|
isLinearElement,
|
|
isLinearElement,
|
|
- isSharpArrow,
|
|
|
|
isUsingAdaptiveRadius,
|
|
isUsingAdaptiveRadius,
|
|
} from "@excalidraw/element";
|
|
} from "@excalidraw/element";
|
|
|
|
|
|
@@ -34,6 +35,8 @@ import {
|
|
CLASSES,
|
|
CLASSES,
|
|
getFontString,
|
|
getFontString,
|
|
isProdEnv,
|
|
isProdEnv,
|
|
|
|
+ mapFind,
|
|
|
|
+ reduceToCommonValue,
|
|
updateActiveTool,
|
|
updateActiveTool,
|
|
} from "@excalidraw/common";
|
|
} from "@excalidraw/common";
|
|
|
|
|
|
@@ -55,9 +58,7 @@ import type {
|
|
ConvertibleGenericTypes,
|
|
ConvertibleGenericTypes,
|
|
ConvertibleLinearTypes,
|
|
ConvertibleLinearTypes,
|
|
ConvertibleTypes,
|
|
ConvertibleTypes,
|
|
- ExcalidrawArrowElement,
|
|
|
|
ExcalidrawDiamondElement,
|
|
ExcalidrawDiamondElement,
|
|
- ExcalidrawElbowArrowElement,
|
|
|
|
ExcalidrawElement,
|
|
ExcalidrawElement,
|
|
ExcalidrawEllipseElement,
|
|
ExcalidrawEllipseElement,
|
|
ExcalidrawLinearElement,
|
|
ExcalidrawLinearElement,
|
|
@@ -77,7 +78,7 @@ import {
|
|
sceneCoordsToViewportCoords,
|
|
sceneCoordsToViewportCoords,
|
|
} from "..";
|
|
} from "..";
|
|
import { trackEvent } from "../analytics";
|
|
import { trackEvent } from "../analytics";
|
|
-import { atom, editorJotaiStore, useSetAtom } from "../editor-jotai";
|
|
|
|
|
|
+import { atom } from "../editor-jotai";
|
|
|
|
|
|
import "./ConvertElementTypePopup.scss";
|
|
import "./ConvertElementTypePopup.scss";
|
|
import { ToolButton } from "./ToolButton";
|
|
import { ToolButton } from "./ToolButton";
|
|
@@ -98,6 +99,12 @@ import type { AppClassProperties } from "../types";
|
|
const GAP_HORIZONTAL = 8;
|
|
const GAP_HORIZONTAL = 8;
|
|
const GAP_VERTICAL = 10;
|
|
const GAP_VERTICAL = 10;
|
|
|
|
|
|
|
|
+type ExcalidrawConvertibleElement =
|
|
|
|
+ | ExcalidrawRectangleElement
|
|
|
|
+ | ExcalidrawDiamondElement
|
|
|
|
+ | ExcalidrawEllipseElement
|
|
|
|
+ | ExcalidrawLinearElement;
|
|
|
|
+
|
|
// indicates order of switching
|
|
// indicates order of switching
|
|
const GENERIC_TYPES = ["rectangle", "diamond", "ellipse"] as const;
|
|
const GENERIC_TYPES = ["rectangle", "diamond", "ellipse"] as const;
|
|
// indicates order of switching
|
|
// indicates order of switching
|
|
@@ -131,28 +138,21 @@ export const convertElementTypePopupAtom = atom<{
|
|
type: "panel";
|
|
type: "panel";
|
|
} | null>(null);
|
|
} | null>(null);
|
|
|
|
|
|
-// NOTE doesn't need to be an atom. Review once we integrate with properties panel.
|
|
|
|
-export const fontSize_conversionCacheAtom = atom<{
|
|
|
|
- [id: string]: {
|
|
|
|
|
|
+type CacheKey = string & { _brand: "CacheKey" };
|
|
|
|
+
|
|
|
|
+const FONT_SIZE_CONVERSION_CACHE = new Map<
|
|
|
|
+ ExcalidrawElement["id"],
|
|
|
|
+ {
|
|
fontSize: number;
|
|
fontSize: number;
|
|
- elementType: ConvertibleGenericTypes;
|
|
|
|
- };
|
|
|
|
-} | null>(null);
|
|
|
|
|
|
+ }
|
|
|
|
+>();
|
|
|
|
|
|
-// NOTE doesn't need to be an atom. Review once we integrate with properties panel.
|
|
|
|
-export const linearElement_conversionCacheAtom = atom<{
|
|
|
|
- [id: string]: {
|
|
|
|
- properties:
|
|
|
|
- | Partial<ExcalidrawLinearElement>
|
|
|
|
- | Partial<ExcalidrawElbowArrowElement>;
|
|
|
|
- initialType: ConvertibleLinearTypes;
|
|
|
|
- };
|
|
|
|
-} | null>(null);
|
|
|
|
|
|
+const LINEAR_ELEMENT_CONVERSION_CACHE = new Map<
|
|
|
|
+ CacheKey,
|
|
|
|
+ ExcalidrawLinearElement
|
|
|
|
+>();
|
|
|
|
|
|
const ConvertElementTypePopup = ({ app }: { app: App }) => {
|
|
const ConvertElementTypePopup = ({ app }: { app: App }) => {
|
|
- const setFontSizeCache = useSetAtom(fontSize_conversionCacheAtom);
|
|
|
|
- const setLinearElementCache = useSetAtom(linearElement_conversionCacheAtom);
|
|
|
|
-
|
|
|
|
const selectedElements = app.scene.getSelectedElements(app.state);
|
|
const selectedElements = app.scene.getSelectedElements(app.state);
|
|
const elementsCategoryRef = useRef<ConversionType>(null);
|
|
const elementsCategoryRef = useRef<ConversionType>(null);
|
|
|
|
|
|
@@ -179,10 +179,10 @@ const ConvertElementTypePopup = ({ app }: { app: App }) => {
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
return () => {
|
|
return () => {
|
|
- setFontSizeCache(null);
|
|
|
|
- setLinearElementCache(null);
|
|
|
|
|
|
+ FONT_SIZE_CONVERSION_CACHE.clear();
|
|
|
|
+ LINEAR_ELEMENT_CONVERSION_CACHE.clear();
|
|
};
|
|
};
|
|
- }, [setFontSizeCache, setLinearElementCache]);
|
|
|
|
|
|
+ }, []);
|
|
|
|
|
|
return <Panel app={app} elements={selectedElements} />;
|
|
return <Panel app={app} elements={selectedElements} />;
|
|
};
|
|
};
|
|
@@ -215,7 +215,8 @@ const Panel = ({
|
|
: conversionType === "linear"
|
|
: conversionType === "linear"
|
|
? linearElements.every(
|
|
? linearElements.every(
|
|
(element) =>
|
|
(element) =>
|
|
- getArrowType(element) === getArrowType(linearElements[0]),
|
|
|
|
|
|
+ getLinearElementSubType(element) ===
|
|
|
|
+ getLinearElementSubType(linearElements[0]),
|
|
)
|
|
)
|
|
: false;
|
|
: false;
|
|
|
|
|
|
@@ -264,51 +265,29 @@ const Panel = ({
|
|
}, [genericElements, linearElements, app.scene, app.state]);
|
|
}, [genericElements, linearElements, app.scene, app.state]);
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
- if (editorJotaiStore.get(linearElement_conversionCacheAtom)) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
for (const linearElement of linearElements) {
|
|
for (const linearElement of linearElements) {
|
|
- const initialType = getArrowType(linearElement);
|
|
|
|
- const cachedProperties =
|
|
|
|
- initialType === "line"
|
|
|
|
- ? getLineProperties(linearElement)
|
|
|
|
- : initialType === "sharpArrow"
|
|
|
|
- ? getSharpArrowProperties(linearElement)
|
|
|
|
- : initialType === "curvedArrow"
|
|
|
|
- ? getCurvedArrowProperties(linearElement)
|
|
|
|
- : initialType === "elbowArrow"
|
|
|
|
- ? getElbowArrowProperties(linearElement)
|
|
|
|
- : {};
|
|
|
|
-
|
|
|
|
- editorJotaiStore.set(linearElement_conversionCacheAtom, {
|
|
|
|
- ...editorJotaiStore.get(linearElement_conversionCacheAtom),
|
|
|
|
- [linearElement.id]: {
|
|
|
|
- properties: cachedProperties,
|
|
|
|
- initialType,
|
|
|
|
- },
|
|
|
|
- });
|
|
|
|
|
|
+ const cacheKey = toCacheKey(
|
|
|
|
+ linearElement.id,
|
|
|
|
+ getConvertibleType(linearElement),
|
|
|
|
+ );
|
|
|
|
+ if (!LINEAR_ELEMENT_CONVERSION_CACHE.has(cacheKey)) {
|
|
|
|
+ LINEAR_ELEMENT_CONVERSION_CACHE.set(cacheKey, linearElement);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}, [linearElements]);
|
|
}, [linearElements]);
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
- if (editorJotaiStore.get(fontSize_conversionCacheAtom)) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
for (const element of genericElements) {
|
|
for (const element of genericElements) {
|
|
- const boundText = getBoundTextElement(
|
|
|
|
- element,
|
|
|
|
- app.scene.getNonDeletedElementsMap(),
|
|
|
|
- );
|
|
|
|
- if (boundText) {
|
|
|
|
- editorJotaiStore.set(fontSize_conversionCacheAtom, {
|
|
|
|
- ...editorJotaiStore.get(fontSize_conversionCacheAtom),
|
|
|
|
- [element.id]: {
|
|
|
|
|
|
+ if (!FONT_SIZE_CONVERSION_CACHE.has(element.id)) {
|
|
|
|
+ const boundText = getBoundTextElement(
|
|
|
|
+ element,
|
|
|
|
+ app.scene.getNonDeletedElementsMap(),
|
|
|
|
+ );
|
|
|
|
+ if (boundText) {
|
|
|
|
+ FONT_SIZE_CONVERSION_CACHE.set(element.id, {
|
|
fontSize: boundText.fontSize,
|
|
fontSize: boundText.fontSize,
|
|
- elementType: element.type as ConvertibleGenericTypes,
|
|
|
|
- },
|
|
|
|
- });
|
|
|
|
|
|
+ });
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, [genericElements, app.scene]);
|
|
}, [genericElements, app.scene]);
|
|
@@ -350,7 +329,7 @@ const Panel = ({
|
|
sameType &&
|
|
sameType &&
|
|
((conversionType === "generic" && genericElements[0].type === type) ||
|
|
((conversionType === "generic" && genericElements[0].type === type) ||
|
|
(conversionType === "linear" &&
|
|
(conversionType === "linear" &&
|
|
- getArrowType(linearElements[0]) === type));
|
|
|
|
|
|
+ getLinearElementSubType(linearElements[0]) === type));
|
|
|
|
|
|
return (
|
|
return (
|
|
<ToolButton
|
|
<ToolButton
|
|
@@ -500,14 +479,11 @@ export const convertElementTypes = (
|
|
app.scene.getNonDeletedElementsMap(),
|
|
app.scene.getNonDeletedElementsMap(),
|
|
);
|
|
);
|
|
if (boundText) {
|
|
if (boundText) {
|
|
- if (
|
|
|
|
- editorJotaiStore.get(fontSize_conversionCacheAtom)?.[element.id]
|
|
|
|
- ?.elementType === nextType
|
|
|
|
- ) {
|
|
|
|
|
|
+ if (FONT_SIZE_CONVERSION_CACHE.get(element.id)) {
|
|
mutateElement(boundText, app.scene.getNonDeletedElementsMap(), {
|
|
mutateElement(boundText, app.scene.getNonDeletedElementsMap(), {
|
|
fontSize:
|
|
fontSize:
|
|
- editorJotaiStore.get(fontSize_conversionCacheAtom)?.[element.id]
|
|
|
|
- ?.fontSize ?? boundText.fontSize,
|
|
|
|
|
|
+ FONT_SIZE_CONVERSION_CACHE.get(element.id)?.fontSize ??
|
|
|
|
+ boundText.fontSize,
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
@@ -535,124 +511,101 @@ export const convertElementTypes = (
|
|
selectedElements,
|
|
selectedElements,
|
|
) as ExcalidrawLinearElement[];
|
|
) as ExcalidrawLinearElement[];
|
|
|
|
|
|
- const arrowType = getArrowType(convertibleLinearElements[0]);
|
|
|
|
- const sameType = convertibleLinearElements.every(
|
|
|
|
- (element) => getArrowType(element) === arrowType,
|
|
|
|
- );
|
|
|
|
|
|
+ if (!nextType) {
|
|
|
|
+ const commonSubType = reduceToCommonValue(
|
|
|
|
+ convertibleLinearElements,
|
|
|
|
+ getLinearElementSubType,
|
|
|
|
+ );
|
|
|
|
|
|
- const index = sameType ? LINEAR_TYPES.indexOf(arrowType) : -1;
|
|
|
|
- nextType =
|
|
|
|
- nextType ??
|
|
|
|
- LINEAR_TYPES[
|
|
|
|
- (index + LINEAR_TYPES.length + advancement) % LINEAR_TYPES.length
|
|
|
|
- ];
|
|
|
|
|
|
+ const index = commonSubType ? LINEAR_TYPES.indexOf(commonSubType) : -1;
|
|
|
|
+ nextType =
|
|
|
|
+ LINEAR_TYPES[
|
|
|
|
+ (index + LINEAR_TYPES.length + advancement) % LINEAR_TYPES.length
|
|
|
|
+ ];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (isConvertibleLinearType(nextType)) {
|
|
|
|
+ const convertedElements: ExcalidrawElement[] = [];
|
|
|
|
+
|
|
|
|
+ const nextElementsMap: Map<ExcalidrawElement["id"], ExcalidrawElement> =
|
|
|
|
+ app.scene.getElementsMapIncludingDeleted();
|
|
|
|
|
|
- if (nextType && isConvertibleLinearType(nextType)) {
|
|
|
|
- const convertedElements: Record<string, ExcalidrawElement> = {};
|
|
|
|
for (const element of convertibleLinearElements) {
|
|
for (const element of convertibleLinearElements) {
|
|
- const { properties, initialType } =
|
|
|
|
- editorJotaiStore.get(linearElement_conversionCacheAtom)?.[
|
|
|
|
- element.id
|
|
|
|
- ] || {};
|
|
|
|
-
|
|
|
|
- // If the initial type is not elbow, and when we switch to elbow,
|
|
|
|
- // the linear line might be "bent" and the points would likely be different.
|
|
|
|
- // When we then switch to other non elbow types from this converted elbow,
|
|
|
|
- // we still want to use the original points instead.
|
|
|
|
|
|
+ const cachedElement = LINEAR_ELEMENT_CONVERSION_CACHE.get(
|
|
|
|
+ toCacheKey(element.id, nextType),
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ // if switching to the original subType or a subType we've already
|
|
|
|
+ // converted to, reuse the cached element to get the original properties
|
|
|
|
+ // (needed for simple->elbow->simple conversions or between line
|
|
|
|
+ // and arrows)
|
|
if (
|
|
if (
|
|
- initialType &&
|
|
|
|
- properties &&
|
|
|
|
- isElbowArrow(element) &&
|
|
|
|
- initialType !== "elbowArrow" &&
|
|
|
|
- nextType !== "elbowArrow"
|
|
|
|
|
|
+ cachedElement &&
|
|
|
|
+ getLinearElementSubType(cachedElement) === nextType
|
|
) {
|
|
) {
|
|
- // first convert back to the original type
|
|
|
|
- const originalType = convertElementType(
|
|
|
|
- element,
|
|
|
|
- initialType,
|
|
|
|
- app,
|
|
|
|
- ) as ExcalidrawLinearElement;
|
|
|
|
- // then convert to the target type
|
|
|
|
- const converted = convertElementType(
|
|
|
|
- initialType === "line"
|
|
|
|
- ? newLinearElement({
|
|
|
|
- ...originalType,
|
|
|
|
- ...properties,
|
|
|
|
- type: "line",
|
|
|
|
- })
|
|
|
|
- : newArrowElement({
|
|
|
|
- ...originalType,
|
|
|
|
- ...properties,
|
|
|
|
- type: "arrow",
|
|
|
|
- }),
|
|
|
|
- nextType,
|
|
|
|
- app,
|
|
|
|
- );
|
|
|
|
- convertedElements[converted.id] = converted;
|
|
|
|
|
|
+ nextElementsMap.set(cachedElement.id, cachedElement);
|
|
|
|
+ convertedElements.push(cachedElement);
|
|
} else {
|
|
} else {
|
|
const converted = convertElementType(element, nextType, app);
|
|
const converted = convertElementType(element, nextType, app);
|
|
- convertedElements[converted.id] = converted;
|
|
|
|
|
|
+ nextElementsMap.set(converted.id, converted);
|
|
|
|
+ convertedElements.push(converted);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- const nextElements = [];
|
|
|
|
-
|
|
|
|
- for (const element of app.scene.getElementsIncludingDeleted()) {
|
|
|
|
- if (convertedElements[element.id]) {
|
|
|
|
- nextElements.push(convertedElements[element.id]);
|
|
|
|
- } else {
|
|
|
|
- nextElements.push(element);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ app.scene.replaceAllElements(nextElementsMap);
|
|
|
|
|
|
- app.scene.replaceAllElements(nextElements);
|
|
|
|
-
|
|
|
|
- for (const element of Object.values(convertedElements)) {
|
|
|
|
- const cachedLinear = editorJotaiStore.get(
|
|
|
|
- linearElement_conversionCacheAtom,
|
|
|
|
- )?.[element.id];
|
|
|
|
-
|
|
|
|
- if (cachedLinear) {
|
|
|
|
- const { properties, initialType } = cachedLinear;
|
|
|
|
-
|
|
|
|
- if (initialType === nextType) {
|
|
|
|
- mutateElement(
|
|
|
|
|
|
+ // post normalization
|
|
|
|
+ for (const element of convertedElements) {
|
|
|
|
+ if (isLinearElement(element)) {
|
|
|
|
+ if (isElbowArrow(element)) {
|
|
|
|
+ const nextPoints = convertLineToElbow(element);
|
|
|
|
+ if (nextPoints.length < 2) {
|
|
|
|
+ // skip if not enough points to form valid segments
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ const fixedSegments: FixedSegment[] = [];
|
|
|
|
+ for (let i = 0; i < nextPoints.length - 1; i++) {
|
|
|
|
+ fixedSegments.push({
|
|
|
|
+ start: nextPoints[i],
|
|
|
|
+ end: nextPoints[i + 1],
|
|
|
|
+ index: i + 1,
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ const updates = updateElbowArrowPoints(
|
|
element,
|
|
element,
|
|
app.scene.getNonDeletedElementsMap(),
|
|
app.scene.getNonDeletedElementsMap(),
|
|
- properties,
|
|
|
|
|
|
+ {
|
|
|
|
+ points: nextPoints,
|
|
|
|
+ fixedSegments,
|
|
|
|
+ },
|
|
);
|
|
);
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (isElbowArrow(element)) {
|
|
|
|
- const nextPoints = convertLineToElbow(element);
|
|
|
|
- if (nextPoints.length < 2) {
|
|
|
|
- // skip if not enough points to form valid segments
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- const fixedSegments: FixedSegment[] = [];
|
|
|
|
- for (let i = 0; i < nextPoints.length - 1; i++) {
|
|
|
|
- fixedSegments.push({
|
|
|
|
- start: nextPoints[i],
|
|
|
|
- end: nextPoints[i + 1],
|
|
|
|
- index: i + 1,
|
|
|
|
|
|
+ mutateElement(element, app.scene.getNonDeletedElementsMap(), {
|
|
|
|
+ ...updates,
|
|
});
|
|
});
|
|
|
|
+ } else {
|
|
|
|
+ // if we're converting to non-elbow linear element, check if
|
|
|
|
+ // we've already cached one of these linear elements so we can
|
|
|
|
+ // reuse the points (case: curved->elbow->line and similar)
|
|
|
|
+
|
|
|
|
+ const similarCachedLinearElement = mapFind(
|
|
|
|
+ ["line", "sharpArrow", "curvedArrow"] as const,
|
|
|
|
+ (type) =>
|
|
|
|
+ LINEAR_ELEMENT_CONVERSION_CACHE.get(
|
|
|
|
+ toCacheKey(element.id, type),
|
|
|
|
+ ),
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ if (similarCachedLinearElement) {
|
|
|
|
+ const points = similarCachedLinearElement.points;
|
|
|
|
+ app.scene.mutateElement(element, {
|
|
|
|
+ points,
|
|
|
|
+ });
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- const updates = updateElbowArrowPoints(
|
|
|
|
- element,
|
|
|
|
- app.scene.getNonDeletedElementsMap(),
|
|
|
|
- {
|
|
|
|
- points: nextPoints,
|
|
|
|
- fixedSegments,
|
|
|
|
- },
|
|
|
|
- );
|
|
|
|
- mutateElement(element, app.scene.getNonDeletedElementsMap(), {
|
|
|
|
- ...updates,
|
|
|
|
- });
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
const convertedSelectedLinearElements = filterLinearConvertibleElements(
|
|
const convertedSelectedLinearElements = filterLinearConvertibleElements(
|
|
app.scene.getSelectedElements(app.state),
|
|
app.scene.getSelectedElements(app.state),
|
|
);
|
|
);
|
|
@@ -708,83 +661,11 @@ const isEligibleLinearElement = (element: ExcalidrawElement) => {
|
|
);
|
|
);
|
|
};
|
|
};
|
|
|
|
|
|
-const getArrowType = (element: ExcalidrawLinearElement) => {
|
|
|
|
- if (isSharpArrow(element)) {
|
|
|
|
- return "sharpArrow";
|
|
|
|
- }
|
|
|
|
- if (isCurvedArrow(element)) {
|
|
|
|
- return "curvedArrow";
|
|
|
|
- }
|
|
|
|
- if (isElbowArrow(element)) {
|
|
|
|
- return "elbowArrow";
|
|
|
|
- }
|
|
|
|
- return "line";
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-const getLineProperties = (
|
|
|
|
- element: ExcalidrawLinearElement,
|
|
|
|
-): Partial<ExcalidrawLinearElement> => {
|
|
|
|
- if (element.type === "line") {
|
|
|
|
- return {
|
|
|
|
- points: element.points,
|
|
|
|
- roundness: element.roundness,
|
|
|
|
- };
|
|
|
|
- }
|
|
|
|
- return {};
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-const getSharpArrowProperties = (
|
|
|
|
- element: ExcalidrawLinearElement,
|
|
|
|
-): Partial<ExcalidrawArrowElement> => {
|
|
|
|
- if (isSharpArrow(element)) {
|
|
|
|
- return {
|
|
|
|
- points: element.points,
|
|
|
|
- startArrowhead: element.startArrowhead,
|
|
|
|
- endArrowhead: element.endArrowhead,
|
|
|
|
- startBinding: element.startBinding,
|
|
|
|
- endBinding: element.endBinding,
|
|
|
|
- roundness: null,
|
|
|
|
- };
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return {};
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-const getCurvedArrowProperties = (
|
|
|
|
- element: ExcalidrawLinearElement,
|
|
|
|
-): Partial<ExcalidrawArrowElement> => {
|
|
|
|
- if (isCurvedArrow(element)) {
|
|
|
|
- return {
|
|
|
|
- points: element.points,
|
|
|
|
- startArrowhead: element.startArrowhead,
|
|
|
|
- endArrowhead: element.endArrowhead,
|
|
|
|
- startBinding: element.startBinding,
|
|
|
|
- endBinding: element.endBinding,
|
|
|
|
- roundness: element.roundness,
|
|
|
|
- };
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return {};
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-const getElbowArrowProperties = (
|
|
|
|
- element: ExcalidrawLinearElement,
|
|
|
|
-): Partial<ExcalidrawElbowArrowElement> => {
|
|
|
|
- if (isElbowArrow(element)) {
|
|
|
|
- return {
|
|
|
|
- points: element.points,
|
|
|
|
- startArrowhead: element.startArrowhead,
|
|
|
|
- endArrowhead: element.endArrowhead,
|
|
|
|
- startBinding: element.startBinding,
|
|
|
|
- endBinding: element.endBinding,
|
|
|
|
- roundness: null,
|
|
|
|
- fixedSegments: element.fixedSegments,
|
|
|
|
- startIsSpecial: element.startIsSpecial,
|
|
|
|
- endIsSpecial: element.endIsSpecial,
|
|
|
|
- };
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return {};
|
|
|
|
|
|
+const toCacheKey = (
|
|
|
|
+ elementId: ExcalidrawElement["id"],
|
|
|
|
+ convertitleType: ConvertibleTypes,
|
|
|
|
+) => {
|
|
|
|
+ return `${elementId}:${convertitleType}` as CacheKey;
|
|
};
|
|
};
|
|
|
|
|
|
const filterGenericConvetibleElements = (elements: ExcalidrawElement[]) =>
|
|
const filterGenericConvetibleElements = (elements: ExcalidrawElement[]) =>
|
|
@@ -1045,4 +926,13 @@ const isValidConversion = (
|
|
return false;
|
|
return false;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+const getConvertibleType = (
|
|
|
|
+ element: ExcalidrawConvertibleElement,
|
|
|
|
+): ConvertibleTypes => {
|
|
|
|
+ if (isLinearElement(element)) {
|
|
|
|
+ return getLinearElementSubType(element);
|
|
|
|
+ }
|
|
|
|
+ return element.type;
|
|
|
|
+};
|
|
|
|
+
|
|
export default ConvertElementTypePopup;
|
|
export default ConvertElementTypePopup;
|