cache initial panel position

This commit is contained in:
Ryan Di 2025-04-22 09:55:02 +10:00
parent 1c4b3cc0b1
commit eff67c5e01

View file

@ -1,4 +1,4 @@
import { type ReactNode, useEffect, useMemo, useRef } from "react"; import { type ReactNode, useEffect, useMemo, useRef, useState } from "react";
import { pointFrom, pointRotateRads } from "@excalidraw/math"; import { pointFrom, pointRotateRads } from "@excalidraw/math";
@ -118,13 +118,14 @@ const Panel = ({
app: App; app: App;
elements: ExcalidrawElement[]; elements: ExcalidrawElement[];
}) => { }) => {
let [x1, y2, cx, cy] = [0, 0, 0, 0];
let rotatedBottomLeft = [0, 0];
const { generic, linear } = getSwitchableTypeFromElements(elements); const { generic, linear } = getSwitchableTypeFromElements(elements);
const genericElements = generic ? getGenericSwitchableElements(elements) : []; const genericElements = useMemo(() => {
const linearElements = linear ? getLinearSwitchableElements(elements) : []; return generic ? getGenericSwitchableElements(elements) : [];
}, [generic, elements]);
const linearElements = useMemo(() => {
return linear ? getLinearSwitchableElements(elements) : [];
}, [linear, elements]);
const sameType = generic const sameType = generic
? genericElements.every( ? genericElements.every(
@ -134,33 +135,45 @@ const Panel = ({
? linearElements.every((element) => element.type === linearElements[0].type) ? linearElements.every((element) => element.type === linearElements[0].type)
: false; : false;
if (elements.length === 1) { const [panelPosition, setPanelPosition] = useState({ x: 0, y: 0 });
[x1, , , y2, cx, cy] = getElementAbsoluteCoords( const selectedElementsRef = useRef("");
elements[0],
app.scene.getNonDeletedElementsMap(), useEffect(() => {
const elements = [...genericElements, ...linearElements].sort((a, b) =>
a.id.localeCompare(b.id),
);
const elementsRef = elements.join(",");
if (elementsRef === selectedElementsRef.current) {
return;
}
selectedElementsRef.current = elementsRef;
let bottomLeft;
if (elements.length === 1) {
const [x1, , , y2, cx, cy] = getElementAbsoluteCoords(
elements[0],
app.scene.getNonDeletedElementsMap(),
);
bottomLeft = pointRotateRads(
pointFrom(x1, y2),
pointFrom(cx, cy),
elements[0].angle,
);
} else {
const { minX, maxY } = getCommonBoundingBox(elements);
bottomLeft = pointFrom(minX, maxY);
}
const { x, y } = sceneCoordsToViewportCoords(
{ sceneX: bottomLeft[0], sceneY: bottomLeft[1] },
app.state,
); );
rotatedBottomLeft = pointRotateRads( setPanelPosition({ x, y });
pointFrom(x1, y2), }, [genericElements, linearElements, app.scene, app.state]);
pointFrom(cx, cy),
elements[0].angle,
);
} else {
const { minX, maxY, midX, midY } = getCommonBoundingBox(elements);
x1 = minX;
y2 = maxY;
cx = midX;
cy = midY;
rotatedBottomLeft = pointFrom(x1, y2);
}
const { x, y } = sceneCoordsToViewportCoords(
{
sceneX: rotatedBottomLeft[0],
sceneY: rotatedBottomLeft[1],
},
app.state,
);
const SHAPES: [string, string, ReactNode][] = linear const SHAPES: [string, string, ReactNode][] = linear
? [ ? [
@ -180,9 +193,11 @@ const Panel = ({
style={{ style={{
position: "absolute", position: "absolute",
top: `${ top: `${
y + (GAP_VERTICAL + 8) * app.state.zoom.value - app.state.offsetTop panelPosition.y +
(GAP_VERTICAL + 8) * app.state.zoom.value -
app.state.offsetTop
}px`, }px`,
left: `${x - app.state.offsetLeft - GAP_HORIZONTAL}px`, left: `${panelPosition.x - app.state.offsetLeft - GAP_HORIZONTAL}px`,
zIndex: 2, zIndex: 2,
}} }}
className="ShapeSwitch__Panel" className="ShapeSwitch__Panel"