mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Remove mutators, pass scene everywhere, make temp scenes for special cases
This commit is contained in:
parent
567c9f51e4
commit
acfa33650e
33 changed files with 177 additions and 266 deletions
|
@ -34,6 +34,7 @@ import type {
|
||||||
NonDeletedSceneElementsMap,
|
NonDeletedSceneElementsMap,
|
||||||
OrderedExcalidrawElement,
|
OrderedExcalidrawElement,
|
||||||
Ordered,
|
Ordered,
|
||||||
|
ElementsMap,
|
||||||
} from "@excalidraw/element/types";
|
} from "@excalidraw/element/types";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
|
@ -42,7 +43,7 @@ import type {
|
||||||
SameType,
|
SameType,
|
||||||
} from "@excalidraw/common/utility-types";
|
} from "@excalidraw/common/utility-types";
|
||||||
|
|
||||||
import type { AppState } from "../types";
|
import type { AppState } from "../../excalidraw/types";
|
||||||
|
|
||||||
type SceneStateCallback = () => void;
|
type SceneStateCallback = () => void;
|
||||||
type SceneStateCallbackRemover = () => void;
|
type SceneStateCallbackRemover = () => void;
|
||||||
|
@ -166,6 +167,12 @@ class Scene {
|
||||||
return this.frames;
|
return this.frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constructor(elementsMap: ElementsMap | null = null) {
|
||||||
|
if (elementsMap) {
|
||||||
|
this.replaceAllElements(elementsMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getSelectedElements(opts: {
|
getSelectedElements(opts: {
|
||||||
// NOTE can be ommitted by making Scene constructor require App instance
|
// NOTE can be ommitted by making Scene constructor require App instance
|
||||||
selectedElementIds: AppState["selectedElementIds"];
|
selectedElementIds: AppState["selectedElementIds"];
|
||||||
|
@ -419,7 +426,6 @@ class Scene {
|
||||||
|
|
||||||
// TODO_SCENE: should be accessed as app.scene through the API
|
// TODO_SCENE: should be accessed as app.scene through the API
|
||||||
// TODO_SCENE: inform mutation false is the new default, meaning all mutateElement with nothing should likely use scene instead
|
// TODO_SCENE: inform mutation false is the new default, meaning all mutateElement with nothing should likely use scene instead
|
||||||
// TODO_SCENE: think one more time about moving the scene inside element (probably we will end up with it either way)
|
|
||||||
// Mutate an element with passed updates and trigger the component to update. Make sure you
|
// Mutate an element with passed updates and trigger the component to update. Make sure you
|
||||||
// are calling it either from a React event handler or within unstable_batchedUpdates().
|
// are calling it either from a React event handler or within unstable_batchedUpdates().
|
||||||
mutate<TElement extends Mutable<ExcalidrawElement>>(
|
mutate<TElement extends Mutable<ExcalidrawElement>>(
|
|
@ -1,9 +1,9 @@
|
||||||
import type Scene from "@excalidraw/excalidraw/scene/Scene";
|
|
||||||
|
|
||||||
import { updateBoundElements } from "./binding";
|
import { updateBoundElements } from "./binding";
|
||||||
import { getCommonBoundingBox } from "./bounds";
|
import { getCommonBoundingBox } from "./bounds";
|
||||||
import { getMaximumGroups } from "./groups";
|
import { getMaximumGroups } from "./groups";
|
||||||
|
|
||||||
|
import type Scene from "./Scene";
|
||||||
|
|
||||||
import type { BoundingBox } from "./bounds";
|
import type { BoundingBox } from "./bounds";
|
||||||
import type { ExcalidrawElement } from "./types";
|
import type { ExcalidrawElement } from "./types";
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ export const alignElements = (
|
||||||
});
|
});
|
||||||
|
|
||||||
// update bound elements
|
// update bound elements
|
||||||
updateBoundElements(element, elementsMap, {
|
updateBoundElements(element, scene, {
|
||||||
simultaneouslyUpdated: group,
|
simultaneouslyUpdated: group,
|
||||||
});
|
});
|
||||||
return updatedEle;
|
return updatedEle;
|
||||||
|
|
|
@ -30,8 +30,6 @@ import { isPointOnShape } from "@excalidraw/utils/collision";
|
||||||
|
|
||||||
import type { LocalPoint, Radians } from "@excalidraw/math";
|
import type { LocalPoint, Radians } from "@excalidraw/math";
|
||||||
|
|
||||||
import type Scene from "@excalidraw/excalidraw/scene/Scene";
|
|
||||||
|
|
||||||
import type { AppState } from "@excalidraw/excalidraw/types";
|
import type { AppState } from "@excalidraw/excalidraw/types";
|
||||||
|
|
||||||
import type { Mutable } from "@excalidraw/common/utility-types";
|
import type { Mutable } from "@excalidraw/common/utility-types";
|
||||||
|
@ -68,6 +66,8 @@ import {
|
||||||
import { aabbForElement, getElementShape, pointInsideBounds } from "./shapes";
|
import { aabbForElement, getElementShape, pointInsideBounds } from "./shapes";
|
||||||
import { updateElbowArrowPoints } from "./elbowArrow";
|
import { updateElbowArrowPoints } from "./elbowArrow";
|
||||||
|
|
||||||
|
import type Scene from "./Scene";
|
||||||
|
|
||||||
import type { Bounds } from "./bounds";
|
import type { Bounds } from "./bounds";
|
||||||
import type { ElementUpdate } from "./mutateElement";
|
import type { ElementUpdate } from "./mutateElement";
|
||||||
import type {
|
import type {
|
||||||
|
@ -177,8 +177,6 @@ const bindOrUnbindLinearElementEdge = (
|
||||||
unboundFromElementIds: Set<ExcalidrawBindableElement["id"]>,
|
unboundFromElementIds: Set<ExcalidrawBindableElement["id"]>,
|
||||||
scene: Scene,
|
scene: Scene,
|
||||||
): void => {
|
): void => {
|
||||||
const elementsMap = scene.getNonDeletedElementsMap();
|
|
||||||
|
|
||||||
// "keep" is for method chaining convenience, a "no-op", so just bail out
|
// "keep" is for method chaining convenience, a "no-op", so just bail out
|
||||||
if (bindableElement === "keep") {
|
if (bindableElement === "keep") {
|
||||||
return;
|
return;
|
||||||
|
@ -209,23 +207,11 @@ const bindOrUnbindLinearElementEdge = (
|
||||||
: startOrEnd === "start" ||
|
: startOrEnd === "start" ||
|
||||||
otherEdgeBindableElement.id !== bindableElement.id)
|
otherEdgeBindableElement.id !== bindableElement.id)
|
||||||
) {
|
) {
|
||||||
bindLinearElement(
|
bindLinearElement(linearElement, bindableElement, startOrEnd, scene);
|
||||||
linearElement,
|
|
||||||
bindableElement,
|
|
||||||
startOrEnd,
|
|
||||||
elementsMap,
|
|
||||||
(...args) => scene.mutate(...args),
|
|
||||||
);
|
|
||||||
boundToElementIds.add(bindableElement.id);
|
boundToElementIds.add(bindableElement.id);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bindLinearElement(
|
bindLinearElement(linearElement, bindableElement, startOrEnd, scene);
|
||||||
linearElement,
|
|
||||||
bindableElement,
|
|
||||||
startOrEnd,
|
|
||||||
elementsMap,
|
|
||||||
(...args) => scene.mutate(...args),
|
|
||||||
);
|
|
||||||
boundToElementIds.add(bindableElement.id);
|
boundToElementIds.add(bindableElement.id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -443,8 +429,7 @@ export const maybeBindLinearElement = (
|
||||||
linearElement,
|
linearElement,
|
||||||
appState.startBoundElement,
|
appState.startBoundElement,
|
||||||
"start",
|
"start",
|
||||||
elementsMap,
|
scene,
|
||||||
(...args) => scene.mutate(...args),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,13 +450,7 @@ export const maybeBindLinearElement = (
|
||||||
"end",
|
"end",
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
bindLinearElement(
|
bindLinearElement(linearElement, hoveredElement, "end", scene);
|
||||||
linearElement,
|
|
||||||
hoveredElement,
|
|
||||||
"end",
|
|
||||||
elementsMap,
|
|
||||||
(...args) => scene.mutate(...args),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -500,11 +479,7 @@ export const bindLinearElement = (
|
||||||
linearElement: NonDeleted<ExcalidrawLinearElement>,
|
linearElement: NonDeleted<ExcalidrawLinearElement>,
|
||||||
hoveredElement: ExcalidrawBindableElement,
|
hoveredElement: ExcalidrawBindableElement,
|
||||||
startOrEnd: "start" | "end",
|
startOrEnd: "start" | "end",
|
||||||
elementsMap: ElementsMap,
|
scene: Scene,
|
||||||
mutator: (
|
|
||||||
element: ExcalidrawElement,
|
|
||||||
updates: ElementUpdate<ExcalidrawElement>,
|
|
||||||
) => ExcalidrawElement,
|
|
||||||
): void => {
|
): void => {
|
||||||
if (!isArrowElement(linearElement)) {
|
if (!isArrowElement(linearElement)) {
|
||||||
return;
|
return;
|
||||||
|
@ -517,7 +492,7 @@ export const bindLinearElement = (
|
||||||
linearElement,
|
linearElement,
|
||||||
hoveredElement,
|
hoveredElement,
|
||||||
startOrEnd,
|
startOrEnd,
|
||||||
elementsMap as NonDeletedSceneElementsMap,
|
scene.getNonDeletedElementsMap(),
|
||||||
),
|
),
|
||||||
hoveredElement,
|
hoveredElement,
|
||||||
),
|
),
|
||||||
|
@ -534,13 +509,13 @@ export const bindLinearElement = (
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
mutator(linearElement, {
|
scene.mutate(linearElement, {
|
||||||
[startOrEnd === "start" ? "startBinding" : "endBinding"]: binding,
|
[startOrEnd === "start" ? "startBinding" : "endBinding"]: binding,
|
||||||
});
|
});
|
||||||
|
|
||||||
const boundElementsMap = arrayToMap(hoveredElement.boundElements || []);
|
const boundElementsMap = arrayToMap(hoveredElement.boundElements || []);
|
||||||
if (!boundElementsMap.has(linearElement.id)) {
|
if (!boundElementsMap.has(linearElement.id)) {
|
||||||
mutator(hoveredElement, {
|
scene.mutate(hoveredElement, {
|
||||||
boundElements: (hoveredElement.boundElements || []).concat({
|
boundElements: (hoveredElement.boundElements || []).concat({
|
||||||
id: linearElement.id,
|
id: linearElement.id,
|
||||||
type: "arrow",
|
type: "arrow",
|
||||||
|
@ -757,7 +732,7 @@ const calculateFocusAndGap = (
|
||||||
// in explicitly.
|
// in explicitly.
|
||||||
export const updateBoundElements = (
|
export const updateBoundElements = (
|
||||||
changedElement: NonDeletedExcalidrawElement,
|
changedElement: NonDeletedExcalidrawElement,
|
||||||
elementsMap: ElementsMap,
|
scene: Scene,
|
||||||
options?: {
|
options?: {
|
||||||
simultaneouslyUpdated?: readonly ExcalidrawElement[];
|
simultaneouslyUpdated?: readonly ExcalidrawElement[];
|
||||||
newSize?: { width: number; height: number };
|
newSize?: { width: number; height: number };
|
||||||
|
@ -773,6 +748,8 @@ export const updateBoundElements = (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
|
|
||||||
boundElementsVisitor(elementsMap, changedElement, (element) => {
|
boundElementsVisitor(elementsMap, changedElement, (element) => {
|
||||||
if (!isLinearElement(element) || element.isDeleted) {
|
if (!isLinearElement(element) || element.isDeleted) {
|
||||||
return;
|
return;
|
||||||
|
@ -860,7 +837,7 @@ export const updateBoundElements = (
|
||||||
}> => update !== null,
|
}> => update !== null,
|
||||||
);
|
);
|
||||||
|
|
||||||
LinearElementEditor.movePoints(element, elementsMap, updates, {
|
LinearElementEditor.movePoints(element, scene, updates, {
|
||||||
...(changedElement.id === element.startBinding?.elementId
|
...(changedElement.id === element.startBinding?.elementId
|
||||||
? { startBinding: bindings.startBinding }
|
? { startBinding: bindings.startBinding }
|
||||||
: {}),
|
: {}),
|
||||||
|
|
|
@ -11,8 +11,6 @@ import type {
|
||||||
PointerDownState,
|
PointerDownState,
|
||||||
} from "@excalidraw/excalidraw/types";
|
} from "@excalidraw/excalidraw/types";
|
||||||
|
|
||||||
import type Scene from "@excalidraw/excalidraw/scene/Scene";
|
|
||||||
|
|
||||||
import type { NonDeletedExcalidrawElement } from "@excalidraw/element/types";
|
import type { NonDeletedExcalidrawElement } from "@excalidraw/element/types";
|
||||||
|
|
||||||
import { updateBoundElements } from "./binding";
|
import { updateBoundElements } from "./binding";
|
||||||
|
@ -28,6 +26,8 @@ import {
|
||||||
isTextElement,
|
isTextElement,
|
||||||
} from "./typeChecks";
|
} from "./typeChecks";
|
||||||
|
|
||||||
|
import type Scene from "./Scene";
|
||||||
|
|
||||||
import type { Bounds } from "./bounds";
|
import type { Bounds } from "./bounds";
|
||||||
import type { ExcalidrawElement } from "./types";
|
import type { ExcalidrawElement } from "./types";
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ export const dragSelectedElements = (
|
||||||
adjustedOffset,
|
adjustedOffset,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
updateBoundElements(element, scene.getNonDeletedElementsMap(), {
|
updateBoundElements(element, scene, {
|
||||||
simultaneouslyUpdated: Array.from(elementsToUpdate),
|
simultaneouslyUpdated: Array.from(elementsToUpdate),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,6 @@ import type {
|
||||||
PendingExcalidrawElements,
|
PendingExcalidrawElements,
|
||||||
} from "@excalidraw/excalidraw/types";
|
} from "@excalidraw/excalidraw/types";
|
||||||
|
|
||||||
import type Scene from "@excalidraw/excalidraw/scene/Scene";
|
|
||||||
|
|
||||||
import { bindLinearElement } from "./binding";
|
import { bindLinearElement } from "./binding";
|
||||||
import { updateElbowArrowPoints } from "./elbowArrow";
|
import { updateElbowArrowPoints } from "./elbowArrow";
|
||||||
import {
|
import {
|
||||||
|
@ -41,6 +39,8 @@ import {
|
||||||
type OrderedExcalidrawElement,
|
type OrderedExcalidrawElement,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
|
import type Scene from "./Scene";
|
||||||
|
|
||||||
type LinkDirection = "up" | "right" | "down" | "left";
|
type LinkDirection = "up" | "right" | "down" | "left";
|
||||||
|
|
||||||
const VERTICAL_OFFSET = 100;
|
const VERTICAL_OFFSET = 100;
|
||||||
|
@ -445,20 +445,8 @@ const createBindingArrow = (
|
||||||
|
|
||||||
const elementsMap = scene.getNonDeletedElementsMap();
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
|
|
||||||
bindLinearElement(
|
bindLinearElement(bindingArrow, startBindingElement, "start", scene);
|
||||||
bindingArrow,
|
bindLinearElement(bindingArrow, endBindingElement, "end", scene);
|
||||||
startBindingElement,
|
|
||||||
"start",
|
|
||||||
elementsMap,
|
|
||||||
(...args) => scene.mutate(...args),
|
|
||||||
);
|
|
||||||
bindLinearElement(
|
|
||||||
bindingArrow,
|
|
||||||
endBindingElement,
|
|
||||||
"end",
|
|
||||||
elementsMap,
|
|
||||||
(...args) => scene.mutate(...args),
|
|
||||||
);
|
|
||||||
|
|
||||||
const changedElements = new Map<string, OrderedExcalidrawElement>();
|
const changedElements = new Map<string, OrderedExcalidrawElement>();
|
||||||
changedElements.set(
|
changedElements.set(
|
||||||
|
@ -474,7 +462,7 @@ const createBindingArrow = (
|
||||||
bindingArrow as OrderedExcalidrawElement,
|
bindingArrow as OrderedExcalidrawElement,
|
||||||
);
|
);
|
||||||
|
|
||||||
LinearElementEditor.movePoints(bindingArrow, elementsMap, [
|
LinearElementEditor.movePoints(bindingArrow, scene, [
|
||||||
{
|
{
|
||||||
index: 1,
|
index: 1,
|
||||||
point: bindingArrow.points[1],
|
point: bindingArrow.points[1],
|
||||||
|
|
|
@ -3,8 +3,6 @@ import { isPointWithinBounds, pointFrom } from "@excalidraw/math";
|
||||||
import { doLineSegmentsIntersect } from "@excalidraw/utils/bbox";
|
import { doLineSegmentsIntersect } from "@excalidraw/utils/bbox";
|
||||||
import { elementsOverlappingBBox } from "@excalidraw/utils/withinBounds";
|
import { elementsOverlappingBBox } from "@excalidraw/utils/withinBounds";
|
||||||
|
|
||||||
import type { ExcalidrawElementsIncludingDeleted } from "@excalidraw/excalidraw/scene/Scene";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
AppClassProperties,
|
AppClassProperties,
|
||||||
AppState,
|
AppState,
|
||||||
|
@ -29,6 +27,8 @@ import {
|
||||||
isTextElement,
|
isTextElement,
|
||||||
} from "./typeChecks";
|
} from "./typeChecks";
|
||||||
|
|
||||||
|
import type { ExcalidrawElementsIncludingDeleted } from "./Scene";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ElementsMap,
|
ElementsMap,
|
||||||
ElementsMapOrArray,
|
ElementsMapOrArray,
|
||||||
|
|
|
@ -20,8 +20,6 @@ import {
|
||||||
tupleToCoors,
|
tupleToCoors,
|
||||||
} from "@excalidraw/common";
|
} from "@excalidraw/common";
|
||||||
|
|
||||||
import type Scene from "@excalidraw/excalidraw/scene/Scene";
|
|
||||||
|
|
||||||
import type { Store } from "@excalidraw/excalidraw/store";
|
import type { Store } from "@excalidraw/excalidraw/store";
|
||||||
|
|
||||||
import type { Radians } from "@excalidraw/math";
|
import type { Radians } from "@excalidraw/math";
|
||||||
|
@ -69,6 +67,8 @@ import {
|
||||||
|
|
||||||
import { getLockedLinearCursorAlignSize } from "./sizeHelpers";
|
import { getLockedLinearCursorAlignSize } from "./sizeHelpers";
|
||||||
|
|
||||||
|
import type Scene from "./Scene";
|
||||||
|
|
||||||
import type { Bounds } from "./bounds";
|
import type { Bounds } from "./bounds";
|
||||||
import type {
|
import type {
|
||||||
NonDeleted,
|
NonDeleted,
|
||||||
|
@ -80,7 +80,6 @@ import type {
|
||||||
ElementsMap,
|
ElementsMap,
|
||||||
NonDeletedSceneElementsMap,
|
NonDeletedSceneElementsMap,
|
||||||
FixedPointBinding,
|
FixedPointBinding,
|
||||||
SceneElementsMap,
|
|
||||||
FixedSegment,
|
FixedSegment,
|
||||||
ExcalidrawElbowArrowElement,
|
ExcalidrawElbowArrowElement,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
@ -307,7 +306,7 @@ export class LinearElementEditor {
|
||||||
event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(),
|
event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(),
|
||||||
);
|
);
|
||||||
|
|
||||||
LinearElementEditor.movePoints(element, elementsMap, [
|
LinearElementEditor.movePoints(element, scene, [
|
||||||
{
|
{
|
||||||
index: selectedIndex,
|
index: selectedIndex,
|
||||||
point: pointFrom(
|
point: pointFrom(
|
||||||
|
@ -331,7 +330,7 @@ export class LinearElementEditor {
|
||||||
|
|
||||||
LinearElementEditor.movePoints(
|
LinearElementEditor.movePoints(
|
||||||
element,
|
element,
|
||||||
elementsMap,
|
scene,
|
||||||
selectedPointsIndices.map((pointIndex) => {
|
selectedPointsIndices.map((pointIndex) => {
|
||||||
const newPointPosition: LocalPoint =
|
const newPointPosition: LocalPoint =
|
||||||
pointIndex === lastClickedPoint
|
pointIndex === lastClickedPoint
|
||||||
|
@ -452,7 +451,7 @@ export class LinearElementEditor {
|
||||||
selectedPoint === element.points.length - 1
|
selectedPoint === element.points.length - 1
|
||||||
) {
|
) {
|
||||||
if (isPathALoop(element.points, appState.zoom.value)) {
|
if (isPathALoop(element.points, appState.zoom.value)) {
|
||||||
LinearElementEditor.movePoints(element, elementsMap, [
|
LinearElementEditor.movePoints(element, scene, [
|
||||||
{
|
{
|
||||||
index: selectedPoint,
|
index: selectedPoint,
|
||||||
point:
|
point:
|
||||||
|
@ -932,13 +931,13 @@ export class LinearElementEditor {
|
||||||
scenePointerX: number,
|
scenePointerX: number,
|
||||||
scenePointerY: number,
|
scenePointerY: number,
|
||||||
app: AppClassProperties,
|
app: AppClassProperties,
|
||||||
elementsMap: NonDeletedSceneElementsMap | SceneElementsMap,
|
|
||||||
): LinearElementEditor | null {
|
): LinearElementEditor | null {
|
||||||
const appState = app.state;
|
const appState = app.state;
|
||||||
if (!appState.editingLinearElement) {
|
if (!appState.editingLinearElement) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const { elementId, lastUncommittedPoint } = appState.editingLinearElement;
|
const { elementId, lastUncommittedPoint } = appState.editingLinearElement;
|
||||||
|
const elementsMap = app.scene.getNonDeletedElementsMap();
|
||||||
const element = LinearElementEditor.getElement(elementId, elementsMap);
|
const element = LinearElementEditor.getElement(elementId, elementsMap);
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return appState.editingLinearElement;
|
return appState.editingLinearElement;
|
||||||
|
@ -949,7 +948,7 @@ export class LinearElementEditor {
|
||||||
|
|
||||||
if (!event.altKey) {
|
if (!event.altKey) {
|
||||||
if (lastPoint === lastUncommittedPoint) {
|
if (lastPoint === lastUncommittedPoint) {
|
||||||
LinearElementEditor.deletePoints(element, elementsMap, [
|
LinearElementEditor.deletePoints(element, app.scene, [
|
||||||
points.length - 1,
|
points.length - 1,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -989,16 +988,14 @@ export class LinearElementEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastPoint === lastUncommittedPoint) {
|
if (lastPoint === lastUncommittedPoint) {
|
||||||
LinearElementEditor.movePoints(element, elementsMap, [
|
LinearElementEditor.movePoints(element, app.scene, [
|
||||||
{
|
{
|
||||||
index: element.points.length - 1,
|
index: element.points.length - 1,
|
||||||
point: newPoint,
|
point: newPoint,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
LinearElementEditor.addPoints(element, elementsMap, [
|
LinearElementEditor.addPoints(element, app.scene, [{ point: newPoint }]);
|
||||||
{ point: newPoint },
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
...appState.editingLinearElement,
|
...appState.editingLinearElement,
|
||||||
|
@ -1168,7 +1165,6 @@ export class LinearElementEditor {
|
||||||
element: NonDeleted<ExcalidrawLinearElement>,
|
element: NonDeleted<ExcalidrawLinearElement>,
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
) {
|
) {
|
||||||
// TODO_SCENE: we don't need to inform mutation here?
|
|
||||||
mutateElementWith(
|
mutateElementWith(
|
||||||
element,
|
element,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
|
@ -1231,7 +1227,7 @@ export class LinearElementEditor {
|
||||||
// potentially expanding the bounding box
|
// potentially expanding the bounding box
|
||||||
if (pointAddedToEnd) {
|
if (pointAddedToEnd) {
|
||||||
const lastPoint = element.points[element.points.length - 1];
|
const lastPoint = element.points[element.points.length - 1];
|
||||||
LinearElementEditor.movePoints(element, elementsMap, [
|
LinearElementEditor.movePoints(element, scene, [
|
||||||
{
|
{
|
||||||
index: element.points.length - 1,
|
index: element.points.length - 1,
|
||||||
point: pointFrom(lastPoint[0] + 30, lastPoint[1] + 30),
|
point: pointFrom(lastPoint[0] + 30, lastPoint[1] + 30),
|
||||||
|
@ -1250,7 +1246,7 @@ export class LinearElementEditor {
|
||||||
|
|
||||||
static deletePoints(
|
static deletePoints(
|
||||||
element: NonDeleted<ExcalidrawLinearElement>,
|
element: NonDeleted<ExcalidrawLinearElement>,
|
||||||
elementsMap: ElementsMap,
|
scene: Scene,
|
||||||
pointIndices: readonly number[],
|
pointIndices: readonly number[],
|
||||||
) {
|
) {
|
||||||
let offsetX = 0;
|
let offsetX = 0;
|
||||||
|
@ -1283,7 +1279,7 @@ export class LinearElementEditor {
|
||||||
|
|
||||||
LinearElementEditor._updatePoints(
|
LinearElementEditor._updatePoints(
|
||||||
element,
|
element,
|
||||||
elementsMap,
|
scene,
|
||||||
nextPoints,
|
nextPoints,
|
||||||
offsetX,
|
offsetX,
|
||||||
offsetY,
|
offsetY,
|
||||||
|
@ -1292,7 +1288,7 @@ export class LinearElementEditor {
|
||||||
|
|
||||||
static addPoints(
|
static addPoints(
|
||||||
element: NonDeleted<ExcalidrawLinearElement>,
|
element: NonDeleted<ExcalidrawLinearElement>,
|
||||||
elementsMap: ElementsMap,
|
scene: Scene,
|
||||||
targetPoints: { point: LocalPoint }[],
|
targetPoints: { point: LocalPoint }[],
|
||||||
) {
|
) {
|
||||||
const offsetX = 0;
|
const offsetX = 0;
|
||||||
|
@ -1301,7 +1297,7 @@ export class LinearElementEditor {
|
||||||
const nextPoints = [...element.points, ...targetPoints.map((x) => x.point)];
|
const nextPoints = [...element.points, ...targetPoints.map((x) => x.point)];
|
||||||
LinearElementEditor._updatePoints(
|
LinearElementEditor._updatePoints(
|
||||||
element,
|
element,
|
||||||
elementsMap,
|
scene,
|
||||||
nextPoints,
|
nextPoints,
|
||||||
offsetX,
|
offsetX,
|
||||||
offsetY,
|
offsetY,
|
||||||
|
@ -1310,7 +1306,7 @@ export class LinearElementEditor {
|
||||||
|
|
||||||
static movePoints(
|
static movePoints(
|
||||||
element: NonDeleted<ExcalidrawLinearElement>,
|
element: NonDeleted<ExcalidrawLinearElement>,
|
||||||
elementsMap: ElementsMap,
|
scene: Scene,
|
||||||
targetPoints: { index: number; point: LocalPoint; isDragging?: boolean }[],
|
targetPoints: { index: number; point: LocalPoint; isDragging?: boolean }[],
|
||||||
otherUpdates?: {
|
otherUpdates?: {
|
||||||
startBinding?: PointBinding | null;
|
startBinding?: PointBinding | null;
|
||||||
|
@ -1349,7 +1345,7 @@ export class LinearElementEditor {
|
||||||
|
|
||||||
LinearElementEditor._updatePoints(
|
LinearElementEditor._updatePoints(
|
||||||
element,
|
element,
|
||||||
elementsMap,
|
scene,
|
||||||
nextPoints,
|
nextPoints,
|
||||||
offsetX,
|
offsetX,
|
||||||
offsetY,
|
offsetY,
|
||||||
|
@ -1462,7 +1458,7 @@ export class LinearElementEditor {
|
||||||
|
|
||||||
private static _updatePoints(
|
private static _updatePoints(
|
||||||
element: NonDeleted<ExcalidrawLinearElement>,
|
element: NonDeleted<ExcalidrawLinearElement>,
|
||||||
elementsMap: ElementsMap,
|
scene: Scene,
|
||||||
nextPoints: readonly LocalPoint[],
|
nextPoints: readonly LocalPoint[],
|
||||||
offsetX: number,
|
offsetX: number,
|
||||||
offsetY: number,
|
offsetY: number,
|
||||||
|
@ -1499,7 +1495,7 @@ export class LinearElementEditor {
|
||||||
|
|
||||||
updates.points = Array.from(nextPoints);
|
updates.points = Array.from(nextPoints);
|
||||||
|
|
||||||
mutateElementWith(element, elementsMap, updates, {
|
scene.mutate(element, updates, {
|
||||||
isDragging: options?.isDragging,
|
isDragging: options?.isDragging,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -1516,7 +1512,7 @@ export class LinearElementEditor {
|
||||||
pointFrom(dX, dY),
|
pointFrom(dX, dY),
|
||||||
element.angle,
|
element.angle,
|
||||||
);
|
);
|
||||||
mutateElement(element, {
|
scene.mutate(element, {
|
||||||
...otherUpdates,
|
...otherUpdates,
|
||||||
points: nextPoints,
|
points: nextPoints,
|
||||||
x: element.x + rotated[0],
|
x: element.x + rotated[0],
|
||||||
|
|
|
@ -17,8 +17,6 @@ import {
|
||||||
|
|
||||||
import type { GlobalPoint } from "@excalidraw/math";
|
import type { GlobalPoint } from "@excalidraw/math";
|
||||||
|
|
||||||
import type Scene from "@excalidraw/excalidraw/scene/Scene";
|
|
||||||
|
|
||||||
import type { PointerDownState } from "@excalidraw/excalidraw/types";
|
import type { PointerDownState } from "@excalidraw/excalidraw/types";
|
||||||
|
|
||||||
import type { Mutable } from "@excalidraw/common/utility-types";
|
import type { Mutable } from "@excalidraw/common/utility-types";
|
||||||
|
@ -60,6 +58,8 @@ import {
|
||||||
|
|
||||||
import { isInGroup } from "./groups";
|
import { isInGroup } from "./groups";
|
||||||
|
|
||||||
|
import type Scene from "./Scene";
|
||||||
|
|
||||||
import type { BoundingBox } from "./bounds";
|
import type { BoundingBox } from "./bounds";
|
||||||
import type {
|
import type {
|
||||||
MaybeTransformHandleType,
|
MaybeTransformHandleType,
|
||||||
|
@ -103,7 +103,7 @@ export const transformElements = (
|
||||||
pointerY,
|
pointerY,
|
||||||
shouldRotateWithDiscreteAngle,
|
shouldRotateWithDiscreteAngle,
|
||||||
);
|
);
|
||||||
updateBoundElements(element, elementsMap);
|
updateBoundElements(element, scene);
|
||||||
}
|
}
|
||||||
} else if (isTextElement(element) && transformHandleType) {
|
} else if (isTextElement(element) && transformHandleType) {
|
||||||
resizeSingleTextElement(
|
resizeSingleTextElement(
|
||||||
|
@ -115,7 +115,7 @@ export const transformElements = (
|
||||||
pointerX,
|
pointerX,
|
||||||
pointerY,
|
pointerY,
|
||||||
);
|
);
|
||||||
updateBoundElements(element, elementsMap);
|
updateBoundElements(element, scene);
|
||||||
return true;
|
return true;
|
||||||
} else if (transformHandleType) {
|
} else if (transformHandleType) {
|
||||||
const elementId = selectedElements[0].id;
|
const elementId = selectedElements[0].id;
|
||||||
|
@ -554,7 +554,7 @@ const rotateMultipleElements = (
|
||||||
|
|
||||||
scene.mutate(element, updates);
|
scene.mutate(element, updates);
|
||||||
|
|
||||||
updateBoundElements(element, elementsMap, {
|
updateBoundElements(element, scene, {
|
||||||
simultaneouslyUpdated: elements,
|
simultaneouslyUpdated: elements,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -964,7 +964,7 @@ export const resizeSingleElement = (
|
||||||
|
|
||||||
const elementsMap = scene.getNonDeletedElementsMap();
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
|
|
||||||
updateBoundElements(latestElement, elementsMap, {
|
updateBoundElements(latestElement, scene, {
|
||||||
// TODO: confirm with MARK if this actually makes sense
|
// TODO: confirm with MARK if this actually makes sense
|
||||||
newSize: { width: nextWidth, height: nextHeight },
|
newSize: { width: nextWidth, height: nextHeight },
|
||||||
});
|
});
|
||||||
|
@ -1525,7 +1525,7 @@ export const resizeMultipleElements = (
|
||||||
isDragging: true,
|
isDragging: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
updateBoundElements(element, scene.getNonDeletedElementsMap(), {
|
updateBoundElements(element, scene, {
|
||||||
simultaneouslyUpdated: elementsToUpdate,
|
simultaneouslyUpdated: elementsToUpdate,
|
||||||
newSize: { width, height },
|
newSize: { width, height },
|
||||||
});
|
});
|
||||||
|
|
|
@ -27,7 +27,7 @@ import {
|
||||||
isTextElement,
|
isTextElement,
|
||||||
} from "./typeChecks";
|
} from "./typeChecks";
|
||||||
|
|
||||||
import type { ElementUpdate } from "./mutateElement";
|
import type Scene from "./Scene";
|
||||||
|
|
||||||
import type { MaybeTransformHandleType } from "./transformHandles";
|
import type { MaybeTransformHandleType } from "./transformHandles";
|
||||||
import type {
|
import type {
|
||||||
|
@ -43,12 +43,10 @@ import type {
|
||||||
export const redrawTextBoundingBox = (
|
export const redrawTextBoundingBox = (
|
||||||
textElement: ExcalidrawTextElement,
|
textElement: ExcalidrawTextElement,
|
||||||
container: ExcalidrawElement | null,
|
container: ExcalidrawElement | null,
|
||||||
elementsMap: ElementsMap,
|
scene: Scene,
|
||||||
mutator: (
|
|
||||||
element: ExcalidrawElement,
|
|
||||||
updates: ElementUpdate<ExcalidrawElement>,
|
|
||||||
) => ExcalidrawElement,
|
|
||||||
) => {
|
) => {
|
||||||
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
|
|
||||||
let maxWidth = undefined;
|
let maxWidth = undefined;
|
||||||
const boundTextUpdates = {
|
const boundTextUpdates = {
|
||||||
x: textElement.x,
|
x: textElement.x,
|
||||||
|
@ -96,30 +94,34 @@ export const redrawTextBoundingBox = (
|
||||||
metrics.height,
|
metrics.height,
|
||||||
container.type,
|
container.type,
|
||||||
);
|
);
|
||||||
mutator(container, { height: nextHeight });
|
scene.mutate(container, { height: nextHeight });
|
||||||
updateOriginalContainerCache(container.id, nextHeight);
|
updateOriginalContainerCache(container.id, nextHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metrics.width > maxContainerWidth) {
|
if (metrics.width > maxContainerWidth) {
|
||||||
const nextWidth = computeContainerDimensionForBoundText(
|
const nextWidth = computeContainerDimensionForBoundText(
|
||||||
metrics.width,
|
metrics.width,
|
||||||
container.type,
|
container.type,
|
||||||
);
|
);
|
||||||
mutator(container, { width: nextWidth });
|
scene.mutate(container, { width: nextWidth });
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedTextElement = {
|
const updatedTextElement = {
|
||||||
...textElement,
|
...textElement,
|
||||||
...boundTextUpdates,
|
...boundTextUpdates,
|
||||||
} as ExcalidrawTextElementWithContainer;
|
} as ExcalidrawTextElementWithContainer;
|
||||||
|
|
||||||
const { x, y } = computeBoundTextPosition(
|
const { x, y } = computeBoundTextPosition(
|
||||||
container,
|
container,
|
||||||
updatedTextElement,
|
updatedTextElement,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
);
|
);
|
||||||
|
|
||||||
boundTextUpdates.x = x;
|
boundTextUpdates.x = x;
|
||||||
boundTextUpdates.y = y;
|
boundTextUpdates.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutator(textElement, boundTextUpdates);
|
scene.mutate(textElement, boundTextUpdates);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const handleBindTextResize = (
|
export const handleBindTextResize = (
|
||||||
|
|
|
@ -2,8 +2,6 @@ import { arrayToMap, findIndex, findLastIndex } from "@excalidraw/common";
|
||||||
|
|
||||||
import type { AppState } from "@excalidraw/excalidraw/types";
|
import type { AppState } from "@excalidraw/excalidraw/types";
|
||||||
|
|
||||||
import type Scene from "@excalidraw/excalidraw/scene/Scene";
|
|
||||||
|
|
||||||
import { isFrameLikeElement } from "./typeChecks";
|
import { isFrameLikeElement } from "./typeChecks";
|
||||||
|
|
||||||
import { getElementsInGroup } from "./groups";
|
import { getElementsInGroup } from "./groups";
|
||||||
|
@ -12,6 +10,8 @@ import { syncMovedIndices } from "./fractionalIndex";
|
||||||
|
|
||||||
import { getSelectedElements } from "./selection";
|
import { getSelectedElements } from "./selection";
|
||||||
|
|
||||||
|
import type Scene from "./Scene";
|
||||||
|
|
||||||
import type { ExcalidrawElement, ExcalidrawFrameLikeElement } from "./types";
|
import type { ExcalidrawElement, ExcalidrawFrameLikeElement } from "./types";
|
||||||
|
|
||||||
const isOfTargetFrame = (element: ExcalidrawElement, frameId: string) => {
|
const isOfTargetFrame = (element: ExcalidrawElement, frameId: string) => {
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { ARROW_TYPE } from "@excalidraw/common";
|
||||||
import { pointFrom } from "@excalidraw/math";
|
import { pointFrom } from "@excalidraw/math";
|
||||||
import { Excalidraw, mutateElement } from "@excalidraw/excalidraw";
|
import { Excalidraw, mutateElement } from "@excalidraw/excalidraw";
|
||||||
|
|
||||||
import Scene from "@excalidraw/excalidraw/scene/Scene";
|
|
||||||
import { actionSelectAll } from "@excalidraw/excalidraw/actions";
|
import { actionSelectAll } from "@excalidraw/excalidraw/actions";
|
||||||
import { actionDuplicateSelection } from "@excalidraw/excalidraw/actions/actionDuplicateSelection";
|
import { actionDuplicateSelection } from "@excalidraw/excalidraw/actions/actionDuplicateSelection";
|
||||||
|
|
||||||
|
@ -23,6 +22,8 @@ import type { LocalPoint } from "@excalidraw/math";
|
||||||
|
|
||||||
import { bindLinearElement } from "../src/binding";
|
import { bindLinearElement } from "../src/binding";
|
||||||
|
|
||||||
|
import Scene from "../src/Scene";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ExcalidrawArrowElement,
|
ExcalidrawArrowElement,
|
||||||
ExcalidrawBindableElement,
|
ExcalidrawBindableElement,
|
||||||
|
@ -187,13 +188,9 @@ describe("elbow arrow routing", () => {
|
||||||
scene.insertElement(rectangle1);
|
scene.insertElement(rectangle1);
|
||||||
scene.insertElement(rectangle2);
|
scene.insertElement(rectangle2);
|
||||||
scene.insertElement(arrow);
|
scene.insertElement(arrow);
|
||||||
const elementsMap = scene.getNonDeletedElementsMap();
|
|
||||||
bindLinearElement(arrow, rectangle1, "start", elementsMap, (...args) =>
|
bindLinearElement(arrow, rectangle1, "start", scene);
|
||||||
scene.mutate(...args),
|
bindLinearElement(arrow, rectangle2, "end", scene);
|
||||||
);
|
|
||||||
bindLinearElement(arrow, rectangle2, "end", elementsMap, (...args) =>
|
|
||||||
scene.mutate(...args),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(arrow.startBinding).not.toBe(null);
|
expect(arrow.startBinding).not.toBe(null);
|
||||||
expect(arrow.endBinding).not.toBe(null);
|
expect(arrow.endBinding).not.toBe(null);
|
||||||
|
|
|
@ -162,12 +162,7 @@ export const actionBindText = register({
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const originalContainerHeight = container.height;
|
const originalContainerHeight = container.height;
|
||||||
redrawTextBoundingBox(
|
redrawTextBoundingBox(textElement, container, app.scene);
|
||||||
textElement,
|
|
||||||
container,
|
|
||||||
app.scene.getNonDeletedElementsMap(),
|
|
||||||
(...args) => app.scene.mutate(...args),
|
|
||||||
);
|
|
||||||
// overwritting the cache with original container height so
|
// overwritting the cache with original container height so
|
||||||
// it can be restored when unbind
|
// it can be restored when unbind
|
||||||
updateOriginalContainerCache(container.id, originalContainerHeight);
|
updateOriginalContainerCache(container.id, originalContainerHeight);
|
||||||
|
@ -312,12 +307,8 @@ export const actionWrapTextInContainer = register({
|
||||||
textAlign: TEXT_ALIGN.CENTER,
|
textAlign: TEXT_ALIGN.CENTER,
|
||||||
autoResize: true,
|
autoResize: true,
|
||||||
});
|
});
|
||||||
redrawTextBoundingBox(
|
|
||||||
textElement,
|
redrawTextBoundingBox(textElement, container, app.scene);
|
||||||
container,
|
|
||||||
app.scene.getNonDeletedElementsMap(),
|
|
||||||
(...args) => app.scene.mutate(...args),
|
|
||||||
);
|
|
||||||
|
|
||||||
updatedElements = pushContainerBelowText(
|
updatedElements = pushContainerBelowText(
|
||||||
[...updatedElements, container],
|
[...updatedElements, container],
|
||||||
|
|
|
@ -259,7 +259,7 @@ export const actionDeleteSelected = register({
|
||||||
|
|
||||||
LinearElementEditor.deletePoints(
|
LinearElementEditor.deletePoints(
|
||||||
element,
|
element,
|
||||||
elementsMap,
|
app.scene,
|
||||||
selectedPointsIndices,
|
selectedPointsIndices,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,8 @@ import type {
|
||||||
VerticalAlign,
|
VerticalAlign,
|
||||||
} from "@excalidraw/element/types";
|
} from "@excalidraw/element/types";
|
||||||
|
|
||||||
|
import type Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import { trackEvent } from "../analytics";
|
import { trackEvent } from "../analytics";
|
||||||
import { ButtonIconSelect } from "../components/ButtonIconSelect";
|
import { ButtonIconSelect } from "../components/ButtonIconSelect";
|
||||||
import { ColorPicker } from "../components/ColorPicker/ColorPicker";
|
import { ColorPicker } from "../components/ColorPicker/ColorPicker";
|
||||||
|
@ -135,7 +137,6 @@ import { register } from "./register";
|
||||||
|
|
||||||
import type { CaptureUpdateActionType } from "../store";
|
import type { CaptureUpdateActionType } from "../store";
|
||||||
import type { AppClassProperties, AppState, Primitive } from "../types";
|
import type { AppClassProperties, AppState, Primitive } from "../types";
|
||||||
import type Scene from "../scene/Scene";
|
|
||||||
|
|
||||||
const FONT_SIZE_RELATIVE_INCREASE_STEP = 0.1;
|
const FONT_SIZE_RELATIVE_INCREASE_STEP = 0.1;
|
||||||
|
|
||||||
|
@ -246,8 +247,7 @@ const changeFontSize = (
|
||||||
redrawTextBoundingBox(
|
redrawTextBoundingBox(
|
||||||
newElement,
|
newElement,
|
||||||
app.scene.getContainerElement(oldElement),
|
app.scene.getContainerElement(oldElement),
|
||||||
app.scene.getNonDeletedElementsMap(),
|
app.scene,
|
||||||
(...args) => app.scene.mutate(...args),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
newElement = offsetElementAfterFontResize(
|
newElement = offsetElementAfterFontResize(
|
||||||
|
@ -264,12 +264,11 @@ const changeFontSize = (
|
||||||
);
|
);
|
||||||
|
|
||||||
// Update arrow elements after text elements have been updated
|
// Update arrow elements after text elements have been updated
|
||||||
const updatedElementsMap = arrayToMap(updatedElements);
|
|
||||||
getSelectedElements(elements, appState, {
|
getSelectedElements(elements, appState, {
|
||||||
includeBoundTextElement: true,
|
includeBoundTextElement: true,
|
||||||
}).forEach((element) => {
|
}).forEach((element) => {
|
||||||
if (isTextElement(element)) {
|
if (isTextElement(element)) {
|
||||||
updateBoundElements(element, updatedElementsMap);
|
updateBoundElements(element, app.scene);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -947,12 +946,7 @@ export const actionChangeFontFamily = register({
|
||||||
// we either skip the check (have at least one font face loaded) or do the check and find out all the font faces have loaded
|
// we either skip the check (have at least one font face loaded) or do the check and find out all the font faces have loaded
|
||||||
for (const [element, container] of elementContainerMapping) {
|
for (const [element, container] of elementContainerMapping) {
|
||||||
// trigger synchronous redraw
|
// trigger synchronous redraw
|
||||||
redrawTextBoundingBox(
|
redrawTextBoundingBox(element, container, app.scene);
|
||||||
element,
|
|
||||||
container,
|
|
||||||
app.scene.getNonDeletedElementsMap(),
|
|
||||||
(...args) => app.scene.mutate(...args),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// otherwise try to load all font faces for the given chars and redraw elements once our font faces loaded
|
// otherwise try to load all font faces for the given chars and redraw elements once our font faces loaded
|
||||||
|
@ -969,8 +963,7 @@ export const actionChangeFontFamily = register({
|
||||||
redrawTextBoundingBox(
|
redrawTextBoundingBox(
|
||||||
latestElement as ExcalidrawTextElement,
|
latestElement as ExcalidrawTextElement,
|
||||||
latestContainer,
|
latestContainer,
|
||||||
app.scene.getNonDeletedElementsMap(),
|
app.scene,
|
||||||
(...args) => app.scene.mutate(...args),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1176,8 +1169,7 @@ export const actionChangeTextAlign = register({
|
||||||
redrawTextBoundingBox(
|
redrawTextBoundingBox(
|
||||||
newElement,
|
newElement,
|
||||||
app.scene.getContainerElement(oldElement),
|
app.scene.getContainerElement(oldElement),
|
||||||
app.scene.getNonDeletedElementsMap(),
|
app.scene,
|
||||||
(...args) => app.scene.mutate(...args),
|
|
||||||
);
|
);
|
||||||
return newElement;
|
return newElement;
|
||||||
}
|
}
|
||||||
|
@ -1268,8 +1260,7 @@ export const actionChangeVerticalAlign = register({
|
||||||
redrawTextBoundingBox(
|
redrawTextBoundingBox(
|
||||||
newElement,
|
newElement,
|
||||||
app.scene.getContainerElement(oldElement),
|
app.scene.getContainerElement(oldElement),
|
||||||
app.scene.getNonDeletedElementsMap(),
|
app.scene,
|
||||||
(...args) => app.scene.mutate(...args),
|
|
||||||
);
|
);
|
||||||
return newElement;
|
return newElement;
|
||||||
}
|
}
|
||||||
|
@ -1669,17 +1660,10 @@ export const actionChangeArrowType = register({
|
||||||
newElement,
|
newElement,
|
||||||
startHoveredElement,
|
startHoveredElement,
|
||||||
"start",
|
"start",
|
||||||
elementsMap,
|
app.scene,
|
||||||
(...args) => app.scene.mutate(...args),
|
|
||||||
);
|
);
|
||||||
endHoveredElement &&
|
endHoveredElement &&
|
||||||
bindLinearElement(
|
bindLinearElement(newElement, endHoveredElement, "end", app.scene);
|
||||||
newElement,
|
|
||||||
endHoveredElement,
|
|
||||||
"end",
|
|
||||||
elementsMap,
|
|
||||||
(...args) => app.scene.mutate(...args),
|
|
||||||
);
|
|
||||||
|
|
||||||
const startBinding =
|
const startBinding =
|
||||||
startElement && newElement.startBinding
|
startElement && newElement.startBinding
|
||||||
|
@ -1733,13 +1717,7 @@ export const actionChangeArrowType = register({
|
||||||
newElement.startBinding.elementId,
|
newElement.startBinding.elementId,
|
||||||
) as ExcalidrawBindableElement;
|
) as ExcalidrawBindableElement;
|
||||||
if (startElement) {
|
if (startElement) {
|
||||||
bindLinearElement(
|
bindLinearElement(newElement, startElement, "start", app.scene);
|
||||||
newElement,
|
|
||||||
startElement,
|
|
||||||
"start",
|
|
||||||
elementsMap,
|
|
||||||
(...args) => app.scene.mutate(...args),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (newElement.endBinding) {
|
if (newElement.endBinding) {
|
||||||
|
@ -1747,13 +1725,7 @@ export const actionChangeArrowType = register({
|
||||||
newElement.endBinding.elementId,
|
newElement.endBinding.elementId,
|
||||||
) as ExcalidrawBindableElement;
|
) as ExcalidrawBindableElement;
|
||||||
if (endElement) {
|
if (endElement) {
|
||||||
bindLinearElement(
|
bindLinearElement(newElement, endElement, "end", app.scene);
|
||||||
newElement,
|
|
||||||
endElement,
|
|
||||||
"end",
|
|
||||||
elementsMap,
|
|
||||||
(...args) => app.scene.mutate(...args),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,12 +139,8 @@ export const actionPasteStyles = register({
|
||||||
element.id === newElement.containerId,
|
element.id === newElement.containerId,
|
||||||
) || null;
|
) || null;
|
||||||
}
|
}
|
||||||
redrawTextBoundingBox(
|
|
||||||
newElement,
|
redrawTextBoundingBox(newElement, container, app.scene);
|
||||||
container,
|
|
||||||
app.scene.getNonDeletedElementsMap(),
|
|
||||||
(...args) => app.scene.mutate(...args),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -16,7 +16,6 @@ import {
|
||||||
import { LinearElementEditor } from "@excalidraw/element/linearElementEditor";
|
import { LinearElementEditor } from "@excalidraw/element/linearElementEditor";
|
||||||
import {
|
import {
|
||||||
mutateElement,
|
mutateElement,
|
||||||
mutateElementWith,
|
|
||||||
newElementWith,
|
newElementWith,
|
||||||
} from "@excalidraw/element/mutateElement";
|
} from "@excalidraw/element/mutateElement";
|
||||||
import {
|
import {
|
||||||
|
@ -38,6 +37,8 @@ import {
|
||||||
syncMovedIndices,
|
syncMovedIndices,
|
||||||
} from "@excalidraw/element/fractionalIndex";
|
} from "@excalidraw/element/fractionalIndex";
|
||||||
|
|
||||||
|
import Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import type { BindableProp, BindingProp } from "@excalidraw/element/binding";
|
import type { BindableProp, BindingProp } from "@excalidraw/element/binding";
|
||||||
|
|
||||||
import type { ElementUpdate } from "@excalidraw/element/mutateElement";
|
import type { ElementUpdate } from "@excalidraw/element/mutateElement";
|
||||||
|
@ -1135,8 +1136,13 @@ export class ElementsChange implements Change<SceneElementsMap> {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// we don't have an up-to-date scene, as we can be just in the middle of applying history entry
|
||||||
|
// we also don't have a scene on the server
|
||||||
|
// so we are creating a temp scene just to query and mutate elements
|
||||||
|
const tempScene = new Scene(nextElements);
|
||||||
|
|
||||||
// TODO: #7348 refactor away mutations below, so that we couldn't end up in an incosistent state
|
// TODO: #7348 refactor away mutations below, so that we couldn't end up in an incosistent state
|
||||||
ElementsChange.redrawTextBoundingBoxes(nextElements, changedElements);
|
ElementsChange.redrawTextBoundingBoxes(tempScene, changedElements);
|
||||||
|
|
||||||
// the following reorder performs also mutations, but only on new instances of changed elements
|
// the following reorder performs also mutations, but only on new instances of changed elements
|
||||||
// (unless something goes really bad and it fallbacks to fixing all invalid indices)
|
// (unless something goes really bad and it fallbacks to fixing all invalid indices)
|
||||||
|
@ -1147,7 +1153,7 @@ export class ElementsChange implements Change<SceneElementsMap> {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Need ordered nextElements to avoid z-index binding issues
|
// Need ordered nextElements to avoid z-index binding issues
|
||||||
ElementsChange.redrawBoundArrows(nextElements, changedElements);
|
ElementsChange.redrawBoundArrows(tempScene, changedElements);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(
|
console.error(
|
||||||
`Couldn't mutate elements after applying elements change`,
|
`Couldn't mutate elements after applying elements change`,
|
||||||
|
@ -1459,9 +1465,10 @@ export class ElementsChange implements Change<SceneElementsMap> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static redrawTextBoundingBoxes(
|
private static redrawTextBoundingBoxes(
|
||||||
elements: SceneElementsMap,
|
scene: Scene,
|
||||||
changed: Map<string, OrderedExcalidrawElement>,
|
changed: Map<string, OrderedExcalidrawElement>,
|
||||||
) {
|
) {
|
||||||
|
const elements = scene.getNonDeletedElementsMap();
|
||||||
const boxesToRedraw = new Map<
|
const boxesToRedraw = new Map<
|
||||||
string,
|
string,
|
||||||
{ container: OrderedExcalidrawElement; boundText: ExcalidrawTextElement }
|
{ container: OrderedExcalidrawElement; boundText: ExcalidrawTextElement }
|
||||||
|
@ -1501,22 +1508,17 @@ export class ElementsChange implements Change<SceneElementsMap> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
redrawTextBoundingBox(
|
redrawTextBoundingBox(boundText, container, scene);
|
||||||
boundText,
|
|
||||||
container,
|
|
||||||
elements,
|
|
||||||
(element, updates) => mutateElementWith(element, elements, updates),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static redrawBoundArrows(
|
private static redrawBoundArrows(
|
||||||
elements: SceneElementsMap,
|
scene: Scene,
|
||||||
changed: Map<string, OrderedExcalidrawElement>,
|
changed: Map<string, OrderedExcalidrawElement>,
|
||||||
) {
|
) {
|
||||||
for (const element of changed.values()) {
|
for (const element of changed.values()) {
|
||||||
if (!element.isDeleted && isBindableElement(element)) {
|
if (!element.isDeleted && isBindableElement(element)) {
|
||||||
updateBoundElements(element, elements, {
|
updateBoundElements(element, scene, {
|
||||||
changedElements: changed,
|
changedElements: changed,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -299,6 +299,8 @@ import {
|
||||||
|
|
||||||
import { isNonDeletedElement } from "@excalidraw/element";
|
import { isNonDeletedElement } from "@excalidraw/element";
|
||||||
|
|
||||||
|
import Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import type { LocalPoint, Radians } from "@excalidraw/math";
|
import type { LocalPoint, Radians } from "@excalidraw/math";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
|
@ -400,7 +402,6 @@ import {
|
||||||
hasBackground,
|
hasBackground,
|
||||||
isSomeElementSelected,
|
isSomeElementSelected,
|
||||||
} from "../scene";
|
} from "../scene";
|
||||||
import Scene from "../scene/Scene";
|
|
||||||
import { getStateForZoom } from "../scene/zoom";
|
import { getStateForZoom } from "../scene/zoom";
|
||||||
import {
|
import {
|
||||||
dataURLToFile,
|
dataURLToFile,
|
||||||
|
@ -3332,12 +3333,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
newElement,
|
newElement,
|
||||||
this.scene.getElementsMapIncludingDeleted(),
|
this.scene.getElementsMapIncludingDeleted(),
|
||||||
);
|
);
|
||||||
redrawTextBoundingBox(
|
redrawTextBoundingBox(newElement, container, this.scene);
|
||||||
newElement,
|
|
||||||
container,
|
|
||||||
this.scene.getElementsMapIncludingDeleted(),
|
|
||||||
(...args) => this.scene.mutate(...args),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4439,7 +4435,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
{ informMutation: false },
|
{ informMutation: false },
|
||||||
);
|
);
|
||||||
|
|
||||||
updateBoundElements(element, this.scene.getNonDeletedElementsMap(), {
|
updateBoundElements(element, this.scene, {
|
||||||
simultaneouslyUpdated: selectedElements,
|
simultaneouslyUpdated: selectedElements,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -4976,7 +4972,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
onChange: withBatchedUpdates((nextOriginalText) => {
|
onChange: withBatchedUpdates((nextOriginalText) => {
|
||||||
updateElement(nextOriginalText, false);
|
updateElement(nextOriginalText, false);
|
||||||
if (isNonDeletedElement(element)) {
|
if (isNonDeletedElement(element)) {
|
||||||
updateBoundElements(element, this.scene.getNonDeletedElementsMap());
|
updateBoundElements(element, this.scene);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
onSubmit: withBatchedUpdates(({ viaKeyboard, nextOriginalText }) => {
|
onSubmit: withBatchedUpdates(({ viaKeyboard, nextOriginalText }) => {
|
||||||
|
@ -5883,7 +5879,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
scenePointerX,
|
scenePointerX,
|
||||||
scenePointerY,
|
scenePointerY,
|
||||||
this,
|
this,
|
||||||
this.scene.getNonDeletedElementsMap(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -10762,16 +10757,12 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
updateBoundElements(
|
updateBoundElements(croppingElement, this.scene, {
|
||||||
croppingElement,
|
|
||||||
this.scene.getNonDeletedElementsMap(),
|
|
||||||
{
|
|
||||||
newSize: {
|
newSize: {
|
||||||
width: croppingElement.width,
|
width: croppingElement.width,
|
||||||
height: croppingElement.height,
|
height: croppingElement.height,
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
isCropping: transformHandleType && transformHandleType !== "rotation",
|
isCropping: transformHandleType && transformHandleType !== "rotation",
|
||||||
|
|
|
@ -7,13 +7,14 @@ import type { Degrees } from "@excalidraw/math";
|
||||||
|
|
||||||
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
||||||
|
|
||||||
|
import type Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import { angleIcon } from "../icons";
|
import { angleIcon } from "../icons";
|
||||||
|
|
||||||
import DragInput from "./DragInput";
|
import DragInput from "./DragInput";
|
||||||
import { getStepSizedValue, isPropertyEditable, updateBindings } from "./utils";
|
import { getStepSizedValue, isPropertyEditable, updateBindings } from "./utils";
|
||||||
|
|
||||||
import type { DragInputCallbackType } from "./DragInput";
|
import type { DragInputCallbackType } from "./DragInput";
|
||||||
import type Scene from "../../scene/Scene";
|
|
||||||
import type { AppState } from "../../types";
|
import type { AppState } from "../../types";
|
||||||
|
|
||||||
interface AngleProps {
|
interface AngleProps {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
import type Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import { getNormalizedGridStep } from "../../scene";
|
import { getNormalizedGridStep } from "../../scene";
|
||||||
|
|
||||||
import StatsDragInput from "./DragInput";
|
import StatsDragInput from "./DragInput";
|
||||||
import { getStepSizedValue } from "./utils";
|
import { getStepSizedValue } from "./utils";
|
||||||
|
|
||||||
import type Scene from "../../scene/Scene";
|
|
||||||
import type { AppState } from "../../types";
|
import type { AppState } from "../../types";
|
||||||
|
|
||||||
interface PositionProps {
|
interface PositionProps {
|
||||||
|
|
|
@ -10,11 +10,12 @@ import { isImageElement } from "@excalidraw/element/typeChecks";
|
||||||
|
|
||||||
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
||||||
|
|
||||||
|
import type Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import DragInput from "./DragInput";
|
import DragInput from "./DragInput";
|
||||||
import { getStepSizedValue, isPropertyEditable } from "./utils";
|
import { getStepSizedValue, isPropertyEditable } from "./utils";
|
||||||
|
|
||||||
import type { DragInputCallbackType } from "./DragInput";
|
import type { DragInputCallbackType } from "./DragInput";
|
||||||
import type Scene from "../../scene/Scene";
|
|
||||||
import type { AppState } from "../../types";
|
import type { AppState } from "../../types";
|
||||||
|
|
||||||
interface DimensionDragInputProps {
|
interface DimensionDragInputProps {
|
||||||
|
|
|
@ -7,6 +7,8 @@ import { deepCopyElement } from "@excalidraw/element/duplicate";
|
||||||
|
|
||||||
import type { ElementsMap, ExcalidrawElement } from "@excalidraw/element/types";
|
import type { ElementsMap, ExcalidrawElement } from "@excalidraw/element/types";
|
||||||
|
|
||||||
|
import type Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import { CaptureUpdateAction } from "../../store";
|
import { CaptureUpdateAction } from "../../store";
|
||||||
import { useApp } from "../App";
|
import { useApp } from "../App";
|
||||||
import { InlineIcon } from "../InlineIcon";
|
import { InlineIcon } from "../InlineIcon";
|
||||||
|
@ -16,7 +18,6 @@ import { SMALLEST_DELTA } from "./utils";
|
||||||
import "./DragInput.scss";
|
import "./DragInput.scss";
|
||||||
|
|
||||||
import type { StatsInputProperty } from "./utils";
|
import type { StatsInputProperty } from "./utils";
|
||||||
import type Scene from "../../scene/Scene";
|
|
||||||
import type { AppState } from "../../types";
|
import type { AppState } from "../../types";
|
||||||
|
|
||||||
export type DragInputCallbackType<
|
export type DragInputCallbackType<
|
||||||
|
|
|
@ -13,13 +13,14 @@ import type {
|
||||||
ExcalidrawTextElement,
|
ExcalidrawTextElement,
|
||||||
} from "@excalidraw/element/types";
|
} from "@excalidraw/element/types";
|
||||||
|
|
||||||
|
import type Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import { fontSizeIcon } from "../icons";
|
import { fontSizeIcon } from "../icons";
|
||||||
|
|
||||||
import StatsDragInput from "./DragInput";
|
import StatsDragInput from "./DragInput";
|
||||||
import { getStepSizedValue } from "./utils";
|
import { getStepSizedValue } from "./utils";
|
||||||
|
|
||||||
import type { DragInputCallbackType } from "./DragInput";
|
import type { DragInputCallbackType } from "./DragInput";
|
||||||
import type Scene from "../../scene/Scene";
|
|
||||||
import type { AppState } from "../../types";
|
import type { AppState } from "../../types";
|
||||||
|
|
||||||
interface FontSizeProps {
|
interface FontSizeProps {
|
||||||
|
@ -74,8 +75,7 @@ const handleFontSizeChange: DragInputCallbackType<
|
||||||
redrawTextBoundingBox(
|
redrawTextBoundingBox(
|
||||||
latestElement,
|
latestElement,
|
||||||
scene.getContainerElement(latestElement),
|
scene.getContainerElement(latestElement),
|
||||||
scene.getNonDeletedElementsMap(),
|
scene,
|
||||||
(...args) => scene.mutate(...args),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,13 +11,14 @@ import type { Degrees } from "@excalidraw/math";
|
||||||
|
|
||||||
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
||||||
|
|
||||||
|
import type Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import { angleIcon } from "../icons";
|
import { angleIcon } from "../icons";
|
||||||
|
|
||||||
import DragInput from "./DragInput";
|
import DragInput from "./DragInput";
|
||||||
import { getStepSizedValue, isPropertyEditable } from "./utils";
|
import { getStepSizedValue, isPropertyEditable } from "./utils";
|
||||||
|
|
||||||
import type { DragInputCallbackType } from "./DragInput";
|
import type { DragInputCallbackType } from "./DragInput";
|
||||||
import type Scene from "../../scene/Scene";
|
|
||||||
import type { AppState } from "../../types";
|
import type { AppState } from "../../types";
|
||||||
|
|
||||||
interface MultiAngleProps {
|
interface MultiAngleProps {
|
||||||
|
|
|
@ -16,24 +16,20 @@ import { isTextElement } from "@excalidraw/element/typeChecks";
|
||||||
|
|
||||||
import { getCommonBounds } from "@excalidraw/utils";
|
import { getCommonBounds } from "@excalidraw/utils";
|
||||||
|
|
||||||
import {
|
|
||||||
mutateElement,
|
|
||||||
mutateElementWith,
|
|
||||||
} from "@excalidraw/element/mutateElement";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ElementsMap,
|
ElementsMap,
|
||||||
ExcalidrawElement,
|
ExcalidrawElement,
|
||||||
NonDeletedSceneElementsMap,
|
NonDeletedSceneElementsMap,
|
||||||
} from "@excalidraw/element/types";
|
} from "@excalidraw/element/types";
|
||||||
|
|
||||||
|
import type Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import DragInput from "./DragInput";
|
import DragInput from "./DragInput";
|
||||||
import { getAtomicUnits, getStepSizedValue, isPropertyEditable } from "./utils";
|
import { getAtomicUnits, getStepSizedValue, isPropertyEditable } from "./utils";
|
||||||
import { getElementsInAtomicUnit } from "./utils";
|
import { getElementsInAtomicUnit } from "./utils";
|
||||||
|
|
||||||
import type { DragInputCallbackType } from "./DragInput";
|
import type { DragInputCallbackType } from "./DragInput";
|
||||||
import type { AtomicUnit } from "./utils";
|
import type { AtomicUnit } from "./utils";
|
||||||
import type Scene from "../../scene/Scene";
|
|
||||||
import type { AppState } from "../../types";
|
import type { AppState } from "../../types";
|
||||||
|
|
||||||
interface MultiDimensionProps {
|
interface MultiDimensionProps {
|
||||||
|
@ -79,12 +75,13 @@ const resizeElementInGroup = (
|
||||||
scale: number,
|
scale: number,
|
||||||
latestElement: ExcalidrawElement,
|
latestElement: ExcalidrawElement,
|
||||||
origElement: ExcalidrawElement,
|
origElement: ExcalidrawElement,
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
|
||||||
originalElementsMap: ElementsMap,
|
originalElementsMap: ElementsMap,
|
||||||
|
scene: Scene,
|
||||||
) => {
|
) => {
|
||||||
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
const updates = getResizedUpdates(anchorX, anchorY, scale, origElement);
|
const updates = getResizedUpdates(anchorX, anchorY, scale, origElement);
|
||||||
|
|
||||||
mutateElementWith(latestElement, elementsMap, updates);
|
scene.mutate(latestElement, updates);
|
||||||
|
|
||||||
const boundTextElement = getBoundTextElement(
|
const boundTextElement = getBoundTextElement(
|
||||||
origElement,
|
origElement,
|
||||||
|
@ -92,12 +89,12 @@ const resizeElementInGroup = (
|
||||||
);
|
);
|
||||||
if (boundTextElement) {
|
if (boundTextElement) {
|
||||||
const newFontSize = boundTextElement.fontSize * scale;
|
const newFontSize = boundTextElement.fontSize * scale;
|
||||||
updateBoundElements(latestElement, elementsMap, {
|
updateBoundElements(latestElement, scene, {
|
||||||
newSize: { width: updates.width, height: updates.height },
|
newSize: { width: updates.width, height: updates.height },
|
||||||
});
|
});
|
||||||
const latestBoundTextElement = elementsMap.get(boundTextElement.id);
|
const latestBoundTextElement = elementsMap.get(boundTextElement.id);
|
||||||
if (latestBoundTextElement && isTextElement(latestBoundTextElement)) {
|
if (latestBoundTextElement && isTextElement(latestBoundTextElement)) {
|
||||||
mutateElement(latestBoundTextElement, {
|
scene.mutate(latestBoundTextElement, {
|
||||||
fontSize: newFontSize,
|
fontSize: newFontSize,
|
||||||
});
|
});
|
||||||
handleBindTextResize(
|
handleBindTextResize(
|
||||||
|
@ -119,8 +116,8 @@ const resizeGroup = (
|
||||||
property: MultiDimensionProps["property"],
|
property: MultiDimensionProps["property"],
|
||||||
latestElements: ExcalidrawElement[],
|
latestElements: ExcalidrawElement[],
|
||||||
originalElements: ExcalidrawElement[],
|
originalElements: ExcalidrawElement[],
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
|
||||||
originalElementsMap: ElementsMap,
|
originalElementsMap: ElementsMap,
|
||||||
|
scene: Scene,
|
||||||
) => {
|
) => {
|
||||||
// keep aspect ratio for groups
|
// keep aspect ratio for groups
|
||||||
if (property === "width") {
|
if (property === "width") {
|
||||||
|
@ -142,8 +139,8 @@ const resizeGroup = (
|
||||||
scale,
|
scale,
|
||||||
latestElement,
|
latestElement,
|
||||||
origElement,
|
origElement,
|
||||||
elementsMap,
|
|
||||||
originalElementsMap,
|
originalElementsMap,
|
||||||
|
scene,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -195,8 +192,8 @@ const handleDimensionChange: DragInputCallbackType<
|
||||||
property,
|
property,
|
||||||
latestElements,
|
latestElements,
|
||||||
originalElements,
|
originalElements,
|
||||||
elementsMap,
|
|
||||||
originalElementsMap,
|
originalElementsMap,
|
||||||
|
scene,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const [el] = elementsInUnit;
|
const [el] = elementsInUnit;
|
||||||
|
@ -302,8 +299,8 @@ const handleDimensionChange: DragInputCallbackType<
|
||||||
property,
|
property,
|
||||||
latestElements,
|
latestElements,
|
||||||
originalElements,
|
originalElements,
|
||||||
elementsMap,
|
|
||||||
originalElementsMap,
|
originalElementsMap,
|
||||||
|
scene,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const [el] = elementsInUnit;
|
const [el] = elementsInUnit;
|
||||||
|
|
|
@ -16,13 +16,14 @@ import type {
|
||||||
NonDeletedSceneElementsMap,
|
NonDeletedSceneElementsMap,
|
||||||
} from "@excalidraw/element/types";
|
} from "@excalidraw/element/types";
|
||||||
|
|
||||||
|
import type Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import { fontSizeIcon } from "../icons";
|
import { fontSizeIcon } from "../icons";
|
||||||
|
|
||||||
import StatsDragInput from "./DragInput";
|
import StatsDragInput from "./DragInput";
|
||||||
import { getStepSizedValue } from "./utils";
|
import { getStepSizedValue } from "./utils";
|
||||||
|
|
||||||
import type { DragInputCallbackType } from "./DragInput";
|
import type { DragInputCallbackType } from "./DragInput";
|
||||||
import type Scene from "../../scene/Scene";
|
|
||||||
import type { AppState } from "../../types";
|
import type { AppState } from "../../types";
|
||||||
|
|
||||||
interface MultiFontSizeProps {
|
interface MultiFontSizeProps {
|
||||||
|
@ -91,8 +92,7 @@ const handleFontSizeChange: DragInputCallbackType<
|
||||||
redrawTextBoundingBox(
|
redrawTextBoundingBox(
|
||||||
textElement,
|
textElement,
|
||||||
scene.getContainerElement(textElement),
|
scene.getContainerElement(textElement),
|
||||||
elementsMap,
|
scene,
|
||||||
(...args) => scene.mutate(...args),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,8 +120,7 @@ const handleFontSizeChange: DragInputCallbackType<
|
||||||
redrawTextBoundingBox(
|
redrawTextBoundingBox(
|
||||||
latestElement,
|
latestElement,
|
||||||
scene.getContainerElement(latestElement),
|
scene.getContainerElement(latestElement),
|
||||||
elementsMap,
|
scene,
|
||||||
(...args) => scene.mutate(...args),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,14 @@ import { getCommonBounds } from "@excalidraw/element/bounds";
|
||||||
|
|
||||||
import type { ElementsMap, ExcalidrawElement } from "@excalidraw/element/types";
|
import type { ElementsMap, ExcalidrawElement } from "@excalidraw/element/types";
|
||||||
|
|
||||||
|
import type Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import StatsDragInput from "./DragInput";
|
import StatsDragInput from "./DragInput";
|
||||||
import { getAtomicUnits, getStepSizedValue, isPropertyEditable } from "./utils";
|
import { getAtomicUnits, getStepSizedValue, isPropertyEditable } from "./utils";
|
||||||
import { getElementsInAtomicUnit, moveElement } from "./utils";
|
import { getElementsInAtomicUnit, moveElement } from "./utils";
|
||||||
|
|
||||||
import type { DragInputCallbackType } from "./DragInput";
|
import type { DragInputCallbackType } from "./DragInput";
|
||||||
import type { AtomicUnit } from "./utils";
|
import type { AtomicUnit } from "./utils";
|
||||||
import type Scene from "../../scene/Scene";
|
|
||||||
import type { AppState } from "../../types";
|
import type { AppState } from "../../types";
|
||||||
|
|
||||||
interface MultiPositionProps {
|
interface MultiPositionProps {
|
||||||
|
|
|
@ -9,11 +9,12 @@ import { isImageElement } from "@excalidraw/element/typeChecks";
|
||||||
|
|
||||||
import type { ElementsMap, ExcalidrawElement } from "@excalidraw/element/types";
|
import type { ElementsMap, ExcalidrawElement } from "@excalidraw/element/types";
|
||||||
|
|
||||||
|
import type Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import StatsDragInput from "./DragInput";
|
import StatsDragInput from "./DragInput";
|
||||||
import { getStepSizedValue, moveElement } from "./utils";
|
import { getStepSizedValue, moveElement } from "./utils";
|
||||||
|
|
||||||
import type { DragInputCallbackType } from "./DragInput";
|
import type { DragInputCallbackType } from "./DragInput";
|
||||||
import type Scene from "../../scene/Scene";
|
|
||||||
import type { AppState } from "../../types";
|
import type { AppState } from "../../types";
|
||||||
|
|
||||||
interface PositionProps {
|
interface PositionProps {
|
||||||
|
|
|
@ -25,7 +25,8 @@ import type {
|
||||||
NonDeletedExcalidrawElement,
|
NonDeletedExcalidrawElement,
|
||||||
} from "@excalidraw/element/types";
|
} from "@excalidraw/element/types";
|
||||||
|
|
||||||
import type Scene from "../../scene/Scene";
|
import type Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import type { AppState } from "../../types";
|
import type { AppState } from "../../types";
|
||||||
|
|
||||||
export type StatsInputProperty =
|
export type StatsInputProperty =
|
||||||
|
@ -206,10 +207,6 @@ export const updateBindings = (
|
||||||
if (isLinearElement(latestElement)) {
|
if (isLinearElement(latestElement)) {
|
||||||
bindOrUnbindLinearElements([latestElement], true, [], scene, options?.zoom);
|
bindOrUnbindLinearElements([latestElement], true, [], scene, options?.zoom);
|
||||||
} else {
|
} else {
|
||||||
updateBoundElements(
|
updateBoundElements(latestElement, scene, options);
|
||||||
latestElement,
|
|
||||||
scene.getNonDeletedElementsMap(),
|
|
||||||
options,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,14 +38,13 @@ import { redrawTextBoundingBox } from "@excalidraw/element/textElement";
|
||||||
|
|
||||||
import { LinearElementEditor } from "@excalidraw/element/linearElementEditor";
|
import { LinearElementEditor } from "@excalidraw/element/linearElementEditor";
|
||||||
|
|
||||||
import { mutateElementWith } from "@excalidraw/element/mutateElement";
|
|
||||||
|
|
||||||
import { getCommonBounds } from "@excalidraw/element/bounds";
|
import { getCommonBounds } from "@excalidraw/element/bounds";
|
||||||
|
|
||||||
|
import Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import type { ElementConstructorOpts } from "@excalidraw/element/newElement";
|
import type { ElementConstructorOpts } from "@excalidraw/element/newElement";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ElementsMap,
|
|
||||||
ExcalidrawArrowElement,
|
ExcalidrawArrowElement,
|
||||||
ExcalidrawBindableElement,
|
ExcalidrawBindableElement,
|
||||||
ExcalidrawElement,
|
ExcalidrawElement,
|
||||||
|
@ -223,7 +222,7 @@ const DEFAULT_DIMENSION = 100;
|
||||||
const bindTextToContainer = (
|
const bindTextToContainer = (
|
||||||
container: ExcalidrawElement,
|
container: ExcalidrawElement,
|
||||||
textProps: { text: string } & MarkOptional<ElementConstructorOpts, "x" | "y">,
|
textProps: { text: string } & MarkOptional<ElementConstructorOpts, "x" | "y">,
|
||||||
elementsMap: ElementsMap,
|
scene: Scene,
|
||||||
) => {
|
) => {
|
||||||
const textElement: ExcalidrawTextElement = newTextElement({
|
const textElement: ExcalidrawTextElement = newTextElement({
|
||||||
x: 0,
|
x: 0,
|
||||||
|
@ -242,12 +241,8 @@ const bindTextToContainer = (
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
redrawTextBoundingBox(
|
redrawTextBoundingBox(textElement, container, scene);
|
||||||
textElement,
|
|
||||||
container,
|
|
||||||
elementsMap,
|
|
||||||
(element, updates) => mutateElementWith(element, elementsMap, updates),
|
|
||||||
);
|
|
||||||
return [container, textElement] as const;
|
return [container, textElement] as const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -256,7 +251,7 @@ const bindLinearElementToElement = (
|
||||||
start: ValidLinearElement["start"],
|
start: ValidLinearElement["start"],
|
||||||
end: ValidLinearElement["end"],
|
end: ValidLinearElement["end"],
|
||||||
elementStore: ElementStore,
|
elementStore: ElementStore,
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
scene: Scene,
|
||||||
): {
|
): {
|
||||||
linearElement: ExcalidrawLinearElement;
|
linearElement: ExcalidrawLinearElement;
|
||||||
startBoundElement?: ExcalidrawElement;
|
startBoundElement?: ExcalidrawElement;
|
||||||
|
@ -342,8 +337,7 @@ const bindLinearElementToElement = (
|
||||||
linearElement,
|
linearElement,
|
||||||
startBoundElement as ExcalidrawBindableElement,
|
startBoundElement as ExcalidrawBindableElement,
|
||||||
"start",
|
"start",
|
||||||
elementsMap,
|
scene,
|
||||||
(element, updates) => mutateElementWith(element, elementsMap, updates),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -418,8 +412,7 @@ const bindLinearElementToElement = (
|
||||||
linearElement,
|
linearElement,
|
||||||
endBoundElement as ExcalidrawBindableElement,
|
endBoundElement as ExcalidrawBindableElement,
|
||||||
"end",
|
"end",
|
||||||
elementsMap,
|
scene,
|
||||||
(element, updates) => mutateElementWith(element, elementsMap, updates),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -660,6 +653,9 @@ export const convertToExcalidrawElements = (
|
||||||
}
|
}
|
||||||
|
|
||||||
const elementsMap = elementStore.getElementsMap();
|
const elementsMap = elementStore.getElementsMap();
|
||||||
|
// we don't have a real scene, so we just use a temp scene to query and mutate elements
|
||||||
|
const scene = new Scene(elementsMap);
|
||||||
|
|
||||||
// Add labels and arrow bindings
|
// Add labels and arrow bindings
|
||||||
for (const [id, element] of elementsWithIds) {
|
for (const [id, element] of elementsWithIds) {
|
||||||
const excalidrawElement = elementStore.getElement(id)!;
|
const excalidrawElement = elementStore.getElement(id)!;
|
||||||
|
@ -673,7 +669,7 @@ export const convertToExcalidrawElements = (
|
||||||
let [container, text] = bindTextToContainer(
|
let [container, text] = bindTextToContainer(
|
||||||
excalidrawElement,
|
excalidrawElement,
|
||||||
element?.label,
|
element?.label,
|
||||||
elementsMap,
|
scene,
|
||||||
);
|
);
|
||||||
elementStore.add(container);
|
elementStore.add(container);
|
||||||
elementStore.add(text);
|
elementStore.add(text);
|
||||||
|
@ -701,7 +697,7 @@ export const convertToExcalidrawElements = (
|
||||||
originalStart,
|
originalStart,
|
||||||
originalEnd,
|
originalEnd,
|
||||||
elementStore,
|
elementStore,
|
||||||
elementsMap,
|
scene,
|
||||||
);
|
);
|
||||||
container = linearElement;
|
container = linearElement;
|
||||||
elementStore.add(linearElement);
|
elementStore.add(linearElement);
|
||||||
|
@ -726,7 +722,7 @@ export const convertToExcalidrawElements = (
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
elementStore,
|
elementStore,
|
||||||
elementsMap,
|
scene,
|
||||||
);
|
);
|
||||||
|
|
||||||
elementStore.add(linearElement);
|
elementStore.add(linearElement);
|
||||||
|
|
|
@ -28,6 +28,8 @@ import type {
|
||||||
|
|
||||||
import type { ValueOf } from "@excalidraw/common/utility-types";
|
import type { ValueOf } from "@excalidraw/common/utility-types";
|
||||||
|
|
||||||
|
import type Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import { CascadiaFontFaces } from "./Cascadia";
|
import { CascadiaFontFaces } from "./Cascadia";
|
||||||
import { ComicShannsFontFaces } from "./ComicShanns";
|
import { ComicShannsFontFaces } from "./ComicShanns";
|
||||||
import { EmojiFontFaces } from "./Emoji";
|
import { EmojiFontFaces } from "./Emoji";
|
||||||
|
@ -40,8 +42,6 @@ import { NunitoFontFaces } from "./Nunito";
|
||||||
import { VirgilFontFaces } from "./Virgil";
|
import { VirgilFontFaces } from "./Virgil";
|
||||||
import { XiaolaiFontFaces } from "./Xiaolai";
|
import { XiaolaiFontFaces } from "./Xiaolai";
|
||||||
|
|
||||||
import type Scene from "../scene/Scene";
|
|
||||||
|
|
||||||
export class Fonts {
|
export class Fonts {
|
||||||
// it's ok to track fonts across multiple instances only once, so let's use
|
// it's ok to track fonts across multiple instances only once, so let's use
|
||||||
// a static member to reduce memory footprint
|
// a static member to reduce memory footprint
|
||||||
|
|
|
@ -9,10 +9,11 @@ import type {
|
||||||
NonDeletedExcalidrawElement,
|
NonDeletedExcalidrawElement,
|
||||||
} from "@excalidraw/element/types";
|
} from "@excalidraw/element/types";
|
||||||
|
|
||||||
|
import type Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import { renderInteractiveSceneThrottled } from "../renderer/interactiveScene";
|
import { renderInteractiveSceneThrottled } from "../renderer/interactiveScene";
|
||||||
import { renderStaticSceneThrottled } from "../renderer/staticScene";
|
import { renderStaticSceneThrottled } from "../renderer/staticScene";
|
||||||
|
|
||||||
import type Scene from "./Scene";
|
|
||||||
import type { RenderableElementsMap } from "./types";
|
import type { RenderableElementsMap } from "./types";
|
||||||
|
|
||||||
import type { AppState } from "../types";
|
import type { AppState } from "../types";
|
||||||
|
|
|
@ -1384,7 +1384,7 @@ describe("Test Linear Elements", () => {
|
||||||
const [origStartX, origStartY] = [line.x, line.y];
|
const [origStartX, origStartY] = [line.x, line.y];
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
LinearElementEditor.movePoints(line, arrayToMap(h.elements), [
|
LinearElementEditor.movePoints(line, h.app.scene, [
|
||||||
{
|
{
|
||||||
index: 0,
|
index: 0,
|
||||||
point: pointFrom(line.points[0][0] + 10, line.points[0][1] + 10),
|
point: pointFrom(line.points[0][0] + 10, line.points[0][1] + 10),
|
||||||
|
|
|
@ -577,12 +577,8 @@ export const textWysiwyg = ({
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
redrawTextBoundingBox(
|
|
||||||
updateElement,
|
redrawTextBoundingBox(updateElement, container, app.scene);
|
||||||
container,
|
|
||||||
app.scene.getNonDeletedElementsMap(),
|
|
||||||
(...args) => app.scene.mutate(...args),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmit({
|
onSubmit({
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue