fix: Arrow overlap arrow behavior (#10732)
* fix(arrow): Overlap arrow behavior Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Lint Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * feat(editor): reduce binding gap (#10739) * feat(editor): reduce binding gap to 7px * feat(editor): reduce binding gap to 5px * feat(editor): reduce binding gap to 3px * go back to 5px * update tests * feat: Simplified update bind points Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Remove non-needed export Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix. Possessed arrows #1 Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Focus point projection stabilization Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Remove arrow stability hack Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Unbound other endpoint Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * feat(editor): visualize binding midpoints + support for simple arrows (#10611) * feat: Force exact center focus point When the projected point is close to center snap it to the exact center. Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Tests Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Snap to center around side mid point. Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * Trigger CI * fix: Midpoint outline focus point Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Tests Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Dragging existing arrow reset focus point on outline Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Tests Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * feat: Midpoint indicator Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Rotated mid points Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: No hole Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * feat: Cache hits and scene lookups Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * chore: Remove debug Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Consider hit threshold and inside override too Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Increase outline midpoint sticky distance Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Don't show midpoint indicator when no snapping is possible Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * feat: Indicate lock-in Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * chore: Remove Map caching Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: incorrect threshold Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: threshold setting Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Hit caching Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Simple arrow mid point selection inconsistency Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: cache override Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Precise know dragging with midpoint refactor Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fear: Frame support Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Crossing arrow won't trigger mid point Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Arrow creation point highlight Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Restore types & tests Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * chore: Restore restore.ts Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: restore.ts Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Elbow arrows reliably highlight center point Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Highlight point ordering Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * feat: Bind with focus point across shape Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Lint * fix: Midpoint and binding alignment Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * chore: Indicator color Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * chore: More knob tuning Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Radius Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Tests Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * simplify point indicators --------- Signed-off-by: Mark Tolmacs <mark@lazycat.hu> Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com> * fix: Tests Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Snapshots Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Target point selection Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * chore: Remove non-needed change Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * chore: Try again removing non-needed modification Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Inside-inside binding arrow endpoint drag trigger focus point editor Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Area based edge case Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Overlapping new arrow jump Signed-off-by: Mark Tolmacs <mark@lazycat.hu> --------- Signed-off-by: Mark Tolmacs <mark@lazycat.hu> Co-authored-by: David Luzar <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
@@ -43,7 +43,6 @@ export const alignElements = (
|
||||
// update bound elements
|
||||
updateBoundElements(element, scene, {
|
||||
simultaneouslyUpdated: group,
|
||||
indirectArrowUpdate: true,
|
||||
});
|
||||
return updatedEle;
|
||||
});
|
||||
|
||||
@@ -141,6 +141,7 @@ const focusPointUpdate = (
|
||||
currentBinding,
|
||||
bindableElement,
|
||||
elementsMap,
|
||||
true,
|
||||
);
|
||||
|
||||
if (newPoint) {
|
||||
|
||||
+165
-149
@@ -27,11 +27,7 @@ import type { AppState } from "@excalidraw/excalidraw/types";
|
||||
import type { MapEntry, Mutable } from "@excalidraw/common/utility-types";
|
||||
import type { Bounds } from "@excalidraw/common";
|
||||
|
||||
import {
|
||||
doBoundsIntersect,
|
||||
getCenterForBounds,
|
||||
getElementBounds,
|
||||
} from "./bounds";
|
||||
import { getCenterForBounds } from "./bounds";
|
||||
import {
|
||||
getAllHoveredElementAtPoint,
|
||||
getHoveredElementForBinding,
|
||||
@@ -116,6 +112,7 @@ export type BindingStrategy =
|
||||
*/
|
||||
export const BASE_BINDING_GAP = 5;
|
||||
export const BASE_BINDING_GAP_ELBOW = 5;
|
||||
export const BASE_ARROW_MIN_LENGTH = 10;
|
||||
export const FOCUS_POINT_SIZE = 10 / 1.5;
|
||||
|
||||
export const getBindingGap = (
|
||||
@@ -810,13 +807,23 @@ const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
|
||||
startDragged ? -1 : 0,
|
||||
elementsMap,
|
||||
);
|
||||
|
||||
const pointIsCloseToOtherElement =
|
||||
otherFocusPoint &&
|
||||
otherBindableElement &&
|
||||
hitElementItself({
|
||||
point: globalPoint,
|
||||
element: otherBindableElement,
|
||||
elementsMap,
|
||||
threshold: maxBindingDistance_simple(appState.zoom),
|
||||
overrideShouldTestInside: true,
|
||||
});
|
||||
const otherNeverOverride = opts?.newArrow
|
||||
? appState.selectedLinearElement?.initialState.arrowStartIsInside
|
||||
: otherBinding?.mode === "inside";
|
||||
const other: BindingStrategy = !otherNeverOverride
|
||||
? otherBindableElement &&
|
||||
!otherFocusPointIsInElement &&
|
||||
!pointIsCloseToOtherElement &&
|
||||
appState.selectedLinearElement?.initialState.altFocusPoint
|
||||
? {
|
||||
mode: "orbit",
|
||||
@@ -1083,7 +1090,6 @@ export const updateBoundElements = (
|
||||
options?: {
|
||||
simultaneouslyUpdated?: readonly ExcalidrawElement[];
|
||||
changedElements?: Map<string, ExcalidrawElement>;
|
||||
indirectArrowUpdate?: boolean;
|
||||
},
|
||||
) => {
|
||||
if (!isBindableElement(changedElement)) {
|
||||
@@ -1178,11 +1184,6 @@ export const updateBoundElements = (
|
||||
};
|
||||
|
||||
boundElementsVisitor(elementsMap, changedElement, visitor);
|
||||
|
||||
if (options?.indirectArrowUpdate) {
|
||||
boundElementsVisitor(elementsMap, changedElement, visitor);
|
||||
boundElementsVisitor(elementsMap, changedElement, visitor);
|
||||
}
|
||||
};
|
||||
|
||||
const updateArrowBindings = (
|
||||
@@ -1692,10 +1693,41 @@ export const snapToMid = (
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const compareElementArea = (
|
||||
a: ExcalidrawBindableElement,
|
||||
b: ExcalidrawBindableElement,
|
||||
) => b.width ** 2 + b.height ** 2 - (a.width ** 2 + a.height ** 2);
|
||||
const extractBinding = (
|
||||
arrow: ExcalidrawArrowElement,
|
||||
startOrEnd: "startBinding" | "endBinding",
|
||||
elementsMap: ElementsMap,
|
||||
) => {
|
||||
const binding = arrow[startOrEnd];
|
||||
if (!binding) {
|
||||
return {
|
||||
element: null,
|
||||
fixedPoint: null,
|
||||
focusPoint: null,
|
||||
binding,
|
||||
mode: null,
|
||||
};
|
||||
}
|
||||
|
||||
const element = elementsMap.get(
|
||||
binding.elementId,
|
||||
) as ExcalidrawBindableElement;
|
||||
|
||||
return {
|
||||
element,
|
||||
fixedPoint: binding.fixedPoint,
|
||||
focusPoint: getGlobalFixedPointForBindableElement(
|
||||
normalizeFixedPoint(binding.fixedPoint),
|
||||
element,
|
||||
elementsMap,
|
||||
),
|
||||
binding,
|
||||
mode: binding.mode,
|
||||
};
|
||||
};
|
||||
|
||||
const elementArea = (element: ExcalidrawBindableElement) =>
|
||||
element.width * element.height;
|
||||
|
||||
export const updateBoundPoint = (
|
||||
arrow: NonDeleted<ExcalidrawArrowElement>,
|
||||
@@ -1703,9 +1735,7 @@ export const updateBoundPoint = (
|
||||
binding: FixedPointBinding | null | undefined,
|
||||
bindableElement: ExcalidrawBindableElement,
|
||||
elementsMap: ElementsMap,
|
||||
opts?: {
|
||||
customIntersector?: LineSegment<GlobalPoint>;
|
||||
},
|
||||
dragging?: boolean,
|
||||
): LocalPoint | null => {
|
||||
if (
|
||||
binding == null ||
|
||||
@@ -1720,150 +1750,136 @@ export const updateBoundPoint = (
|
||||
return null;
|
||||
}
|
||||
|
||||
const global = getGlobalFixedPointForBindableElement(
|
||||
const focusPoint = getGlobalFixedPointForBindableElement(
|
||||
normalizeFixedPoint(binding.fixedPoint),
|
||||
bindableElement,
|
||||
elementsMap,
|
||||
);
|
||||
const pointIndex =
|
||||
startOrEnd === "startBinding" ? 0 : arrow.points.length - 1;
|
||||
const elbowed = isElbowArrow(arrow);
|
||||
const otherBinding =
|
||||
startOrEnd === "startBinding" ? arrow.endBinding : arrow.startBinding;
|
||||
const otherBindableElement =
|
||||
otherBinding &&
|
||||
(elementsMap.get(otherBinding.elementId)! as ExcalidrawBindableElement);
|
||||
const bounds = getElementBounds(bindableElement, elementsMap);
|
||||
const otherBounds =
|
||||
otherBindableElement && getElementBounds(otherBindableElement, elementsMap);
|
||||
const isLargerThanOther =
|
||||
otherBindableElement &&
|
||||
compareElementArea(bindableElement, otherBindableElement) <
|
||||
// if both shapes the same size, pretend the other is larger
|
||||
(startOrEnd === "endBinding" ? 1 : 0);
|
||||
const isOverlapping = otherBounds && doBoundsIntersect(bounds, otherBounds);
|
||||
|
||||
// GOAL: If the arrow becomes too short, we want to jump the arrow endpoints
|
||||
// to the exact focus points on the elements.
|
||||
// INTUITION: We're not interested in the exacts length of the arrow (which
|
||||
// will change if we change where we route it), we want to know the length of
|
||||
// the part which lies outside of both shapes and consider that as a trigger
|
||||
// to change where we point the arrow. Avoids jumping the arrow in and out
|
||||
// at every frame.
|
||||
let arrowTooShort = false;
|
||||
if (
|
||||
!isOverlapping &&
|
||||
!elbowed &&
|
||||
arrow.startBinding &&
|
||||
arrow.endBinding &&
|
||||
otherBindableElement &&
|
||||
arrow.points.length === 2
|
||||
) {
|
||||
const startFocusPoint = getGlobalFixedPointForBindableElement(
|
||||
arrow.startBinding.fixedPoint,
|
||||
startOrEnd === "startBinding" ? bindableElement : otherBindableElement,
|
||||
elementsMap,
|
||||
);
|
||||
const endFocusPoint = getGlobalFixedPointForBindableElement(
|
||||
arrow.endBinding.fixedPoint,
|
||||
startOrEnd === "endBinding" ? bindableElement : otherBindableElement,
|
||||
elementsMap,
|
||||
);
|
||||
const segment = lineSegment(startFocusPoint, endFocusPoint);
|
||||
const startIntersection = intersectElementWithLineSegment(
|
||||
startOrEnd === "endBinding" ? bindableElement : otherBindableElement,
|
||||
elementsMap,
|
||||
segment,
|
||||
0,
|
||||
true,
|
||||
);
|
||||
const endIntersection = intersectElementWithLineSegment(
|
||||
startOrEnd === "startBinding" ? bindableElement : otherBindableElement,
|
||||
elementsMap,
|
||||
segment,
|
||||
0,
|
||||
true,
|
||||
);
|
||||
if (startIntersection.length > 0 && endIntersection.length > 0) {
|
||||
const len = pointDistance(startIntersection[0], endIntersection[0]);
|
||||
arrowTooShort = len < 40;
|
||||
}
|
||||
}
|
||||
|
||||
const isNested = (arrowTooShort || isOverlapping) && isLargerThanOther;
|
||||
|
||||
let _customIntersector = opts?.customIntersector;
|
||||
if (!elbowed && !_customIntersector) {
|
||||
const [x1, y1, x2, y2] = LinearElementEditor.getElementAbsoluteCoords(
|
||||
// 0. Short-circuit for inside binding as it doesn't require any
|
||||
// calculations and is not affected by other bindings
|
||||
if (binding.mode === "inside") {
|
||||
return LinearElementEditor.createPointAt(
|
||||
arrow,
|
||||
elementsMap,
|
||||
);
|
||||
const center = pointFrom<GlobalPoint>((x1 + x2) / 2, (y1 + y2) / 2);
|
||||
const edgePoint = global;
|
||||
const adjacentPoint = pointRotateRads(
|
||||
pointFrom<GlobalPoint>(
|
||||
arrow.x +
|
||||
arrow.points[pointIndex === 0 ? 1 : arrow.points.length - 2][0],
|
||||
arrow.y +
|
||||
arrow.points[pointIndex === 0 ? 1 : arrow.points.length - 2][1],
|
||||
),
|
||||
center,
|
||||
arrow.angle as Radians,
|
||||
);
|
||||
const bindingGap = getBindingGap(bindableElement, arrow);
|
||||
const halfVector = vectorScale(
|
||||
vectorNormalize(vectorFromPoint(edgePoint, adjacentPoint)),
|
||||
pointDistance(edgePoint, adjacentPoint) +
|
||||
Math.max(bindableElement.width, bindableElement.height) +
|
||||
bindingGap * 2,
|
||||
);
|
||||
_customIntersector = lineSegment(
|
||||
pointFromVector(halfVector, adjacentPoint),
|
||||
pointFromVector(vectorScale(halfVector, -1), adjacentPoint),
|
||||
focusPoint[0],
|
||||
focusPoint[1],
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
const maybeOutlineGlobal =
|
||||
binding.mode === "orbit" && bindableElement
|
||||
? isNested
|
||||
? global
|
||||
: bindPointToSnapToElementOutline(
|
||||
{
|
||||
...arrow,
|
||||
points: [
|
||||
pointIndex === 0
|
||||
? LinearElementEditor.createPointAt(
|
||||
arrow,
|
||||
elementsMap,
|
||||
global[0],
|
||||
global[1],
|
||||
null,
|
||||
)
|
||||
: arrow.points[0],
|
||||
...arrow.points.slice(1, -1),
|
||||
pointIndex === arrow.points.length - 1
|
||||
? LinearElementEditor.createPointAt(
|
||||
arrow,
|
||||
elementsMap,
|
||||
global[0],
|
||||
global[1],
|
||||
null,
|
||||
)
|
||||
: arrow.points[arrow.points.length - 1],
|
||||
],
|
||||
},
|
||||
bindableElement,
|
||||
pointIndex === 0 ? "start" : "end",
|
||||
elementsMap,
|
||||
_customIntersector,
|
||||
)
|
||||
: global;
|
||||
const { element: otherBindable, focusPoint: otherFocusPoint } =
|
||||
extractBinding(
|
||||
arrow,
|
||||
startOrEnd === "startBinding" ? "endBinding" : "startBinding",
|
||||
elementsMap,
|
||||
);
|
||||
const otherArrowPoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||
arrow,
|
||||
startOrEnd === "startBinding" ? -1 : 0,
|
||||
elementsMap,
|
||||
);
|
||||
const otherFocusPointOrArrowPoint = otherFocusPoint || otherArrowPoint;
|
||||
const intersector =
|
||||
otherFocusPointOrArrowPoint &&
|
||||
lineSegment(focusPoint, otherFocusPointOrArrowPoint);
|
||||
const otherOutlinePoint =
|
||||
otherBindable &&
|
||||
intersector &&
|
||||
intersectElementWithLineSegment(
|
||||
otherBindable,
|
||||
elementsMap,
|
||||
intersector,
|
||||
getBindingGap(otherBindable, arrow),
|
||||
).sort(
|
||||
(a, b) => pointDistanceSq(a, focusPoint) - pointDistanceSq(b, focusPoint),
|
||||
)[0];
|
||||
const outlinePoint =
|
||||
intersector &&
|
||||
intersectElementWithLineSegment(
|
||||
bindableElement,
|
||||
elementsMap,
|
||||
intersector,
|
||||
getBindingGap(bindableElement, arrow),
|
||||
).sort(
|
||||
(a, b) =>
|
||||
pointDistanceSq(a, otherFocusPointOrArrowPoint) -
|
||||
pointDistanceSq(b, otherFocusPointOrArrowPoint),
|
||||
)[0];
|
||||
const startHasArrowhead = arrow.startArrowhead !== null;
|
||||
const endHasArrowhead = arrow.endArrowhead !== null;
|
||||
const resolvedTarget =
|
||||
(!startHasArrowhead && !endHasArrowhead) ||
|
||||
(startOrEnd === "startBinding" && startHasArrowhead) ||
|
||||
(startOrEnd === "endBinding" && endHasArrowhead)
|
||||
? focusPoint
|
||||
: outlinePoint || focusPoint;
|
||||
|
||||
// 1. Handle case when the outline point (or focus point) is inside
|
||||
// the other shape by short-circuiting to the focus point, otherwise
|
||||
// the arrow would invert
|
||||
if (
|
||||
otherBindable &&
|
||||
outlinePoint &&
|
||||
!dragging &&
|
||||
// Arbitrary threshold to handle wireframing use cases
|
||||
elementArea(otherBindable) < elementArea(bindableElement) * 2 &&
|
||||
hitElementItself({
|
||||
element: otherBindable,
|
||||
point: outlinePoint,
|
||||
elementsMap,
|
||||
threshold: getBindingGap(otherBindable, arrow),
|
||||
overrideShouldTestInside: true,
|
||||
})
|
||||
) {
|
||||
return LinearElementEditor.createPointAt(
|
||||
arrow,
|
||||
elementsMap,
|
||||
resolvedTarget[0],
|
||||
resolvedTarget[1],
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
const otherTargetPoint = otherBindable
|
||||
? otherOutlinePoint || otherFocusPoint || otherArrowPoint
|
||||
: otherArrowPoint;
|
||||
const arrowTooShort =
|
||||
pointDistance(otherTargetPoint, outlinePoint || focusPoint) <=
|
||||
BASE_ARROW_MIN_LENGTH;
|
||||
|
||||
// 2. If the arrow is unconnected at the other end, just check arrow size
|
||||
// and short-circuit to the focus point if the arrow is too short to
|
||||
// avoid inversion
|
||||
if (!otherBindable) {
|
||||
return LinearElementEditor.createPointAt(
|
||||
arrow,
|
||||
elementsMap,
|
||||
arrowTooShort ? focusPoint[0] : outlinePoint?.[0] ?? focusPoint[0],
|
||||
arrowTooShort ? focusPoint[1] : outlinePoint?.[1] ?? focusPoint[1],
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
// 3. If the arrow is too short while connected on both ends and
|
||||
// the other arrow endpoint will not be inside the bindable, just
|
||||
// check the arrow size and make a decision based on that
|
||||
if (arrowTooShort) {
|
||||
return LinearElementEditor.createPointAt(
|
||||
arrow,
|
||||
elementsMap,
|
||||
resolvedTarget?.[0] || focusPoint[0],
|
||||
resolvedTarget?.[1] || focusPoint[1],
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
// 4. In the general case, snap to the outline if possible
|
||||
return LinearElementEditor.createPointAt(
|
||||
arrow,
|
||||
elementsMap,
|
||||
maybeOutlineGlobal[0],
|
||||
maybeOutlineGlobal[1],
|
||||
outlinePoint?.[0] || focusPoint[0],
|
||||
outlinePoint?.[1] || focusPoint[1],
|
||||
null,
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
vectorFromPoint,
|
||||
curveLength,
|
||||
curvePointAtLength,
|
||||
lineSegment,
|
||||
} from "@excalidraw/math";
|
||||
|
||||
import { getCurvePathOps } from "@excalidraw/utils/shape";
|
||||
@@ -2339,19 +2338,6 @@ const pointDraggingUpdates = (
|
||||
: updates.endBinding,
|
||||
};
|
||||
|
||||
// We need to use a custom intersector to ensure that if there is a big "jump"
|
||||
// in the arrow's position, we can position it with outline avoidance
|
||||
// pixel-perfectly and avoid "dancing" arrows.
|
||||
// NOTE: Direction matters here, so we create two intersectors
|
||||
const startCustomIntersector =
|
||||
start.focusPoint && end.focusPoint
|
||||
? lineSegment(start.focusPoint, end.focusPoint)
|
||||
: undefined;
|
||||
const endCustomIntersector =
|
||||
start.focusPoint && end.focusPoint
|
||||
? lineSegment(end.focusPoint, start.focusPoint)
|
||||
: undefined;
|
||||
|
||||
// Needed to handle a special case where an existing arrow is dragged over
|
||||
// the same element it is bound to on the other side
|
||||
const startIsDraggingOverEndElement =
|
||||
@@ -2387,9 +2373,7 @@ const pointDraggingUpdates = (
|
||||
nextArrow.endBinding,
|
||||
endBindable,
|
||||
elementsMap,
|
||||
{
|
||||
customIntersector: endCustomIntersector,
|
||||
},
|
||||
endIsDragged,
|
||||
) || nextArrow.points[nextArrow.points.length - 1]
|
||||
: nextArrow.points[nextArrow.points.length - 1];
|
||||
|
||||
@@ -2420,7 +2404,7 @@ const pointDraggingUpdates = (
|
||||
nextArrow.startBinding,
|
||||
startBindable,
|
||||
elementsMap,
|
||||
{ customIntersector: startCustomIntersector },
|
||||
startIsDragged,
|
||||
) || nextArrow.points[0]
|
||||
: nextArrow.points[0];
|
||||
|
||||
|
||||
@@ -43,6 +43,11 @@ import { LinearElementEditor } from "./linearElementEditor";
|
||||
import { isRectangularElement } from "./typeChecks";
|
||||
import { maxBindingDistance_simple } from "./binding";
|
||||
|
||||
import {
|
||||
getGlobalFixedPointForBindableElement,
|
||||
normalizeFixedPoint,
|
||||
} from "./binding";
|
||||
|
||||
import type {
|
||||
ElementsMap,
|
||||
ExcalidrawArrowElement,
|
||||
@@ -677,11 +682,35 @@ export const projectFixedPointOntoDiagonal = (
|
||||
elementsMap,
|
||||
);
|
||||
|
||||
const a = LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||
// To avoid working with stale arrow state, we use the opposite focus point
|
||||
// of the current endpoint, which will always be unchanged during moving of
|
||||
// the endpoint. This is only needed when the arrow has only two points.
|
||||
let a = LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||
arrow,
|
||||
startOrEnd === "start" ? 1 : arrow.points.length - 2,
|
||||
elementsMap,
|
||||
);
|
||||
if (arrow.points.length === 2) {
|
||||
const otherBinding =
|
||||
startOrEnd === "start" ? arrow.endBinding : arrow.startBinding;
|
||||
const otherBindable =
|
||||
otherBinding &&
|
||||
(elementsMap.get(otherBinding.elementId) as
|
||||
| ExcalidrawBindableElement
|
||||
| undefined);
|
||||
const otherFocusPoint =
|
||||
otherBinding &&
|
||||
otherBindable &&
|
||||
getGlobalFixedPointForBindableElement(
|
||||
normalizeFixedPoint(otherBinding.fixedPoint),
|
||||
otherBindable,
|
||||
elementsMap,
|
||||
);
|
||||
if (otherFocusPoint) {
|
||||
a = otherFocusPoint;
|
||||
}
|
||||
}
|
||||
|
||||
const b = pointFromVector<GlobalPoint>(
|
||||
vectorScale(
|
||||
vectorFromPoint(point, a),
|
||||
|
||||
@@ -9623,9 +9623,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
isBindableElement(element) &&
|
||||
element.boundElements?.some((other) => other.type === "arrow")
|
||||
) {
|
||||
updateBoundElements(element, this.scene, {
|
||||
indirectArrowUpdate: true,
|
||||
});
|
||||
updateBoundElements(element, this.scene);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 33,
|
||||
"version": 29,
|
||||
"width": "94.00000",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
@@ -334,15 +334,15 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"height": "105.58873",
|
||||
"height": "105.58874",
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
],
|
||||
[
|
||||
88,
|
||||
"105.58873",
|
||||
"88.00000",
|
||||
"105.58874",
|
||||
],
|
||||
],
|
||||
"startBinding": {
|
||||
@@ -353,8 +353,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"version": 32,
|
||||
"width": 88,
|
||||
"version": 28,
|
||||
"width": "88.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"endBinding": {
|
||||
@@ -365,7 +365,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"height": "0.00000",
|
||||
"height": 0,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
@@ -373,7 +373,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
],
|
||||
[
|
||||
"88.00000",
|
||||
"0.00000",
|
||||
0,
|
||||
],
|
||||
],
|
||||
"startBinding": {
|
||||
@@ -384,7 +384,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"version": 29,
|
||||
"version": 25,
|
||||
"width": "88.00000",
|
||||
},
|
||||
},
|
||||
@@ -440,21 +440,21 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
],
|
||||
],
|
||||
"startBinding": null,
|
||||
"version": 33,
|
||||
"version": 29,
|
||||
"width": "94.00000",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
},
|
||||
"inserted": {
|
||||
"height": "105.58873",
|
||||
"height": "105.58874",
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
],
|
||||
[
|
||||
88,
|
||||
"105.58873",
|
||||
"88.00000",
|
||||
"105.58874",
|
||||
],
|
||||
],
|
||||
"startBinding": {
|
||||
@@ -465,10 +465,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"version": 32,
|
||||
"width": 88,
|
||||
"version": 28,
|
||||
"width": "88.00000",
|
||||
"x": 6,
|
||||
"y": "7.09000",
|
||||
"y": "7.20923",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -854,7 +854,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 30,
|
||||
"version": 25,
|
||||
"width": 100,
|
||||
"x": 150,
|
||||
"y": 0,
|
||||
@@ -904,15 +904,15 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"id4": {
|
||||
"deleted": {
|
||||
"endBinding": null,
|
||||
"height": "0.00293",
|
||||
"height": "0.01000",
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
],
|
||||
[
|
||||
"-44.00000",
|
||||
"-0.00293",
|
||||
-44,
|
||||
"-0.01000",
|
||||
],
|
||||
],
|
||||
"startBinding": {
|
||||
@@ -923,9 +923,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"version": 29,
|
||||
"width": "44.00000",
|
||||
"y": "0.00293",
|
||||
"version": 24,
|
||||
"width": 44,
|
||||
"y": "0.01000",
|
||||
},
|
||||
"inserted": {
|
||||
"endBinding": {
|
||||
@@ -943,7 +943,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
0,
|
||||
],
|
||||
[
|
||||
"6.00000",
|
||||
-100,
|
||||
0,
|
||||
],
|
||||
],
|
||||
@@ -955,8 +955,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"version": 27,
|
||||
"width": "6.00000",
|
||||
"version": 23,
|
||||
"width": 100,
|
||||
"y": "0.01000",
|
||||
},
|
||||
},
|
||||
@@ -1004,21 +1004,21 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
],
|
||||
],
|
||||
"startBinding": null,
|
||||
"version": 30,
|
||||
"version": 25,
|
||||
"width": 100,
|
||||
"x": 150,
|
||||
"y": 0,
|
||||
},
|
||||
"inserted": {
|
||||
"height": "0.00293",
|
||||
"height": "0.01000",
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
],
|
||||
[
|
||||
"-44.00000",
|
||||
"-0.00293",
|
||||
-44,
|
||||
"-0.01000",
|
||||
],
|
||||
],
|
||||
"startBinding": {
|
||||
@@ -1029,10 +1029,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"version": 29,
|
||||
"width": "44.00000",
|
||||
"x": 144,
|
||||
"y": "0.00293",
|
||||
"version": 24,
|
||||
"width": 44,
|
||||
"x": 250,
|
||||
"y": "0.01000",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1335,7 +1335,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "29.36414",
|
||||
"height": "29.32551",
|
||||
"id": "id4",
|
||||
"index": "Zz",
|
||||
"isDeleted": false,
|
||||
@@ -1350,7 +1350,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
],
|
||||
[
|
||||
88,
|
||||
"29.36414",
|
||||
"29.32551",
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -1369,10 +1369,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 10,
|
||||
"version": 8,
|
||||
"width": 88,
|
||||
"x": 6,
|
||||
"y": "2.00946",
|
||||
"y": "2.00947",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1546,7 +1546,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"version": 10,
|
||||
"version": 8,
|
||||
},
|
||||
"inserted": {
|
||||
"endBinding": null,
|
||||
@@ -1698,7 +1698,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "14.91372",
|
||||
"height": "17.59718",
|
||||
"id": "id5",
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
@@ -1712,8 +1712,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
0,
|
||||
],
|
||||
[
|
||||
"88.00000",
|
||||
"-14.91372",
|
||||
88,
|
||||
"-17.59718",
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -1732,10 +1732,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 11,
|
||||
"width": "88.00000",
|
||||
"version": 8,
|
||||
"width": 88,
|
||||
"x": 6,
|
||||
"y": "37.05219",
|
||||
"y": "38.80379",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1846,7 +1846,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "14.91372",
|
||||
"height": "17.59718",
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
@@ -1858,8 +1858,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
0,
|
||||
],
|
||||
[
|
||||
"88.00000",
|
||||
"-14.91372",
|
||||
88,
|
||||
"-17.59718",
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -1877,14 +1877,14 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"version": 11,
|
||||
"width": "88.00000",
|
||||
"version": 8,
|
||||
"width": 88,
|
||||
"x": 6,
|
||||
"y": "37.05219",
|
||||
"y": "38.80379",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
"version": 8,
|
||||
"version": 7,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -2398,7 +2398,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "439.13521",
|
||||
"height": "439.20000",
|
||||
"id": "id4",
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
@@ -2413,7 +2413,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
],
|
||||
[
|
||||
488,
|
||||
"-439.13521",
|
||||
"-439.20000",
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -2434,10 +2434,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 13,
|
||||
"version": 12,
|
||||
"width": 488,
|
||||
"x": 6,
|
||||
"y": "-5.38920",
|
||||
"y": "-5.39000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -2566,7 +2566,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "439.13521",
|
||||
"height": "439.20000",
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
@@ -2579,7 +2579,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
],
|
||||
[
|
||||
488,
|
||||
"-439.13521",
|
||||
"-439.20000",
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -2599,14 +2599,14 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"version": 13,
|
||||
"version": 12,
|
||||
"width": 488,
|
||||
"x": 6,
|
||||
"y": "-5.38920",
|
||||
"y": "-5.39000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
"version": 10,
|
||||
"version": 9,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -16383,7 +16383,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "0.00004",
|
||||
"height": 0,
|
||||
"id": "id13",
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
@@ -16398,7 +16398,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
],
|
||||
[
|
||||
"88.00000",
|
||||
"0.00004",
|
||||
0,
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -16419,10 +16419,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 12,
|
||||
"version": 10,
|
||||
"width": "88.00000",
|
||||
"x": 6,
|
||||
"y": "0.00996",
|
||||
"y": "0.01000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -16472,7 +16472,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"version": 12,
|
||||
"version": 10,
|
||||
},
|
||||
"inserted": {
|
||||
"endBinding": {
|
||||
@@ -16492,7 +16492,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"version": 9,
|
||||
"version": 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -16801,7 +16801,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "0.00936",
|
||||
"height": "0.00120",
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
@@ -16813,8 +16813,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
0,
|
||||
],
|
||||
[
|
||||
88,
|
||||
"0.00936",
|
||||
"88.00000",
|
||||
"0.00120",
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -16834,14 +16834,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"version": 8,
|
||||
"width": 88,
|
||||
"version": 7,
|
||||
"width": "88.00000",
|
||||
"x": 6,
|
||||
"y": 0,
|
||||
"y": "0.00880",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
"version": 7,
|
||||
"version": 6,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -17134,7 +17134,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "0.00004",
|
||||
"height": 0,
|
||||
"id": "id13",
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
@@ -17149,7 +17149,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
],
|
||||
[
|
||||
"88.00000",
|
||||
"0.00004",
|
||||
0,
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -17170,10 +17170,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 12,
|
||||
"version": 10,
|
||||
"width": "88.00000",
|
||||
"x": 6,
|
||||
"y": "0.00996",
|
||||
"y": "0.01000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -17442,7 +17442,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "0.00004",
|
||||
"height": 0,
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
@@ -17455,7 +17455,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
],
|
||||
[
|
||||
"88.00000",
|
||||
"0.00004",
|
||||
0,
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -17475,14 +17475,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"version": 12,
|
||||
"version": 10,
|
||||
"width": "88.00000",
|
||||
"x": 6,
|
||||
"y": "0.00996",
|
||||
"y": "0.01000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
"version": 9,
|
||||
"version": 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -17783,7 +17783,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "0.00004",
|
||||
"height": 0,
|
||||
"id": "id13",
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
@@ -17798,7 +17798,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
],
|
||||
[
|
||||
"88.00000",
|
||||
"0.00004",
|
||||
0,
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -17819,10 +17819,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 12,
|
||||
"version": 10,
|
||||
"width": "88.00000",
|
||||
"x": 6,
|
||||
"y": "0.00996",
|
||||
"y": "0.01000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -18091,7 +18091,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "0.00004",
|
||||
"height": 0,
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
@@ -18104,7 +18104,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
],
|
||||
[
|
||||
"88.00000",
|
||||
"0.00004",
|
||||
0,
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -18124,14 +18124,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"version": 12,
|
||||
"version": 10,
|
||||
"width": "88.00000",
|
||||
"x": 6,
|
||||
"y": "0.00996",
|
||||
"y": "0.01000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
"version": 9,
|
||||
"version": 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -18430,7 +18430,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "0.00004",
|
||||
"height": 0,
|
||||
"id": "id13",
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
@@ -18445,7 +18445,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
],
|
||||
[
|
||||
"88.00000",
|
||||
"0.00004",
|
||||
0,
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -18466,10 +18466,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 12,
|
||||
"version": 10,
|
||||
"width": "88.00000",
|
||||
"x": 6,
|
||||
"y": "0.00996",
|
||||
"y": "0.01000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -18535,7 +18535,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"version": 12,
|
||||
"version": 10,
|
||||
},
|
||||
"inserted": {
|
||||
"endBinding": {
|
||||
@@ -18547,7 +18547,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"mode": "orbit",
|
||||
},
|
||||
"startBinding": null,
|
||||
"version": 9,
|
||||
"version": 8,
|
||||
},
|
||||
},
|
||||
"id2": {
|
||||
@@ -18824,7 +18824,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "0.00936",
|
||||
"height": "0.00120",
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
@@ -18836,8 +18836,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
0,
|
||||
],
|
||||
[
|
||||
88,
|
||||
"0.00936",
|
||||
"88.00000",
|
||||
"0.00120",
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -18857,14 +18857,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"version": 8,
|
||||
"width": 88,
|
||||
"version": 7,
|
||||
"width": "88.00000",
|
||||
"x": 6,
|
||||
"y": 0,
|
||||
"y": "0.00880",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
"version": 7,
|
||||
"version": 6,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -19185,7 +19185,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "0.00004",
|
||||
"height": 0,
|
||||
"id": "id13",
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
@@ -19200,7 +19200,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
],
|
||||
[
|
||||
"88.00000",
|
||||
"0.00004",
|
||||
0,
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -19221,10 +19221,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 13,
|
||||
"version": 11,
|
||||
"width": "88.00000",
|
||||
"x": 6,
|
||||
"y": "0.00996",
|
||||
"y": "0.01000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -19301,12 +19301,12 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"version": 13,
|
||||
"version": 11,
|
||||
},
|
||||
"inserted": {
|
||||
"endBinding": null,
|
||||
"startBinding": null,
|
||||
"version": 10,
|
||||
"version": 9,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -19575,7 +19575,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "0.00936",
|
||||
"height": "0.00120",
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
@@ -19587,8 +19587,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
0,
|
||||
],
|
||||
[
|
||||
88,
|
||||
"0.00936",
|
||||
"88.00000",
|
||||
"0.00120",
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -19608,14 +19608,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"version": 8,
|
||||
"width": 88,
|
||||
"version": 7,
|
||||
"width": "88.00000",
|
||||
"x": 6,
|
||||
"y": 0,
|
||||
"y": "0.00880",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
"version": 7,
|
||||
"version": 6,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -182,14 +182,14 @@ exports[`move element > rectangles with binding arrow 7`] = `
|
||||
"elementId": "id3",
|
||||
"fixedPoint": [
|
||||
"-0.02000",
|
||||
"0.47904",
|
||||
"0.48010",
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "90.02554",
|
||||
"height": "90.01760",
|
||||
"id": "id6",
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
@@ -204,7 +204,7 @@ exports[`move element > rectangles with binding arrow 7`] = `
|
||||
],
|
||||
[
|
||||
89,
|
||||
"90.02554",
|
||||
"90.01760",
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -217,7 +217,7 @@ exports[`move element > rectangles with binding arrow 7`] = `
|
||||
"elementId": "id0",
|
||||
"fixedPoint": [
|
||||
"1.06000",
|
||||
"0.55687",
|
||||
"0.56011",
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
@@ -230,6 +230,6 @@ exports[`move element > rectangles with binding arrow 7`] = `
|
||||
"versionNonce": 271613161,
|
||||
"width": 89,
|
||||
"x": 106,
|
||||
"y": "55.68677",
|
||||
"y": "56.01120",
|
||||
}
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user