Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d878a2f647 | ||
|
|
de983c1d93 |
@@ -18,7 +18,7 @@
|
|||||||
"@docusaurus/core": "2.2.0",
|
"@docusaurus/core": "2.2.0",
|
||||||
"@docusaurus/preset-classic": "2.2.0",
|
"@docusaurus/preset-classic": "2.2.0",
|
||||||
"@docusaurus/theme-live-codeblock": "2.2.0",
|
"@docusaurus/theme-live-codeblock": "2.2.0",
|
||||||
"@excalidraw/excalidraw": "0.17.0",
|
"@excalidraw/excalidraw": "0.17.0-7284-25ea35d",
|
||||||
"@mdx-js/react": "^1.6.22",
|
"@mdx-js/react": "^1.6.22",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"docusaurus-plugin-sass": "0.2.3",
|
"docusaurus-plugin-sass": "0.2.3",
|
||||||
|
|||||||
+4
-4
@@ -1718,10 +1718,10 @@
|
|||||||
url-loader "^4.1.1"
|
url-loader "^4.1.1"
|
||||||
webpack "^5.73.0"
|
webpack "^5.73.0"
|
||||||
|
|
||||||
"@excalidraw/excalidraw@0.17.0":
|
"@excalidraw/excalidraw@0.17.0-7284-25ea35d":
|
||||||
version "0.17.0"
|
version "0.17.0-7284-25ea35d"
|
||||||
resolved "https://registry.yarnpkg.com/@excalidraw/excalidraw/-/excalidraw-0.17.0.tgz#3c64aa8e36406ac171b008cfecbdce5bb0755725"
|
resolved "https://registry.yarnpkg.com/@excalidraw/excalidraw/-/excalidraw-0.17.0-7284-25ea35d.tgz#dd42ccc757e81d064f55bb0cac96c344fb557358"
|
||||||
integrity sha512-NzP22v5xMqxYW27ZtTHhiGFe7kE8NeBk45aoeM/mDSkXiOXPDH+PcvwzHRN/Ei+Vj/0sTPHxejn8bZyRWKGjXg==
|
integrity sha512-VVe0bdnmsZeIcbfoK2DgJefWmCmyQDFRvssCfxP3l2g/W8/6uKiKG+WNylu1D9dGveMfg1Io7XG2/PGRyD8OrQ==
|
||||||
|
|
||||||
"@hapi/hoek@^9.0.0":
|
"@hapi/hoek@^9.0.0":
|
||||||
version "9.3.0"
|
version "9.3.0"
|
||||||
|
|||||||
+1
-1
@@ -96,7 +96,7 @@
|
|||||||
"vitest-canvas-mock": "0.3.2"
|
"vitest-canvas-mock": "0.3.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "18.0.0 - 20.x.x"
|
"node": ">=18.0.0"
|
||||||
},
|
},
|
||||||
"homepage": ".",
|
"homepage": ".",
|
||||||
"name": "excalidraw",
|
"name": "excalidraw",
|
||||||
|
|||||||
@@ -265,21 +265,7 @@ export const zoomToFit = ({
|
|||||||
30.0,
|
30.0,
|
||||||
) as NormalizedZoomValue;
|
) as NormalizedZoomValue;
|
||||||
|
|
||||||
let appStateWidth = appState.width;
|
scrollX = (appState.width / 2) * (1 / newZoomValue) - centerX;
|
||||||
|
|
||||||
if (appState.openSidebar) {
|
|
||||||
const sidebarDOMElem = document.querySelector(
|
|
||||||
".sidebar",
|
|
||||||
) as HTMLElement | null;
|
|
||||||
const sidebarWidth = sidebarDOMElem?.offsetWidth ?? 0;
|
|
||||||
const isRTL = document.documentElement.getAttribute("dir") === "rtl";
|
|
||||||
|
|
||||||
appStateWidth = !isRTL
|
|
||||||
? appState.width - sidebarWidth
|
|
||||||
: appState.width + sidebarWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollX = (appStateWidth / 2) * (1 / newZoomValue) - centerX;
|
|
||||||
scrollY = (appState.height / 2) * (1 / newZoomValue) - centerY;
|
scrollY = (appState.height / 2) * (1 / newZoomValue) - centerY;
|
||||||
} else {
|
} else {
|
||||||
newZoomValue = zoomValueToFitBoundsOnViewport(commonBounds, {
|
newZoomValue = zoomValueToFitBoundsOnViewport(commonBounds, {
|
||||||
|
|||||||
+66
-20
@@ -8238,8 +8238,27 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
|
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
|
||||||
);
|
);
|
||||||
|
|
||||||
const resizingSingleFrameOnly =
|
const frameElementsOffsetsMap = new Map<
|
||||||
selectedElements.length === 1 && selectedFrames.length === 1;
|
string,
|
||||||
|
{
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
|
>();
|
||||||
|
|
||||||
|
selectedFrames.forEach((frame) => {
|
||||||
|
const elementsInFrame = getFrameChildren(
|
||||||
|
this.scene.getNonDeletedElements(),
|
||||||
|
frame.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
elementsInFrame.forEach((element) => {
|
||||||
|
frameElementsOffsetsMap.set(frame.id + element.id, {
|
||||||
|
x: element.x - frame.x,
|
||||||
|
y: element.y - frame.y,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// check needed for avoiding flickering when a key gets pressed
|
// check needed for avoiding flickering when a key gets pressed
|
||||||
// during dragging
|
// during dragging
|
||||||
@@ -8280,12 +8299,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
transformElements(
|
transformElements(
|
||||||
pointerDownState,
|
pointerDownState,
|
||||||
transformHandleType,
|
transformHandleType,
|
||||||
resizingSingleFrameOnly
|
selectedElements,
|
||||||
? selectedElements
|
|
||||||
: this.scene.getSelectedElements({
|
|
||||||
selectedElementIds: this.state.selectedElementIds,
|
|
||||||
includeElementsInFrames: true,
|
|
||||||
}),
|
|
||||||
pointerDownState.resize.arrowDirection,
|
pointerDownState.resize.arrowDirection,
|
||||||
shouldRotateWithDiscreteAngle(event),
|
shouldRotateWithDiscreteAngle(event),
|
||||||
shouldResizeFromCenter(event),
|
shouldResizeFromCenter(event),
|
||||||
@@ -8301,19 +8315,51 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
) {
|
) {
|
||||||
this.maybeSuggestBindingForAll(selectedElements);
|
this.maybeSuggestBindingForAll(selectedElements);
|
||||||
|
|
||||||
// highlight frame children ONLY when resizing a single frame
|
const elementsToHighlight = new Set<ExcalidrawElement>();
|
||||||
if (resizingSingleFrameOnly) {
|
selectedFrames.forEach((frame) => {
|
||||||
const selectedFrame = selectedFrames[0];
|
const elementsInFrame = getFrameChildren(
|
||||||
if (selectedFrame) {
|
this.scene.getNonDeletedElements(),
|
||||||
this.setState({
|
frame.id,
|
||||||
elementsToHighlight: getElementsInResizingFrame(
|
);
|
||||||
this.scene.getNonDeletedElements(),
|
|
||||||
selectedFrame,
|
// keep elements' positions relative to their frames on frames resizing
|
||||||
this.state,
|
if (transformHandleType) {
|
||||||
),
|
if (transformHandleType.includes("w")) {
|
||||||
});
|
elementsInFrame.forEach((element) => {
|
||||||
|
mutateElement(element, {
|
||||||
|
x:
|
||||||
|
frame.x +
|
||||||
|
(frameElementsOffsetsMap.get(frame.id + element.id)?.x || 0),
|
||||||
|
y:
|
||||||
|
frame.y +
|
||||||
|
(frameElementsOffsetsMap.get(frame.id + element.id)?.y || 0),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (transformHandleType.includes("n")) {
|
||||||
|
elementsInFrame.forEach((element) => {
|
||||||
|
mutateElement(element, {
|
||||||
|
x:
|
||||||
|
frame.x +
|
||||||
|
(frameElementsOffsetsMap.get(frame.id + element.id)?.x || 0),
|
||||||
|
y:
|
||||||
|
frame.y +
|
||||||
|
(frameElementsOffsetsMap.get(frame.id + element.id)?.y || 0),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
getElementsInResizingFrame(
|
||||||
|
this.scene.getNonDeletedElements(),
|
||||||
|
frame,
|
||||||
|
this.state,
|
||||||
|
).forEach((element) => elementsToHighlight.add(element));
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
elementsToHighlight: [...elementsToHighlight],
|
||||||
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-5
@@ -13,6 +13,7 @@ import { Point } from "../types";
|
|||||||
import { generateRoughOptions } from "../scene/Shape";
|
import { generateRoughOptions } from "../scene/Shape";
|
||||||
import {
|
import {
|
||||||
isArrowElement,
|
isArrowElement,
|
||||||
|
isBoundToContainer,
|
||||||
isFreeDrawElement,
|
isFreeDrawElement,
|
||||||
isLinearElement,
|
isLinearElement,
|
||||||
isTextElement,
|
isTextElement,
|
||||||
@@ -22,6 +23,7 @@ import { getBoundTextElement, getContainerElement } from "./textElement";
|
|||||||
import { LinearElementEditor } from "./linearElementEditor";
|
import { LinearElementEditor } from "./linearElementEditor";
|
||||||
import { Mutable } from "../utility-types";
|
import { Mutable } from "../utility-types";
|
||||||
import { ShapeCache } from "../scene/ShapeCache";
|
import { ShapeCache } from "../scene/ShapeCache";
|
||||||
|
import Scene from "../scene/Scene";
|
||||||
|
|
||||||
export type RectangleBox = {
|
export type RectangleBox = {
|
||||||
x: number;
|
x: number;
|
||||||
@@ -53,16 +55,29 @@ export class ElementBounds {
|
|||||||
static getBounds(element: ExcalidrawElement) {
|
static getBounds(element: ExcalidrawElement) {
|
||||||
const cachedBounds = ElementBounds.boundsCache.get(element);
|
const cachedBounds = ElementBounds.boundsCache.get(element);
|
||||||
|
|
||||||
if (cachedBounds?.version && cachedBounds.version === element.version) {
|
if (
|
||||||
|
cachedBounds?.version &&
|
||||||
|
cachedBounds.version === element.version &&
|
||||||
|
// we don't invalidate cache when we update containers and not labels,
|
||||||
|
// which is causing problems down the line. Fix TBA.
|
||||||
|
!isBoundToContainer(element)
|
||||||
|
) {
|
||||||
return cachedBounds.bounds;
|
return cachedBounds.bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bounds = ElementBounds.calculateBounds(element);
|
const bounds = ElementBounds.calculateBounds(element);
|
||||||
|
|
||||||
ElementBounds.boundsCache.set(element, {
|
// hack to ensure that downstream checks could retrieve element Scene
|
||||||
version: element.version,
|
// so as to have correctly calculated bounds
|
||||||
bounds,
|
// FIXME remove when we get rid of all the id:Scene / element:Scene mapping
|
||||||
});
|
const shouldCache = Scene.getScene(element);
|
||||||
|
|
||||||
|
if (shouldCache) {
|
||||||
|
ElementBounds.boundsCache.set(element, {
|
||||||
|
version: element.version,
|
||||||
|
bounds,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user