mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
[skip ci] First iteration of bringing over previous changes
This commit is contained in:
parent
4ee99de2fb
commit
fbde68c849
19 changed files with 599 additions and 596 deletions
|
@ -2,6 +2,7 @@ import { average } from "@excalidraw/math";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ExcalidrawBindableElement,
|
ExcalidrawBindableElement,
|
||||||
|
ExcalidrawElement,
|
||||||
FontFamilyValues,
|
FontFamilyValues,
|
||||||
FontString,
|
FontString,
|
||||||
} from "@excalidraw/element/types";
|
} from "@excalidraw/element/types";
|
||||||
|
@ -1201,3 +1202,6 @@ export const escapeDoubleQuotes = (str: string) => {
|
||||||
|
|
||||||
export const castArray = <T>(value: T | T[]): T[] =>
|
export const castArray = <T>(value: T | T[]): T[] =>
|
||||||
Array.isArray(value) ? value : [value];
|
Array.isArray(value) ? value : [value];
|
||||||
|
|
||||||
|
export const toLocalPoint = (p: GlobalPoint, element: ExcalidrawElement) =>
|
||||||
|
pointTranslate<GlobalPoint, LocalPoint>(p, vector(-element.x, -element.y));
|
||||||
|
|
|
@ -81,11 +81,10 @@ import type {
|
||||||
NonDeletedSceneElementsMap,
|
NonDeletedSceneElementsMap,
|
||||||
ExcalidrawTextElement,
|
ExcalidrawTextElement,
|
||||||
ExcalidrawArrowElement,
|
ExcalidrawArrowElement,
|
||||||
OrderedExcalidrawElement,
|
|
||||||
ExcalidrawElbowArrowElement,
|
|
||||||
FixedPoint,
|
FixedPoint,
|
||||||
SceneElementsMap,
|
SceneElementsMap,
|
||||||
FixedPointBinding,
|
FixedPointBinding,
|
||||||
|
ExcalidrawElbowArrowElement,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
export type SuggestedBinding =
|
export type SuggestedBinding =
|
||||||
|
@ -108,6 +107,7 @@ export const isBindingEnabled = (appState: AppState): boolean => {
|
||||||
return appState.isBindingEnabled;
|
return appState.isBindingEnabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const INSIDE_BINDING_BAND_PERCENT = 0.1;
|
||||||
export const FIXED_BINDING_DISTANCE = 5;
|
export const FIXED_BINDING_DISTANCE = 5;
|
||||||
export const BINDING_HIGHLIGHT_THICKNESS = 10;
|
export const BINDING_HIGHLIGHT_THICKNESS = 10;
|
||||||
export const BINDING_HIGHLIGHT_OFFSET = 4;
|
export const BINDING_HIGHLIGHT_OFFSET = 4;
|
||||||
|
@ -463,26 +463,6 @@ export const maybeBindLinearElement = (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const normalizePointBinding = (
|
|
||||||
binding: { focus: number; gap: number },
|
|
||||||
hoveredElement: ExcalidrawBindableElement,
|
|
||||||
) => {
|
|
||||||
let gap = binding.gap;
|
|
||||||
const maxGap = maxBindingGap(
|
|
||||||
hoveredElement,
|
|
||||||
hoveredElement.width,
|
|
||||||
hoveredElement.height,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (gap > maxGap) {
|
|
||||||
gap = BINDING_HIGHLIGHT_THICKNESS + BINDING_HIGHLIGHT_OFFSET;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...binding,
|
|
||||||
gap,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const bindLinearElement = (
|
export const bindLinearElement = (
|
||||||
linearElement: NonDeleted<ExcalidrawLinearElement>,
|
linearElement: NonDeleted<ExcalidrawLinearElement>,
|
||||||
hoveredElement: ExcalidrawBindableElement,
|
hoveredElement: ExcalidrawBindableElement,
|
||||||
|
@ -493,17 +473,25 @@ export const bindLinearElement = (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const direction = startOrEnd === "start" ? -1 : 1;
|
||||||
|
const edgePointIndex = direction === -1 ? 0 : linearElement.points.length - 1;
|
||||||
|
const adjacentPointIndex = edgePointIndex - direction;
|
||||||
|
|
||||||
|
const edgePoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||||
|
linearElement,
|
||||||
|
edgePointIndex,
|
||||||
|
elementsMap,
|
||||||
|
);
|
||||||
|
const adjacentPoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||||
|
linearElement,
|
||||||
|
adjacentPointIndex,
|
||||||
|
elementsMap,
|
||||||
|
);
|
||||||
|
|
||||||
let binding: PointBinding | FixedPointBinding = {
|
let binding: PointBinding | FixedPointBinding = {
|
||||||
elementId: hoveredElement.id,
|
elementId: hoveredElement.id,
|
||||||
...normalizePointBinding(
|
focus: determineFocusDistance(hoveredElement, adjacentPoint, edgePoint),
|
||||||
calculateFocusAndGap(
|
gap: FIXED_BINDING_DISTANCE,
|
||||||
linearElement,
|
|
||||||
hoveredElement,
|
|
||||||
startOrEnd,
|
|
||||||
elementsMap,
|
|
||||||
),
|
|
||||||
hoveredElement,
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isElbowArrow(linearElement)) {
|
if (isElbowArrow(linearElement)) {
|
||||||
|
@ -706,33 +694,6 @@ const getAllElementsAtPositionForBinding = (
|
||||||
return elementsAtPosition;
|
return elementsAtPosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
const calculateFocusAndGap = (
|
|
||||||
linearElement: NonDeleted<ExcalidrawLinearElement>,
|
|
||||||
hoveredElement: ExcalidrawBindableElement,
|
|
||||||
startOrEnd: "start" | "end",
|
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
|
||||||
): { focus: number; gap: number } => {
|
|
||||||
const direction = startOrEnd === "start" ? -1 : 1;
|
|
||||||
const edgePointIndex = direction === -1 ? 0 : linearElement.points.length - 1;
|
|
||||||
const adjacentPointIndex = edgePointIndex - direction;
|
|
||||||
|
|
||||||
const edgePoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
|
||||||
linearElement,
|
|
||||||
edgePointIndex,
|
|
||||||
elementsMap,
|
|
||||||
);
|
|
||||||
const adjacentPoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
|
||||||
linearElement,
|
|
||||||
adjacentPointIndex,
|
|
||||||
elementsMap,
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
focus: determineFocusDistance(hoveredElement, adjacentPoint, edgePoint),
|
|
||||||
gap: Math.max(1, distanceToBindableElement(hoveredElement, edgePoint)),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Supports translating, rotating and scaling `changedElement` with bound
|
// Supports translating, rotating and scaling `changedElement` with bound
|
||||||
// linear elements.
|
// linear elements.
|
||||||
// Because scaling involves moving the focus points as well, it is
|
// Because scaling involves moving the focus points as well, it is
|
||||||
|
@ -743,11 +704,9 @@ export const updateBoundElements = (
|
||||||
elementsMap: NonDeletedSceneElementsMap | SceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap | SceneElementsMap,
|
||||||
options?: {
|
options?: {
|
||||||
simultaneouslyUpdated?: readonly ExcalidrawElement[];
|
simultaneouslyUpdated?: readonly ExcalidrawElement[];
|
||||||
newSize?: { width: number; height: number };
|
|
||||||
changedElements?: Map<string, OrderedExcalidrawElement>;
|
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
const { newSize, simultaneouslyUpdated } = options ?? {};
|
const { simultaneouslyUpdated } = options ?? {};
|
||||||
const simultaneouslyUpdatedElementIds = getSimultaneouslyUpdatedElementIds(
|
const simultaneouslyUpdatedElementIds = getSimultaneouslyUpdatedElementIds(
|
||||||
simultaneouslyUpdated,
|
simultaneouslyUpdated,
|
||||||
);
|
);
|
||||||
|
@ -781,22 +740,13 @@ export const updateBoundElements = (
|
||||||
endBounds = getElementBounds(endBindingElement, elementsMap);
|
endBounds = getElementBounds(endBindingElement, elementsMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bindings = {
|
|
||||||
startBinding: maybeCalculateNewGapWhenScaling(
|
|
||||||
changedElement,
|
|
||||||
element.startBinding,
|
|
||||||
newSize,
|
|
||||||
),
|
|
||||||
endBinding: maybeCalculateNewGapWhenScaling(
|
|
||||||
changedElement,
|
|
||||||
element.endBinding,
|
|
||||||
newSize,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
// `linearElement` is being moved/scaled already, just update the binding
|
// `linearElement` is being moved/scaled already, just update the binding
|
||||||
if (simultaneouslyUpdatedElementIds.has(element.id)) {
|
if (simultaneouslyUpdatedElementIds.has(element.id)) {
|
||||||
mutateElement(element, bindings, true);
|
mutateElement(
|
||||||
|
element,
|
||||||
|
{ startBinding: element.startBinding, endBinding: element.endBinding },
|
||||||
|
true,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -818,7 +768,9 @@ export const updateBoundElements = (
|
||||||
const point = updateBoundPoint(
|
const point = updateBoundPoint(
|
||||||
element,
|
element,
|
||||||
bindingProp,
|
bindingProp,
|
||||||
bindings[bindingProp],
|
bindingProp === "startBinding"
|
||||||
|
? element.startBinding
|
||||||
|
: element.endBinding,
|
||||||
bindableElement,
|
bindableElement,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
);
|
);
|
||||||
|
@ -848,10 +800,10 @@ export const updateBoundElements = (
|
||||||
updates,
|
updates,
|
||||||
{
|
{
|
||||||
...(changedElement.id === element.startBinding?.elementId
|
...(changedElement.id === element.startBinding?.elementId
|
||||||
? { startBinding: bindings.startBinding }
|
? { startBinding: element.startBinding }
|
||||||
: {}),
|
: {}),
|
||||||
...(changedElement.id === element.endBinding?.elementId
|
...(changedElement.id === element.endBinding?.elementId
|
||||||
? { endBinding: bindings.endBinding }
|
? { endBinding: element.endBinding }
|
||||||
: {}),
|
: {}),
|
||||||
},
|
},
|
||||||
elementsMap as NonDeletedSceneElementsMap,
|
elementsMap as NonDeletedSceneElementsMap,
|
||||||
|
@ -885,7 +837,6 @@ export const getHeadingForElbowArrowSnap = (
|
||||||
otherPoint: Readonly<GlobalPoint>,
|
otherPoint: Readonly<GlobalPoint>,
|
||||||
bindableElement: ExcalidrawBindableElement | undefined | null,
|
bindableElement: ExcalidrawBindableElement | undefined | null,
|
||||||
aabb: Bounds | undefined | null,
|
aabb: Bounds | undefined | null,
|
||||||
elementsMap: ElementsMap,
|
|
||||||
origPoint: GlobalPoint,
|
origPoint: GlobalPoint,
|
||||||
zoom?: AppState["zoom"],
|
zoom?: AppState["zoom"],
|
||||||
): Heading => {
|
): Heading => {
|
||||||
|
@ -895,12 +846,7 @@ export const getHeadingForElbowArrowSnap = (
|
||||||
return otherPointHeading;
|
return otherPointHeading;
|
||||||
}
|
}
|
||||||
|
|
||||||
const distance = getDistanceForBinding(
|
const distance = getDistanceForBinding(origPoint, bindableElement, zoom);
|
||||||
origPoint,
|
|
||||||
bindableElement,
|
|
||||||
elementsMap,
|
|
||||||
zoom,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!distance) {
|
if (!distance) {
|
||||||
return vectorToHeading(
|
return vectorToHeading(
|
||||||
|
@ -920,7 +866,6 @@ export const getHeadingForElbowArrowSnap = (
|
||||||
const getDistanceForBinding = (
|
const getDistanceForBinding = (
|
||||||
point: Readonly<GlobalPoint>,
|
point: Readonly<GlobalPoint>,
|
||||||
bindableElement: ExcalidrawBindableElement,
|
bindableElement: ExcalidrawBindableElement,
|
||||||
elementsMap: ElementsMap,
|
|
||||||
zoom?: AppState["zoom"],
|
zoom?: AppState["zoom"],
|
||||||
) => {
|
) => {
|
||||||
const distance = distanceToBindableElement(bindableElement, point);
|
const distance = distanceToBindableElement(bindableElement, point);
|
||||||
|
@ -935,40 +880,47 @@ const getDistanceForBinding = (
|
||||||
};
|
};
|
||||||
|
|
||||||
export const bindPointToSnapToElementOutline = (
|
export const bindPointToSnapToElementOutline = (
|
||||||
arrow: ExcalidrawElbowArrowElement,
|
linearElement: ExcalidrawLinearElement,
|
||||||
bindableElement: ExcalidrawBindableElement,
|
bindableElement: ExcalidrawBindableElement,
|
||||||
startOrEnd: "start" | "end",
|
startOrEnd: "start" | "end",
|
||||||
|
elementsMap: ElementsMap,
|
||||||
): GlobalPoint => {
|
): GlobalPoint => {
|
||||||
if (isDevEnv() || isTestEnv()) {
|
if (isDevEnv() || isTestEnv()) {
|
||||||
invariant(arrow.points.length > 1, "Arrow should have at least 2 points");
|
invariant(
|
||||||
|
linearElement.points.length > 0,
|
||||||
|
"Arrow should have at least 1 point",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const elbowed = isElbowArrow(linearElement);
|
||||||
const aabb = aabbForElement(bindableElement);
|
const aabb = aabbForElement(bindableElement);
|
||||||
const localP =
|
|
||||||
arrow.points[startOrEnd === "start" ? 0 : arrow.points.length - 1];
|
|
||||||
const globalP = pointFrom<GlobalPoint>(
|
|
||||||
arrow.x + localP[0],
|
|
||||||
arrow.y + localP[1],
|
|
||||||
);
|
|
||||||
const edgePoint = isRectanguloidElement(bindableElement)
|
|
||||||
? avoidRectangularCorner(bindableElement, globalP)
|
|
||||||
: globalP;
|
|
||||||
const elbowed = isElbowArrow(arrow);
|
|
||||||
const center = getCenterForBounds(aabb);
|
const center = getCenterForBounds(aabb);
|
||||||
const adjacentPointIdx = startOrEnd === "start" ? 1 : arrow.points.length - 2;
|
|
||||||
const adjacentPoint = pointRotateRads(
|
const pointIdx = startOrEnd === "start" ? 0 : linearElement.points.length - 1;
|
||||||
pointFrom<GlobalPoint>(
|
const p = pointFrom<GlobalPoint>(
|
||||||
arrow.x + arrow.points[adjacentPointIdx][0],
|
linearElement.x + linearElement.points[pointIdx][0],
|
||||||
arrow.y + arrow.points[adjacentPointIdx][1],
|
linearElement.y + linearElement.points[pointIdx][1],
|
||||||
),
|
|
||||||
center,
|
|
||||||
arrow.angle ?? 0,
|
|
||||||
);
|
);
|
||||||
|
const edgePoint = avoidRectangularCorner(bindableElement, p);
|
||||||
|
|
||||||
|
const adjacentPointIdx =
|
||||||
|
startOrEnd === "start" ? 1 : linearElement.points.length - 2;
|
||||||
|
const adjacentPoint =
|
||||||
|
linearElement.points.length === 1
|
||||||
|
? center
|
||||||
|
: pointRotateRads(
|
||||||
|
pointFrom<GlobalPoint>(
|
||||||
|
linearElement.x + linearElement.points[adjacentPointIdx][0],
|
||||||
|
linearElement.y + linearElement.points[adjacentPointIdx][1],
|
||||||
|
),
|
||||||
|
center,
|
||||||
|
linearElement.angle ?? 0,
|
||||||
|
);
|
||||||
|
|
||||||
let intersection: GlobalPoint | null = null;
|
let intersection: GlobalPoint | null = null;
|
||||||
if (elbowed) {
|
if (elbowed) {
|
||||||
const isHorizontal = headingIsHorizontal(
|
const isHorizontal = headingIsHorizontal(
|
||||||
headingForPointFromElement(bindableElement, aabb, globalP),
|
headingForPointFromElement(bindableElement, aabb, p),
|
||||||
);
|
);
|
||||||
const otherPoint = pointFrom<GlobalPoint>(
|
const otherPoint = pointFrom<GlobalPoint>(
|
||||||
isHorizontal ? center[0] : edgePoint[0],
|
isHorizontal ? center[0] : edgePoint[0],
|
||||||
|
@ -1033,6 +985,28 @@ export const bindPointToSnapToElementOutline = (
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isInside = isPointInShape(
|
||||||
|
edgePoint,
|
||||||
|
getElementShape(
|
||||||
|
{
|
||||||
|
...bindableElement,
|
||||||
|
x:
|
||||||
|
bindableElement.x +
|
||||||
|
bindableElement.width * INSIDE_BINDING_BAND_PERCENT,
|
||||||
|
y:
|
||||||
|
bindableElement.y +
|
||||||
|
bindableElement.height * INSIDE_BINDING_BAND_PERCENT,
|
||||||
|
width: bindableElement.width * (1 - INSIDE_BINDING_BAND_PERCENT * 2),
|
||||||
|
height: bindableElement.height * (1 - INSIDE_BINDING_BAND_PERCENT * 2),
|
||||||
|
} as ExcalidrawBindableElement,
|
||||||
|
elementsMap,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isInside) {
|
||||||
|
return intersection;
|
||||||
|
}
|
||||||
|
|
||||||
return edgePoint;
|
return edgePoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1040,6 +1014,10 @@ export const avoidRectangularCorner = (
|
||||||
element: ExcalidrawBindableElement,
|
element: ExcalidrawBindableElement,
|
||||||
p: GlobalPoint,
|
p: GlobalPoint,
|
||||||
): GlobalPoint => {
|
): GlobalPoint => {
|
||||||
|
if (!isRectanguloidElement(element)) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
const center = pointFrom<GlobalPoint>(
|
const center = pointFrom<GlobalPoint>(
|
||||||
element.x + element.width / 2,
|
element.x + element.width / 2,
|
||||||
element.y + element.height / 2,
|
element.y + element.height / 2,
|
||||||
|
@ -1200,6 +1178,45 @@ export const snapToMid = (
|
||||||
return p;
|
return p;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getOutlineAvoidingPoint = (
|
||||||
|
element: NonDeleted<ExcalidrawLinearElement>,
|
||||||
|
coords: GlobalPoint,
|
||||||
|
pointIndex: number,
|
||||||
|
scene: Scene,
|
||||||
|
zoom: AppState["zoom"],
|
||||||
|
fallback?: GlobalPoint,
|
||||||
|
): GlobalPoint => {
|
||||||
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
|
const hoveredElement = getHoveredElementForBinding(
|
||||||
|
{ x: coords[0], y: coords[1] },
|
||||||
|
scene.getNonDeletedElements(),
|
||||||
|
elementsMap,
|
||||||
|
zoom,
|
||||||
|
true,
|
||||||
|
isElbowArrow(element),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (hoveredElement) {
|
||||||
|
const newPoints = Array.from(element.points);
|
||||||
|
newPoints[pointIndex] = pointFrom<LocalPoint>(
|
||||||
|
coords[0] - element.x,
|
||||||
|
coords[1] - element.y,
|
||||||
|
);
|
||||||
|
|
||||||
|
return bindPointToSnapToElementOutline(
|
||||||
|
{
|
||||||
|
...element,
|
||||||
|
points: newPoints,
|
||||||
|
},
|
||||||
|
hoveredElement,
|
||||||
|
pointIndex === 0 ? "start" : "end",
|
||||||
|
elementsMap,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallback ?? coords;
|
||||||
|
};
|
||||||
|
|
||||||
const updateBoundPoint = (
|
const updateBoundPoint = (
|
||||||
linearElement: NonDeleted<ExcalidrawLinearElement>,
|
linearElement: NonDeleted<ExcalidrawLinearElement>,
|
||||||
startOrEnd: "startBinding" | "endBinding",
|
startOrEnd: "startBinding" | "endBinding",
|
||||||
|
@ -1263,66 +1280,65 @@ const updateBoundPoint = (
|
||||||
|
|
||||||
let newEdgePoint: GlobalPoint;
|
let newEdgePoint: GlobalPoint;
|
||||||
|
|
||||||
// The linear element was not originally pointing inside the bound shape,
|
// // The linear element was not originally pointing inside the bound shape,
|
||||||
// we can point directly at the focus point
|
// // we can point directly at the focus point
|
||||||
if (binding.gap === 0) {
|
// if (binding.gap === 0) {
|
||||||
|
// newEdgePoint = focusPointAbsolute;
|
||||||
|
// } else {
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
const edgePointAbsolute =
|
||||||
|
LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||||
|
linearElement,
|
||||||
|
edgePointIndex,
|
||||||
|
elementsMap,
|
||||||
|
);
|
||||||
|
|
||||||
|
const center = pointFrom<GlobalPoint>(
|
||||||
|
bindableElement.x + bindableElement.width / 2,
|
||||||
|
bindableElement.y + bindableElement.height / 2,
|
||||||
|
);
|
||||||
|
const interceptorLength =
|
||||||
|
pointDistance(adjacentPoint, edgePointAbsolute) +
|
||||||
|
pointDistance(adjacentPoint, center) +
|
||||||
|
Math.max(bindableElement.width, bindableElement.height) * 2;
|
||||||
|
const intersections = [
|
||||||
|
...intersectElementWithLineSegment(
|
||||||
|
bindableElement,
|
||||||
|
lineSegment<GlobalPoint>(
|
||||||
|
adjacentPoint,
|
||||||
|
pointFromVector(
|
||||||
|
vectorScale(
|
||||||
|
vectorNormalize(vectorFromPoint(focusPointAbsolute, adjacentPoint)),
|
||||||
|
interceptorLength,
|
||||||
|
),
|
||||||
|
adjacentPoint,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
FIXED_BINDING_DISTANCE,
|
||||||
|
).sort(
|
||||||
|
(g, h) =>
|
||||||
|
pointDistanceSq(g, adjacentPoint) - pointDistanceSq(h, adjacentPoint),
|
||||||
|
),
|
||||||
|
// Fallback when arrow doesn't point to the shape
|
||||||
|
pointFromVector(
|
||||||
|
vectorScale(
|
||||||
|
vectorNormalize(vectorFromPoint(focusPointAbsolute, adjacentPoint)),
|
||||||
|
pointDistance(adjacentPoint, edgePointAbsolute),
|
||||||
|
),
|
||||||
|
adjacentPoint,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (intersections.length > 1) {
|
||||||
|
// The adjacent point is outside the shape (+ gap)
|
||||||
|
newEdgePoint = intersections[0];
|
||||||
|
} else if (intersections.length === 1) {
|
||||||
|
// The adjacent point is inside the shape (+ gap)
|
||||||
newEdgePoint = focusPointAbsolute;
|
newEdgePoint = focusPointAbsolute;
|
||||||
} else {
|
} else {
|
||||||
const edgePointAbsolute =
|
// Shouldn't happend, but just in case
|
||||||
LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
newEdgePoint = edgePointAbsolute;
|
||||||
linearElement,
|
|
||||||
edgePointIndex,
|
|
||||||
elementsMap,
|
|
||||||
);
|
|
||||||
|
|
||||||
const center = pointFrom<GlobalPoint>(
|
|
||||||
bindableElement.x + bindableElement.width / 2,
|
|
||||||
bindableElement.y + bindableElement.height / 2,
|
|
||||||
);
|
|
||||||
const interceptorLength =
|
|
||||||
pointDistance(adjacentPoint, edgePointAbsolute) +
|
|
||||||
pointDistance(adjacentPoint, center) +
|
|
||||||
Math.max(bindableElement.width, bindableElement.height) * 2;
|
|
||||||
const intersections = [
|
|
||||||
...intersectElementWithLineSegment(
|
|
||||||
bindableElement,
|
|
||||||
lineSegment<GlobalPoint>(
|
|
||||||
adjacentPoint,
|
|
||||||
pointFromVector(
|
|
||||||
vectorScale(
|
|
||||||
vectorNormalize(
|
|
||||||
vectorFromPoint(focusPointAbsolute, adjacentPoint),
|
|
||||||
),
|
|
||||||
interceptorLength,
|
|
||||||
),
|
|
||||||
adjacentPoint,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
binding.gap,
|
|
||||||
).sort(
|
|
||||||
(g, h) =>
|
|
||||||
pointDistanceSq(g, adjacentPoint) - pointDistanceSq(h, adjacentPoint),
|
|
||||||
),
|
|
||||||
// Fallback when arrow doesn't point to the shape
|
|
||||||
pointFromVector(
|
|
||||||
vectorScale(
|
|
||||||
vectorNormalize(vectorFromPoint(focusPointAbsolute, adjacentPoint)),
|
|
||||||
pointDistance(adjacentPoint, edgePointAbsolute),
|
|
||||||
),
|
|
||||||
adjacentPoint,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
if (intersections.length > 1) {
|
|
||||||
// The adjacent point is outside the shape (+ gap)
|
|
||||||
newEdgePoint = intersections[0];
|
|
||||||
} else if (intersections.length === 1) {
|
|
||||||
// The adjacent point is inside the shape (+ gap)
|
|
||||||
newEdgePoint = focusPointAbsolute;
|
|
||||||
} else {
|
|
||||||
// Shouldn't happend, but just in case
|
|
||||||
newEdgePoint = edgePointAbsolute;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return LinearElementEditor.pointFromAbsoluteCoords(
|
return LinearElementEditor.pointFromAbsoluteCoords(
|
||||||
|
@ -1333,7 +1349,7 @@ const updateBoundPoint = (
|
||||||
};
|
};
|
||||||
|
|
||||||
export const calculateFixedPointForElbowArrowBinding = (
|
export const calculateFixedPointForElbowArrowBinding = (
|
||||||
linearElement: NonDeleted<ExcalidrawElbowArrowElement>,
|
linearElement: NonDeleted<ExcalidrawArrowElement>,
|
||||||
hoveredElement: ExcalidrawBindableElement,
|
hoveredElement: ExcalidrawBindableElement,
|
||||||
startOrEnd: "start" | "end",
|
startOrEnd: "start" | "end",
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
|
@ -1348,6 +1364,7 @@ export const calculateFixedPointForElbowArrowBinding = (
|
||||||
linearElement,
|
linearElement,
|
||||||
hoveredElement,
|
hoveredElement,
|
||||||
startOrEnd,
|
startOrEnd,
|
||||||
|
elementsMap,
|
||||||
);
|
);
|
||||||
const globalMidPoint = pointFrom(
|
const globalMidPoint = pointFrom(
|
||||||
bounds[0] + (bounds[2] - bounds[0]) / 2,
|
bounds[0] + (bounds[2] - bounds[0]) / 2,
|
||||||
|
@ -1369,28 +1386,6 @@ export const calculateFixedPointForElbowArrowBinding = (
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const maybeCalculateNewGapWhenScaling = (
|
|
||||||
changedElement: ExcalidrawBindableElement,
|
|
||||||
currentBinding: PointBinding | null | undefined,
|
|
||||||
newSize: { width: number; height: number } | undefined,
|
|
||||||
): PointBinding | null | undefined => {
|
|
||||||
if (currentBinding == null || newSize == null) {
|
|
||||||
return currentBinding;
|
|
||||||
}
|
|
||||||
const { width: newWidth, height: newHeight } = newSize;
|
|
||||||
const { width, height } = changedElement;
|
|
||||||
const newGap = Math.max(
|
|
||||||
1,
|
|
||||||
Math.min(
|
|
||||||
maxBindingGap(changedElement, newWidth, newHeight),
|
|
||||||
currentBinding.gap *
|
|
||||||
(newWidth < newHeight ? newWidth / width : newHeight / height),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return { ...currentBinding, gap: newGap };
|
|
||||||
};
|
|
||||||
|
|
||||||
const getElligibleElementForBindingElement = (
|
const getElligibleElementForBindingElement = (
|
||||||
linearElement: NonDeleted<ExcalidrawLinearElement>,
|
linearElement: NonDeleted<ExcalidrawLinearElement>,
|
||||||
startOrEnd: "start" | "end",
|
startOrEnd: "start" | "end",
|
||||||
|
|
|
@ -1254,6 +1254,7 @@ const getElbowArrowData = (
|
||||||
"start",
|
"start",
|
||||||
arrow.startBinding?.fixedPoint,
|
arrow.startBinding?.fixedPoint,
|
||||||
origStartGlobalPoint,
|
origStartGlobalPoint,
|
||||||
|
elementsMap,
|
||||||
hoveredStartElement,
|
hoveredStartElement,
|
||||||
options?.isDragging,
|
options?.isDragging,
|
||||||
);
|
);
|
||||||
|
@ -1267,6 +1268,7 @@ const getElbowArrowData = (
|
||||||
"end",
|
"end",
|
||||||
arrow.endBinding?.fixedPoint,
|
arrow.endBinding?.fixedPoint,
|
||||||
origEndGlobalPoint,
|
origEndGlobalPoint,
|
||||||
|
elementsMap,
|
||||||
hoveredEndElement,
|
hoveredEndElement,
|
||||||
options?.isDragging,
|
options?.isDragging,
|
||||||
);
|
);
|
||||||
|
@ -2212,6 +2214,7 @@ const getGlobalPoint = (
|
||||||
startOrEnd: "start" | "end",
|
startOrEnd: "start" | "end",
|
||||||
fixedPointRatio: [number, number] | undefined | null,
|
fixedPointRatio: [number, number] | undefined | null,
|
||||||
initialPoint: GlobalPoint,
|
initialPoint: GlobalPoint,
|
||||||
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
element?: ExcalidrawBindableElement | null,
|
element?: ExcalidrawBindableElement | null,
|
||||||
isDragging?: boolean,
|
isDragging?: boolean,
|
||||||
): GlobalPoint => {
|
): GlobalPoint => {
|
||||||
|
@ -2221,6 +2224,7 @@ const getGlobalPoint = (
|
||||||
arrow,
|
arrow,
|
||||||
element,
|
element,
|
||||||
startOrEnd,
|
startOrEnd,
|
||||||
|
elementsMap,
|
||||||
);
|
);
|
||||||
|
|
||||||
return snapToMid(element, snapPoint);
|
return snapToMid(element, snapPoint);
|
||||||
|
@ -2240,7 +2244,7 @@ const getGlobalPoint = (
|
||||||
distanceToBindableElement(element, fixedGlobalPoint) -
|
distanceToBindableElement(element, fixedGlobalPoint) -
|
||||||
FIXED_BINDING_DISTANCE,
|
FIXED_BINDING_DISTANCE,
|
||||||
) > 0.01
|
) > 0.01
|
||||||
? bindPointToSnapToElementOutline(arrow, element, startOrEnd)
|
? bindPointToSnapToElementOutline(arrow, element, startOrEnd, elementsMap)
|
||||||
: fixedGlobalPoint;
|
: fixedGlobalPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2268,7 +2272,6 @@ const getBindPointHeading = (
|
||||||
number,
|
number,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
elementsMap,
|
|
||||||
origPoint,
|
origPoint,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ import type { Mutable } from "@excalidraw/common/utility-types";
|
||||||
import {
|
import {
|
||||||
bindOrUnbindLinearElement,
|
bindOrUnbindLinearElement,
|
||||||
getHoveredElementForBinding,
|
getHoveredElementForBinding,
|
||||||
|
getOutlineAvoidingPoint,
|
||||||
isBindingEnabled,
|
isBindingEnabled,
|
||||||
} from "./binding";
|
} from "./binding";
|
||||||
import {
|
import {
|
||||||
|
@ -252,27 +253,28 @@ export class LinearElementEditor {
|
||||||
pointSceneCoords: { x: number; y: number }[],
|
pointSceneCoords: { x: number; y: number }[],
|
||||||
) => void,
|
) => void,
|
||||||
linearElementEditor: LinearElementEditor,
|
linearElementEditor: LinearElementEditor,
|
||||||
scene: Scene,
|
|
||||||
): LinearElementEditor | null {
|
): LinearElementEditor | null {
|
||||||
if (!linearElementEditor) {
|
if (!linearElementEditor) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const { elementId } = linearElementEditor;
|
const { elementId } = linearElementEditor;
|
||||||
const elementsMap = scene.getNonDeletedElementsMap();
|
const elementsMap = app.scene.getNonDeletedElementsMap();
|
||||||
const element = LinearElementEditor.getElement(elementId, elementsMap);
|
const element = LinearElementEditor.getElement(elementId, elementsMap);
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const elbowed = isElbowArrow(element);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isElbowArrow(element) &&
|
elbowed &&
|
||||||
!linearElementEditor.pointerDownState.lastClickedIsEndPoint &&
|
!linearElementEditor.pointerDownState.lastClickedIsEndPoint &&
|
||||||
linearElementEditor.pointerDownState.lastClickedPoint !== 0
|
linearElementEditor.pointerDownState.lastClickedPoint !== 0
|
||||||
) {
|
) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedPointsIndices = isElbowArrow(element)
|
const selectedPointsIndices = elbowed
|
||||||
? [
|
? [
|
||||||
!!linearElementEditor.selectedPointsIndices?.includes(0)
|
!!linearElementEditor.selectedPointsIndices?.includes(0)
|
||||||
? 0
|
? 0
|
||||||
|
@ -282,7 +284,7 @@ export class LinearElementEditor {
|
||||||
: undefined,
|
: undefined,
|
||||||
].filter((idx): idx is number => idx !== undefined)
|
].filter((idx): idx is number => idx !== undefined)
|
||||||
: linearElementEditor.selectedPointsIndices;
|
: linearElementEditor.selectedPointsIndices;
|
||||||
const lastClickedPoint = isElbowArrow(element)
|
const lastClickedPoint = elbowed
|
||||||
? linearElementEditor.pointerDownState.lastClickedPoint > 0
|
? linearElementEditor.pointerDownState.lastClickedPoint > 0
|
||||||
? element.points.length - 1
|
? element.points.length - 1
|
||||||
: 0
|
: 0
|
||||||
|
@ -334,19 +336,43 @@ export class LinearElementEditor {
|
||||||
LinearElementEditor.movePoints(
|
LinearElementEditor.movePoints(
|
||||||
element,
|
element,
|
||||||
selectedPointsIndices.map((pointIndex) => {
|
selectedPointsIndices.map((pointIndex) => {
|
||||||
const newPointPosition: LocalPoint =
|
let newPointPosition = pointFrom<LocalPoint>(
|
||||||
pointIndex === lastClickedPoint
|
element.points[pointIndex][0] + deltaX,
|
||||||
? LinearElementEditor.createPointAt(
|
element.points[pointIndex][1] + deltaY,
|
||||||
element,
|
);
|
||||||
elementsMap,
|
|
||||||
scenePointerX - linearElementEditor.pointerOffset.x,
|
// Check if point dragging is happening
|
||||||
scenePointerY - linearElementEditor.pointerOffset.y,
|
if (pointIndex === lastClickedPoint) {
|
||||||
event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(),
|
let globalNewPointPosition = pointFrom<GlobalPoint>(
|
||||||
)
|
scenePointerX - linearElementEditor.pointerOffset.x,
|
||||||
: pointFrom(
|
scenePointerY - linearElementEditor.pointerOffset.y,
|
||||||
element.points[pointIndex][0] + deltaX,
|
);
|
||||||
element.points[pointIndex][1] + deltaY,
|
|
||||||
);
|
if (
|
||||||
|
pointIndex === 0 ||
|
||||||
|
pointIndex === element.points.length - 1
|
||||||
|
) {
|
||||||
|
globalNewPointPosition = getOutlineAvoidingPoint(
|
||||||
|
element,
|
||||||
|
pointFrom<GlobalPoint>(
|
||||||
|
element.x + element.points[pointIndex][0] + deltaX,
|
||||||
|
element.y + element.points[pointIndex][1] + deltaY,
|
||||||
|
),
|
||||||
|
pointIndex,
|
||||||
|
app.scene,
|
||||||
|
app.state.zoom,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
newPointPosition = LinearElementEditor.createPointAt(
|
||||||
|
element,
|
||||||
|
elementsMap,
|
||||||
|
globalNewPointPosition[0],
|
||||||
|
globalNewPointPosition[1],
|
||||||
|
event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
index: pointIndex,
|
index: pointIndex,
|
||||||
point: newPointPosition,
|
point: newPointPosition,
|
||||||
|
|
|
@ -969,10 +969,7 @@ export const resizeSingleElement = (
|
||||||
|
|
||||||
mutateElement(latestElement, updates, shouldInformMutation);
|
mutateElement(latestElement, updates, shouldInformMutation);
|
||||||
|
|
||||||
updateBoundElements(latestElement, elementsMap as SceneElementsMap, {
|
updateBoundElements(latestElement, elementsMap as SceneElementsMap);
|
||||||
// TODO: confirm with MARK if this actually makes sense
|
|
||||||
newSize: { width: nextWidth, height: nextHeight },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (boundTextElement && boundTextFont != null) {
|
if (boundTextElement && boundTextFont != null) {
|
||||||
mutateElement(boundTextElement, {
|
mutateElement(boundTextElement, {
|
||||||
|
@ -1525,7 +1522,7 @@ export const resizeMultipleElements = (
|
||||||
element,
|
element,
|
||||||
update: { boundTextFontSize, ...update },
|
update: { boundTextFontSize, ...update },
|
||||||
} of elementsAndUpdates) {
|
} of elementsAndUpdates) {
|
||||||
const { width, height, angle } = update;
|
const { angle } = update;
|
||||||
|
|
||||||
mutateElement(element, update, false, {
|
mutateElement(element, update, false, {
|
||||||
// needed for the fixed binding point udpate to take effect
|
// needed for the fixed binding point udpate to take effect
|
||||||
|
@ -1534,7 +1531,6 @@ export const resizeMultipleElements = (
|
||||||
|
|
||||||
updateBoundElements(element, elementsMap as SceneElementsMap, {
|
updateBoundElements(element, elementsMap as SceneElementsMap, {
|
||||||
simultaneouslyUpdated: elementsToUpdate,
|
simultaneouslyUpdated: elementsToUpdate,
|
||||||
newSize: { width, height },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const boundTextElement = getBoundTextElement(element, elementsMap);
|
const boundTextElement = getBoundTextElement(element, elementsMap);
|
||||||
|
|
|
@ -190,7 +190,18 @@ describe("element binding", () => {
|
||||||
|
|
||||||
// Sever connection
|
// Sever connection
|
||||||
expect(API.getSelectedElement().type).toBe("arrow");
|
expect(API.getSelectedElement().type).toBe("arrow");
|
||||||
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
Keyboard.withModifierKeys({ shift: true }, () => {
|
||||||
|
// We have to move a significant distance to get out of the binding zone
|
||||||
|
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
||||||
|
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
||||||
|
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
||||||
|
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
||||||
|
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
||||||
|
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
||||||
|
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
||||||
|
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
||||||
|
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
||||||
|
});
|
||||||
expect(arrow.endBinding).toBe(null);
|
expect(arrow.endBinding).toBe(null);
|
||||||
Keyboard.keyPress(KEYS.ARROW_RIGHT);
|
Keyboard.keyPress(KEYS.ARROW_RIGHT);
|
||||||
expect(arrow.endBinding).toBe(null);
|
expect(arrow.endBinding).toBe(null);
|
||||||
|
|
|
@ -195,7 +195,7 @@ describe("generic element", () => {
|
||||||
UI.resize(rectangle, "w", [50, 0]);
|
UI.resize(rectangle, "w", [50, 0]);
|
||||||
|
|
||||||
expect(arrow.endBinding?.elementId).toEqual(rectangle.id);
|
expect(arrow.endBinding?.elementId).toEqual(rectangle.id);
|
||||||
expect(arrow.width + arrow.endBinding!.gap).toBeCloseTo(80, 0);
|
expect(arrow.width + arrow.endBinding!.gap).toBeCloseTo(81, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("resizes with a label", async () => {
|
it("resizes with a label", async () => {
|
||||||
|
@ -826,8 +826,9 @@ describe("image element", () => {
|
||||||
UI.resize(image, "nw", [50, 20]);
|
UI.resize(image, "nw", [50, 20]);
|
||||||
|
|
||||||
expect(arrow.endBinding?.elementId).toEqual(image.id);
|
expect(arrow.endBinding?.elementId).toEqual(image.id);
|
||||||
expect(Math.floor(arrow.width + arrow.endBinding!.gap)).toBeCloseTo(
|
|
||||||
30 + imageWidth * scale,
|
expect(arrow.width + arrow.endBinding!.gap).toBeCloseTo(
|
||||||
|
30 + imageWidth * scale + 1,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1033,11 +1034,11 @@ describe("multiple selection", () => {
|
||||||
|
|
||||||
expect(leftBoundArrow.x).toBeCloseTo(-110);
|
expect(leftBoundArrow.x).toBeCloseTo(-110);
|
||||||
expect(leftBoundArrow.y).toBeCloseTo(50);
|
expect(leftBoundArrow.y).toBeCloseTo(50);
|
||||||
expect(leftBoundArrow.width).toBeCloseTo(143, 0);
|
expect(leftBoundArrow.width).toBeCloseTo(146, 0);
|
||||||
expect(leftBoundArrow.height).toBeCloseTo(7, 0);
|
expect(leftBoundArrow.height).toBeCloseTo(7, 0);
|
||||||
expect(leftBoundArrow.angle).toEqual(0);
|
expect(leftBoundArrow.angle).toEqual(0);
|
||||||
expect(leftBoundArrow.startBinding).toBeNull();
|
expect(leftBoundArrow.startBinding).toBeNull();
|
||||||
expect(leftBoundArrow.endBinding?.gap).toBeCloseTo(10);
|
expect(leftBoundArrow.endBinding?.gap).toBeCloseTo(5);
|
||||||
expect(leftBoundArrow.endBinding?.elementId).toBe(
|
expect(leftBoundArrow.endBinding?.elementId).toBe(
|
||||||
leftArrowBinding.elementId,
|
leftArrowBinding.elementId,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { pointFrom } from "@excalidraw/math";
|
import { type GlobalPoint, pointFrom } from "@excalidraw/math";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
maybeBindLinearElement,
|
maybeBindLinearElement,
|
||||||
|
@ -91,10 +91,26 @@ export const actionFinalize = register({
|
||||||
multiPointElement.type !== "freedraw" &&
|
multiPointElement.type !== "freedraw" &&
|
||||||
appState.lastPointerDownWith !== "touch"
|
appState.lastPointerDownWith !== "touch"
|
||||||
) {
|
) {
|
||||||
const { points, lastCommittedPoint } = multiPointElement;
|
const { x: rx, y: ry, points, lastCommittedPoint } = multiPointElement;
|
||||||
|
const lastGlobalPoint = pointFrom<GlobalPoint>(
|
||||||
|
rx + points[points.length - 1][0],
|
||||||
|
ry + points[points.length - 1][1],
|
||||||
|
);
|
||||||
|
const hoveredElementForBinding = getHoveredElementForBinding(
|
||||||
|
{
|
||||||
|
x: lastGlobalPoint[0],
|
||||||
|
y: lastGlobalPoint[1],
|
||||||
|
},
|
||||||
|
elements,
|
||||||
|
elementsMap,
|
||||||
|
app.state.zoom,
|
||||||
|
true,
|
||||||
|
isElbowArrow(multiPointElement),
|
||||||
|
);
|
||||||
if (
|
if (
|
||||||
!lastCommittedPoint ||
|
!hoveredElementForBinding &&
|
||||||
points[points.length - 1] !== lastCommittedPoint
|
(!lastCommittedPoint ||
|
||||||
|
points[points.length - 1] !== lastCommittedPoint)
|
||||||
) {
|
) {
|
||||||
mutateElement(multiPointElement, {
|
mutateElement(multiPointElement, {
|
||||||
points: multiPointElement.points.slice(0, -1),
|
points: multiPointElement.points.slice(0, -1),
|
||||||
|
|
|
@ -1655,6 +1655,7 @@ export const actionChangeArrowType = register({
|
||||||
newElement,
|
newElement,
|
||||||
startHoveredElement,
|
startHoveredElement,
|
||||||
"start",
|
"start",
|
||||||
|
elementsMap,
|
||||||
)
|
)
|
||||||
: startGlobalPoint;
|
: startGlobalPoint;
|
||||||
const finalEndPoint = endHoveredElement
|
const finalEndPoint = endHoveredElement
|
||||||
|
@ -1662,6 +1663,7 @@ export const actionChangeArrowType = register({
|
||||||
newElement,
|
newElement,
|
||||||
endHoveredElement,
|
endHoveredElement,
|
||||||
"end",
|
"end",
|
||||||
|
elementsMap,
|
||||||
)
|
)
|
||||||
: endGlobalPoint;
|
: endGlobalPoint;
|
||||||
|
|
||||||
|
|
|
@ -1508,9 +1508,7 @@ export class ElementsChange implements Change<SceneElementsMap> {
|
||||||
) {
|
) {
|
||||||
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, elements);
|
||||||
changedElements: changed,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
vectorSubtract,
|
vectorSubtract,
|
||||||
vectorDot,
|
vectorDot,
|
||||||
vectorNormalize,
|
vectorNormalize,
|
||||||
|
lineSegment,
|
||||||
} from "@excalidraw/math";
|
} from "@excalidraw/math";
|
||||||
import { isPointInShape } from "@excalidraw/utils/collision";
|
import { isPointInShape } from "@excalidraw/utils/collision";
|
||||||
import { getSelectionBoxShape } from "@excalidraw/utils/shape";
|
import { getSelectionBoxShape } from "@excalidraw/utils/shape";
|
||||||
|
@ -302,7 +303,7 @@ import {
|
||||||
|
|
||||||
import { isNonDeletedElement } from "@excalidraw/element";
|
import { isNonDeletedElement } from "@excalidraw/element";
|
||||||
|
|
||||||
import type { LocalPoint, Radians } from "@excalidraw/math";
|
import type { GlobalPoint, LocalPoint, Radians } from "@excalidraw/math";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ExcalidrawBindableElement,
|
ExcalidrawBindableElement,
|
||||||
|
@ -5997,9 +5998,19 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
{
|
{
|
||||||
points: [
|
points: [
|
||||||
...points.slice(0, -1),
|
...points.slice(0, -1),
|
||||||
pointFrom<LocalPoint>(
|
toLocalPoint(
|
||||||
lastCommittedX + dxFromLastCommitted,
|
getOutlineAvoidingPoint(
|
||||||
lastCommittedY + dyFromLastCommitted,
|
multiElement,
|
||||||
|
pointFrom<GlobalPoint>(scenePointerX, scenePointerY),
|
||||||
|
multiElement.points.length - 1,
|
||||||
|
this.scene,
|
||||||
|
this.state.zoom,
|
||||||
|
pointFrom<GlobalPoint>(
|
||||||
|
multiElement.x + lastCommittedX + dxFromLastCommitted,
|
||||||
|
multiElement.y + lastCommittedY + dyFromLastCommitted,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
multiElement,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -7751,18 +7762,34 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { x: rx, y: ry, lastCommittedPoint } = multiElement;
|
const { x: rx, y: ry, lastCommittedPoint } = multiElement;
|
||||||
|
const lastGlobalPoint = pointFrom<GlobalPoint>(
|
||||||
|
rx + multiElement.points[multiElement.points.length - 1][0],
|
||||||
|
ry + multiElement.points[multiElement.points.length - 1][1],
|
||||||
|
);
|
||||||
|
const hoveredElementForBinding = getHoveredElementForBinding(
|
||||||
|
{
|
||||||
|
x: lastGlobalPoint[0],
|
||||||
|
y: lastGlobalPoint[1],
|
||||||
|
},
|
||||||
|
this.scene.getNonDeletedElements(),
|
||||||
|
this.scene.getNonDeletedElementsMap(),
|
||||||
|
this.state.zoom,
|
||||||
|
true,
|
||||||
|
isElbowArrow(multiElement),
|
||||||
|
);
|
||||||
|
|
||||||
// clicking inside commit zone → finalize arrow
|
// clicking inside commit zone → finalize arrow
|
||||||
if (
|
if (
|
||||||
multiElement.points.length > 1 &&
|
hoveredElementForBinding ||
|
||||||
lastCommittedPoint &&
|
(multiElement.points.length > 1 &&
|
||||||
pointDistance(
|
lastCommittedPoint &&
|
||||||
pointFrom(
|
pointDistance(
|
||||||
pointerDownState.origin.x - rx,
|
pointFrom(
|
||||||
pointerDownState.origin.y - ry,
|
pointerDownState.origin.x - rx,
|
||||||
),
|
pointerDownState.origin.y - ry,
|
||||||
lastCommittedPoint,
|
),
|
||||||
) < LINE_CONFIRM_THRESHOLD
|
lastCommittedPoint,
|
||||||
|
) < LINE_CONFIRM_THRESHOLD)
|
||||||
) {
|
) {
|
||||||
this.actionManager.executeAction(actionFinalize);
|
this.actionManager.executeAction(actionFinalize);
|
||||||
return;
|
return;
|
||||||
|
@ -7806,53 +7833,92 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
? [currentItemStartArrowhead, currentItemEndArrowhead]
|
? [currentItemStartArrowhead, currentItemEndArrowhead]
|
||||||
: [null, null];
|
: [null, null];
|
||||||
|
|
||||||
const element =
|
let element: NonDeleted<ExcalidrawLinearElement>;
|
||||||
elementType === "arrow"
|
if (elementType === "arrow") {
|
||||||
? newArrowElement({
|
const arrow: Mutable<NonDeleted<ExcalidrawArrowElement>> =
|
||||||
type: elementType,
|
newArrowElement({
|
||||||
x: gridX,
|
type: "arrow",
|
||||||
y: gridY,
|
x: gridX,
|
||||||
strokeColor: this.state.currentItemStrokeColor,
|
y: gridY,
|
||||||
backgroundColor: this.state.currentItemBackgroundColor,
|
strokeColor: this.state.currentItemStrokeColor,
|
||||||
fillStyle: this.state.currentItemFillStyle,
|
backgroundColor: this.state.currentItemBackgroundColor,
|
||||||
strokeWidth: this.state.currentItemStrokeWidth,
|
fillStyle: this.state.currentItemFillStyle,
|
||||||
strokeStyle: this.state.currentItemStrokeStyle,
|
strokeWidth: this.state.currentItemStrokeWidth,
|
||||||
roughness: this.state.currentItemRoughness,
|
strokeStyle: this.state.currentItemStrokeStyle,
|
||||||
opacity: this.state.currentItemOpacity,
|
roughness: this.state.currentItemRoughness,
|
||||||
roundness:
|
opacity: this.state.currentItemOpacity,
|
||||||
this.state.currentItemArrowType === ARROW_TYPE.round
|
roundness:
|
||||||
? { type: ROUNDNESS.PROPORTIONAL_RADIUS }
|
this.state.currentItemArrowType === ARROW_TYPE.round
|
||||||
: // note, roundness doesn't have any effect for elbow arrows,
|
? { type: ROUNDNESS.PROPORTIONAL_RADIUS }
|
||||||
// but it's best to set it to null as well
|
: // note, roundness doesn't have any effect for elbow arrows,
|
||||||
null,
|
// but it's best to set it to null as well
|
||||||
startArrowhead,
|
null,
|
||||||
endArrowhead,
|
startArrowhead,
|
||||||
locked: false,
|
endArrowhead,
|
||||||
frameId: topLayerFrame ? topLayerFrame.id : null,
|
locked: false,
|
||||||
elbowed: this.state.currentItemArrowType === ARROW_TYPE.elbow,
|
frameId: topLayerFrame ? topLayerFrame.id : null,
|
||||||
fixedSegments:
|
elbowed: this.state.currentItemArrowType === ARROW_TYPE.elbow,
|
||||||
this.state.currentItemArrowType === ARROW_TYPE.elbow
|
fixedSegments:
|
||||||
? []
|
this.state.currentItemArrowType === ARROW_TYPE.elbow ? [] : null,
|
||||||
: null,
|
});
|
||||||
})
|
|
||||||
: newLinearElement({
|
const hoveredElement = getHoveredElementForBinding(
|
||||||
type: elementType,
|
{ x: gridX, y: gridY },
|
||||||
x: gridX,
|
this.scene.getNonDeletedElements(),
|
||||||
y: gridY,
|
this.scene.getNonDeletedElementsMap(),
|
||||||
strokeColor: this.state.currentItemStrokeColor,
|
this.state.zoom,
|
||||||
backgroundColor: this.state.currentItemBackgroundColor,
|
true,
|
||||||
fillStyle: this.state.currentItemFillStyle,
|
this.state.currentItemArrowType === ARROW_TYPE.elbow,
|
||||||
strokeWidth: this.state.currentItemStrokeWidth,
|
);
|
||||||
strokeStyle: this.state.currentItemStrokeStyle,
|
|
||||||
roughness: this.state.currentItemRoughness,
|
if (hoveredElement) {
|
||||||
opacity: this.state.currentItemOpacity,
|
[arrow.x, arrow.y] =
|
||||||
roundness:
|
intersectElementWithLineSegment(
|
||||||
this.state.currentItemRoundness === "round"
|
hoveredElement,
|
||||||
? { type: ROUNDNESS.PROPORTIONAL_RADIUS }
|
lineSegment(
|
||||||
: null,
|
pointFrom<GlobalPoint>(gridX, gridY),
|
||||||
locked: false,
|
pointFrom<GlobalPoint>(
|
||||||
frameId: topLayerFrame ? topLayerFrame.id : null,
|
gridX,
|
||||||
});
|
hoveredElement.y + hoveredElement.height / 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
2 * FIXED_BINDING_DISTANCE,
|
||||||
|
)[0] ??
|
||||||
|
intersectElementWithLineSegment(
|
||||||
|
hoveredElement,
|
||||||
|
lineSegment(
|
||||||
|
pointFrom<GlobalPoint>(gridX, gridY),
|
||||||
|
pointFrom<GlobalPoint>(
|
||||||
|
hoveredElement.x + hoveredElement.width / 2,
|
||||||
|
gridY,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
2 * FIXED_BINDING_DISTANCE,
|
||||||
|
)[0] ??
|
||||||
|
pointFrom<GlobalPoint>(gridX, gridY);
|
||||||
|
}
|
||||||
|
|
||||||
|
element = arrow;
|
||||||
|
} else {
|
||||||
|
element = newLinearElement({
|
||||||
|
type: elementType,
|
||||||
|
x: gridX,
|
||||||
|
y: gridY,
|
||||||
|
strokeColor: this.state.currentItemStrokeColor,
|
||||||
|
backgroundColor: this.state.currentItemBackgroundColor,
|
||||||
|
fillStyle: this.state.currentItemFillStyle,
|
||||||
|
strokeWidth: this.state.currentItemStrokeWidth,
|
||||||
|
strokeStyle: this.state.currentItemStrokeStyle,
|
||||||
|
roughness: this.state.currentItemRoughness,
|
||||||
|
opacity: this.state.currentItemOpacity,
|
||||||
|
roundness:
|
||||||
|
this.state.currentItemRoundness === "round"
|
||||||
|
? { type: ROUNDNESS.PROPORTIONAL_RADIUS }
|
||||||
|
: null,
|
||||||
|
locked: false,
|
||||||
|
frameId: topLayerFrame ? topLayerFrame.id : null,
|
||||||
|
});
|
||||||
|
}
|
||||||
this.setState((prevState) => {
|
this.setState((prevState) => {
|
||||||
const nextSelectedElementIds = {
|
const nextSelectedElementIds = {
|
||||||
...prevState.selectedElementIds,
|
...prevState.selectedElementIds,
|
||||||
|
@ -8167,12 +8233,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
this.laserTrails.addPointToPath(pointerCoords.x, pointerCoords.y);
|
this.laserTrails.addPointToPath(pointerCoords.x, pointerCoords.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [gridX, gridY] = getGridPoint(
|
|
||||||
pointerCoords.x,
|
|
||||||
pointerCoords.y,
|
|
||||||
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// for arrows/lines, don't start dragging until a given threshold
|
// for arrows/lines, don't start dragging until a given threshold
|
||||||
// to ensure we don't create a 2-point arrow by mistake when
|
// to ensure we don't create a 2-point arrow by mistake when
|
||||||
// user clicks mouse in a way that it moves a tiny bit (thus
|
// user clicks mouse in a way that it moves a tiny bit (thus
|
||||||
|
@ -8273,7 +8333,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
linearElementEditor,
|
linearElementEditor,
|
||||||
this.scene,
|
|
||||||
);
|
);
|
||||||
if (newLinearElementEditor) {
|
if (newLinearElementEditor) {
|
||||||
pointerDownState.lastCoords.x = pointerCoords.x;
|
pointerDownState.lastCoords.x = pointerCoords.x;
|
||||||
|
@ -8660,6 +8719,11 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
} else if (isLinearElement(newElement)) {
|
} else if (isLinearElement(newElement)) {
|
||||||
pointerDownState.drag.hasOccurred = true;
|
pointerDownState.drag.hasOccurred = true;
|
||||||
const points = newElement.points;
|
const points = newElement.points;
|
||||||
|
const [gridX, gridY] = getGridPoint(
|
||||||
|
pointerCoords.x,
|
||||||
|
pointerCoords.y,
|
||||||
|
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
|
||||||
|
);
|
||||||
let dx = gridX - newElement.x;
|
let dx = gridX - newElement.x;
|
||||||
let dy = gridY - newElement.y;
|
let dy = gridY - newElement.y;
|
||||||
|
|
||||||
|
@ -8676,7 +8740,23 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
mutateElement(
|
mutateElement(
|
||||||
newElement,
|
newElement,
|
||||||
{
|
{
|
||||||
points: [...points, pointFrom<LocalPoint>(dx, dy)],
|
points: [
|
||||||
|
...points,
|
||||||
|
toLocalPoint(
|
||||||
|
getOutlineAvoidingPoint(
|
||||||
|
newElement,
|
||||||
|
pointFrom<GlobalPoint>(pointerCoords.x, pointerCoords.y),
|
||||||
|
newElement.points.length - 1,
|
||||||
|
this.scene,
|
||||||
|
this.state.zoom,
|
||||||
|
pointFrom<GlobalPoint>(
|
||||||
|
newElement.x + dx,
|
||||||
|
newElement.y + dy,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
newElement,
|
||||||
|
),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -8687,7 +8767,23 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
mutateElement(
|
mutateElement(
|
||||||
newElement,
|
newElement,
|
||||||
{
|
{
|
||||||
points: [...points.slice(0, -1), pointFrom<LocalPoint>(dx, dy)],
|
points: [
|
||||||
|
...points.slice(0, -1),
|
||||||
|
toLocalPoint(
|
||||||
|
getOutlineAvoidingPoint(
|
||||||
|
newElement,
|
||||||
|
pointFrom<GlobalPoint>(pointerCoords.x, pointerCoords.y),
|
||||||
|
newElement.points.length - 1,
|
||||||
|
this.scene,
|
||||||
|
this.state.zoom,
|
||||||
|
pointFrom<GlobalPoint>(
|
||||||
|
newElement.x + dx,
|
||||||
|
newElement.y + dy,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
newElement,
|
||||||
|
),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
{ isDragging: true },
|
{ isDragging: true },
|
||||||
|
@ -10725,12 +10821,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
updateBoundElements(
|
updateBoundElements(
|
||||||
croppingElement,
|
croppingElement,
|
||||||
this.scene.getNonDeletedElementsMap(),
|
this.scene.getNonDeletedElementsMap(),
|
||||||
{
|
|
||||||
newSize: {
|
|
||||||
width: croppingElement.width,
|
|
||||||
height: croppingElement.height,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
|
|
|
@ -87,9 +87,7 @@ const resizeElementInGroup = (
|
||||||
);
|
);
|
||||||
if (boundTextElement) {
|
if (boundTextElement) {
|
||||||
const newFontSize = boundTextElement.fontSize * scale;
|
const newFontSize = boundTextElement.fontSize * scale;
|
||||||
updateBoundElements(latestElement, elementsMap, {
|
updateBoundElements(latestElement, elementsMap);
|
||||||
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(
|
mutateElement(
|
||||||
|
|
|
@ -89,7 +89,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "ellipse-1",
|
"elementId": "ellipse-1",
|
||||||
"focus": -0.007519379844961235,
|
"focus": -0.007519379844961235,
|
||||||
"gap": 11.562288374879595,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -119,7 +119,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id49",
|
"elementId": "id49",
|
||||||
"focus": -0.0813953488372095,
|
"focus": -0.0813953488372095,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1864ab",
|
"strokeColor": "#1864ab",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
|
@ -145,7 +145,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "ellipse-1",
|
"elementId": "ellipse-1",
|
||||||
"focus": 0.10666666666666667,
|
"focus": 0.10666666666666667,
|
||||||
"gap": 3.8343264684446097,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -175,7 +175,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "diamond-1",
|
"elementId": "diamond-1",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 4.545343408287929,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#e67700",
|
"strokeColor": "#e67700",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
|
@ -335,7 +335,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "text-2",
|
"elementId": "text-2",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 14,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -365,7 +365,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "text-1",
|
"elementId": "text-1",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1e1e1e",
|
"strokeColor": "#1e1e1e",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
|
@ -437,7 +437,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id42",
|
"elementId": "id42",
|
||||||
"focus": -0,
|
"focus": -0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -467,7 +467,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id41",
|
"elementId": "id41",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1e1e1e",
|
"strokeColor": "#1e1e1e",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
|
@ -613,7 +613,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id46",
|
"elementId": "id46",
|
||||||
"focus": -0,
|
"focus": -0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -643,7 +643,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id45",
|
"elementId": "id45",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1e1e1e",
|
"strokeColor": "#1e1e1e",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
|
@ -1475,7 +1475,7 @@ exports[`Test Transform > should transform the elements correctly when linear el
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "Alice",
|
"elementId": "Alice",
|
||||||
"focus": -0,
|
"focus": -0,
|
||||||
"gap": 5.299874999999986,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -1507,7 +1507,7 @@ exports[`Test Transform > should transform the elements correctly when linear el
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "Bob",
|
"elementId": "Bob",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1e1e1e",
|
"strokeColor": "#1e1e1e",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
|
@ -1538,7 +1538,7 @@ exports[`Test Transform > should transform the elements correctly when linear el
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "B",
|
"elementId": "B",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 14,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -1566,7 +1566,7 @@ exports[`Test Transform > should transform the elements correctly when linear el
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "Bob",
|
"elementId": "Bob",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1e1e1e",
|
"strokeColor": "#1e1e1e",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
|
|
|
@ -433,7 +433,7 @@ describe("Test Transform", () => {
|
||||||
startBinding: {
|
startBinding: {
|
||||||
elementId: rectangle.id,
|
elementId: rectangle.id,
|
||||||
focus: 0,
|
focus: 0,
|
||||||
gap: 1,
|
gap: FIXED_BINDING_DISTANCE,
|
||||||
},
|
},
|
||||||
endBinding: {
|
endBinding: {
|
||||||
elementId: ellipse.id,
|
elementId: ellipse.id,
|
||||||
|
@ -518,7 +518,7 @@ describe("Test Transform", () => {
|
||||||
startBinding: {
|
startBinding: {
|
||||||
elementId: text2.id,
|
elementId: text2.id,
|
||||||
focus: 0,
|
focus: 0,
|
||||||
gap: 1,
|
gap: FIXED_BINDING_DISTANCE,
|
||||||
},
|
},
|
||||||
endBinding: {
|
endBinding: {
|
||||||
elementId: text3.id,
|
elementId: text3.id,
|
||||||
|
@ -781,7 +781,7 @@ describe("Test Transform", () => {
|
||||||
expect((arrow as ExcalidrawArrowElement).endBinding).toStrictEqual({
|
expect((arrow as ExcalidrawArrowElement).endBinding).toStrictEqual({
|
||||||
elementId: "rect-1",
|
elementId: "rect-1",
|
||||||
focus: -0,
|
focus: -0,
|
||||||
gap: 14,
|
gap: FIXED_BINDING_DISTANCE,
|
||||||
});
|
});
|
||||||
expect(rect.boundElements).toStrictEqual([
|
expect(rect.boundElements).toStrictEqual([
|
||||||
{
|
{
|
||||||
|
|
|
@ -198,7 +198,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": "102.35417",
|
"height": "99.58947",
|
||||||
"id": "id172",
|
"id": "id172",
|
||||||
"index": "a2",
|
"index": "a2",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
|
@ -212,8 +212,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"101.77517",
|
"99.58947",
|
||||||
"102.35417",
|
"99.58947",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
@ -228,8 +228,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 40,
|
"version": 40,
|
||||||
"width": "101.77517",
|
"width": "99.58947",
|
||||||
"x": "0.70711",
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -295,47 +295,47 @@ History {
|
||||||
"deleted": {
|
"deleted": {
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id171",
|
"elementId": "id171",
|
||||||
"focus": "0.00990",
|
"focus": "0.01099",
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"height": "0.98586",
|
"height": "0.96335",
|
||||||
"points": [
|
"points": [
|
||||||
[
|
[
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"98.58579",
|
"92.92893",
|
||||||
"-0.98586",
|
"-0.96335",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id170",
|
"elementId": "id170",
|
||||||
"focus": "0.02970",
|
"focus": "0.03005",
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id171",
|
"elementId": "id171",
|
||||||
"focus": "-0.02000",
|
"focus": "-0.02041",
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"height": "0.00000",
|
"height": "0.03665",
|
||||||
"points": [
|
"points": [
|
||||||
[
|
[
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"98.58579",
|
"92.92893",
|
||||||
"0.00000",
|
"0.03665",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id170",
|
"elementId": "id170",
|
||||||
"focus": "0.02000",
|
"focus": "0.01884",
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -390,43 +390,47 @@ History {
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 1,
|
||||||
},
|
},
|
||||||
"height": "102.35417",
|
"height": "99.58947",
|
||||||
"points": [
|
"points": [
|
||||||
[
|
[
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"101.77517",
|
"99.58947",
|
||||||
"102.35417",
|
"99.58947",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": null,
|
"startBinding": null,
|
||||||
|
"width": "99.58947",
|
||||||
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id171",
|
"elementId": "id171",
|
||||||
"focus": "0.00990",
|
"focus": "0.01099",
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"height": "0.98586",
|
"height": "0.96335",
|
||||||
"points": [
|
"points": [
|
||||||
[
|
[
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"98.58579",
|
"92.92893",
|
||||||
"-0.98586",
|
"-0.96335",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id170",
|
"elementId": "id170",
|
||||||
"focus": "0.02970",
|
"focus": "0.03005",
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"y": "0.99364",
|
"width": "92.92893",
|
||||||
|
"x": "3.53553",
|
||||||
|
"y": "0.96335",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"id175" => Delta {
|
"id175" => Delta {
|
||||||
|
@ -566,7 +570,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"96.46447",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -580,7 +584,7 @@ History {
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": 100,
|
"width": "96.46447",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
|
@ -804,7 +808,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"96.46447",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -820,8 +824,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 30,
|
"version": 30,
|
||||||
"width": 0,
|
"width": "96.46447",
|
||||||
"x": "149.29289",
|
"x": 150,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -854,7 +858,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0,
|
"0.00000",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -866,7 +870,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -921,17 +925,19 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"96.46447",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": null,
|
"startBinding": null,
|
||||||
|
"width": "96.46447",
|
||||||
|
"x": 150,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id166",
|
"elementId": "id166",
|
||||||
"focus": -0,
|
"focus": -0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"points": [
|
"points": [
|
||||||
[
|
[
|
||||||
|
@ -939,15 +945,17 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0,
|
"0.00000",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id165",
|
"elementId": "id165",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
|
"width": "0.00000",
|
||||||
|
"x": "146.46447",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1074,7 +1082,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"96.46447",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -1088,7 +1096,7 @@ History {
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": 100,
|
"width": "96.46447",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
|
@ -1241,7 +1249,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": "1.30038",
|
"height": "1.71911",
|
||||||
"id": "id178",
|
"id": "id178",
|
||||||
"index": "Zz",
|
"index": "Zz",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
|
@ -1255,8 +1263,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"98.58579",
|
"92.92893",
|
||||||
"1.30038",
|
"1.71911",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
@ -1279,8 +1287,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 11,
|
"version": 11,
|
||||||
"width": "98.58579",
|
"width": "92.92893",
|
||||||
"x": "0.70711",
|
"x": "3.53553",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -1613,7 +1621,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": "1.30038",
|
"height": "1.71911",
|
||||||
"id": "id181",
|
"id": "id181",
|
||||||
"index": "a0",
|
"index": "a0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
|
@ -1627,8 +1635,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"98.58579",
|
"92.92893",
|
||||||
"1.30038",
|
"1.71911",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
@ -1651,8 +1659,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 11,
|
"version": 11,
|
||||||
"width": "98.58579",
|
"width": "92.92893",
|
||||||
"x": "0.70711",
|
"x": "3.53553",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -1771,7 +1779,7 @@ History {
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": "11.27227",
|
"height": "12.86717",
|
||||||
"index": "a0",
|
"index": "a0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"lastCommittedPoint": null,
|
"lastCommittedPoint": null,
|
||||||
|
@ -1784,8 +1792,8 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"98.58579",
|
"92.92893",
|
||||||
"11.27227",
|
"12.86717",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
@ -1806,8 +1814,8 @@ History {
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": "98.58579",
|
"width": "92.92893",
|
||||||
"x": "0.70711",
|
"x": "3.53553",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
@ -2321,12 +2329,12 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id185",
|
"elementId": "id185",
|
||||||
"focus": -0,
|
"focus": -0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": "374.05754",
|
"height": "369.21589",
|
||||||
"id": "id186",
|
"id": "id186",
|
||||||
"index": "a2",
|
"index": "a2",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
|
@ -2340,8 +2348,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"502.78936",
|
"496.84035",
|
||||||
"-374.05754",
|
"-369.21589",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
@ -2352,7 +2360,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id184",
|
"elementId": "id184",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1e1e1e",
|
"strokeColor": "#1e1e1e",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
|
@ -2360,9 +2368,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 10,
|
"version": 10,
|
||||||
"width": "502.78936",
|
"width": "496.84035",
|
||||||
"x": "-0.83465",
|
"x": "2.18463",
|
||||||
"y": "-36.58211",
|
"y": "-38.80748",
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -2481,7 +2489,7 @@ History {
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id185",
|
"elementId": "id185",
|
||||||
"focus": -0,
|
"focus": -0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -2499,7 +2507,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"96.46447",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -2511,13 +2519,13 @@ History {
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id184",
|
"elementId": "id184",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1e1e1e",
|
"strokeColor": "#1e1e1e",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": 100,
|
"width": "96.46447",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
|
@ -15161,7 +15169,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id58",
|
"elementId": "id58",
|
||||||
"focus": -0,
|
"focus": -0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -15180,7 +15188,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"98.58579",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -15192,7 +15200,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id56",
|
"elementId": "id56",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1e1e1e",
|
"strokeColor": "#1e1e1e",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
|
@ -15200,8 +15208,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 10,
|
"version": 10,
|
||||||
"width": "98.58579",
|
"width": "92.92893",
|
||||||
"x": "0.70711",
|
"x": "3.53553",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -15242,7 +15250,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"96.46447",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -15255,7 +15263,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"96.46447",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -15532,7 +15540,7 @@ History {
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id58",
|
"elementId": "id58",
|
||||||
"focus": -0,
|
"focus": -0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -15550,7 +15558,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"96.46447",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -15562,13 +15570,13 @@ History {
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id56",
|
"elementId": "id56",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1e1e1e",
|
"strokeColor": "#1e1e1e",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": 100,
|
"width": "96.46447",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
|
@ -15859,7 +15867,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id52",
|
"elementId": "id52",
|
||||||
"focus": -0,
|
"focus": -0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -15878,7 +15886,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"98.58579",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -15890,7 +15898,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id50",
|
"elementId": "id50",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1e1e1e",
|
"strokeColor": "#1e1e1e",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
|
@ -15898,8 +15906,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 10,
|
"version": 10,
|
||||||
"width": "98.58579",
|
"width": "92.92893",
|
||||||
"x": "0.70711",
|
"x": "3.53553",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -16152,7 +16160,7 @@ History {
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id52",
|
"elementId": "id52",
|
||||||
"focus": -0,
|
"focus": -0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -16170,7 +16178,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"96.46447",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -16182,13 +16190,13 @@ History {
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id50",
|
"elementId": "id50",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1e1e1e",
|
"strokeColor": "#1e1e1e",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": 100,
|
"width": "96.46447",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
|
@ -16479,7 +16487,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id64",
|
"elementId": "id64",
|
||||||
"focus": -0,
|
"focus": -0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -16498,7 +16506,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"98.58579",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -16510,7 +16518,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id62",
|
"elementId": "id62",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1e1e1e",
|
"strokeColor": "#1e1e1e",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
|
@ -16518,8 +16526,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 10,
|
"version": 10,
|
||||||
"width": "98.58579",
|
"width": "92.92893",
|
||||||
"x": "0.70711",
|
"x": "3.53553",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -16772,7 +16780,7 @@ History {
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id64",
|
"elementId": "id64",
|
||||||
"focus": -0,
|
"focus": -0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -16790,7 +16798,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"96.46447",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -16802,13 +16810,13 @@ History {
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id62",
|
"elementId": "id62",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1e1e1e",
|
"strokeColor": "#1e1e1e",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": 100,
|
"width": "96.46447",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
|
@ -17097,7 +17105,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id70",
|
"elementId": "id70",
|
||||||
"focus": -0,
|
"focus": -0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -17116,7 +17124,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"98.58579",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -17128,7 +17136,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id68",
|
"elementId": "id68",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1e1e1e",
|
"strokeColor": "#1e1e1e",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
|
@ -17136,8 +17144,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 10,
|
"version": 10,
|
||||||
"width": "98.58579",
|
"width": "92.92893",
|
||||||
"x": "0.70711",
|
"x": "3.53553",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -17193,14 +17201,14 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"96.46447",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id68",
|
"elementId": "id68",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
@ -17210,7 +17218,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"96.46447",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -17460,7 +17468,7 @@ History {
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id70",
|
"elementId": "id70",
|
||||||
"focus": -0,
|
"focus": -0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -17478,7 +17486,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"96.46447",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -17490,13 +17498,13 @@ History {
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id68",
|
"elementId": "id68",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1e1e1e",
|
"strokeColor": "#1e1e1e",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": 100,
|
"width": "96.46447",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
|
@ -17811,7 +17819,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id77",
|
"elementId": "id77",
|
||||||
"focus": -0,
|
"focus": -0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -17830,7 +17838,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"98.58579",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -17842,7 +17850,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id75",
|
"elementId": "id75",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1e1e1e",
|
"strokeColor": "#1e1e1e",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
|
@ -17850,8 +17858,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 11,
|
"version": 11,
|
||||||
"width": "98.58579",
|
"width": "92.92893",
|
||||||
"x": "0.70711",
|
"x": "3.53553",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -17913,7 +17921,7 @@ History {
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id77",
|
"elementId": "id77",
|
||||||
"focus": -0,
|
"focus": -0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"points": [
|
"points": [
|
||||||
[
|
[
|
||||||
|
@ -17921,14 +17929,14 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"96.46447",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id75",
|
"elementId": "id75",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
@ -17939,7 +17947,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"96.46447",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -18189,7 +18197,7 @@ History {
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id77",
|
"elementId": "id77",
|
||||||
"focus": -0,
|
"focus": -0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
|
@ -18207,7 +18215,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"96.46447",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -18219,13 +18227,13 @@ History {
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id75",
|
"elementId": "id75",
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"strokeColor": "#1e1e1e",
|
"strokeColor": "#1e1e1e",
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": 100,
|
"width": "96.46447",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
|
|
|
@ -44,14 +44,3 @@ exports[`Test Linear Elements > Test bound text element > should resize and posi
|
||||||
"Online whiteboard
|
"Online whiteboard
|
||||||
collaboration made easy"
|
collaboration made easy"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Test Linear Elements > Test bound text element > should wrap the bound text when arrow bound container moves 1`] = `
|
|
||||||
"Online whiteboard
|
|
||||||
collaboration made easy"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Test Linear Elements > Test bound text element > should wrap the bound text when arrow bound container moves 2`] = `
|
|
||||||
"Online whiteboard
|
|
||||||
collaboration made
|
|
||||||
easy"
|
|
||||||
`;
|
|
||||||
|
|
|
@ -101,139 +101,3 @@ exports[`move element > rectangle 5`] = `
|
||||||
"y": 40,
|
"y": 40,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`move element > rectangles with binding arrow 5`] = `
|
|
||||||
{
|
|
||||||
"angle": 0,
|
|
||||||
"backgroundColor": "transparent",
|
|
||||||
"boundElements": [
|
|
||||||
{
|
|
||||||
"id": "id2",
|
|
||||||
"type": "arrow",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"customData": undefined,
|
|
||||||
"fillStyle": "solid",
|
|
||||||
"frameId": null,
|
|
||||||
"groupIds": [],
|
|
||||||
"height": 100,
|
|
||||||
"id": "id0",
|
|
||||||
"index": "a0",
|
|
||||||
"isDeleted": false,
|
|
||||||
"link": null,
|
|
||||||
"locked": false,
|
|
||||||
"opacity": 100,
|
|
||||||
"roughness": 1,
|
|
||||||
"roundness": {
|
|
||||||
"type": 3,
|
|
||||||
},
|
|
||||||
"seed": 1278240551,
|
|
||||||
"strokeColor": "#1e1e1e",
|
|
||||||
"strokeStyle": "solid",
|
|
||||||
"strokeWidth": 2,
|
|
||||||
"type": "rectangle",
|
|
||||||
"updated": 1,
|
|
||||||
"version": 4,
|
|
||||||
"versionNonce": 1723083209,
|
|
||||||
"width": 100,
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`move element > rectangles with binding arrow 6`] = `
|
|
||||||
{
|
|
||||||
"angle": 0,
|
|
||||||
"backgroundColor": "transparent",
|
|
||||||
"boundElements": [
|
|
||||||
{
|
|
||||||
"id": "id2",
|
|
||||||
"type": "arrow",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"customData": undefined,
|
|
||||||
"fillStyle": "solid",
|
|
||||||
"frameId": null,
|
|
||||||
"groupIds": [],
|
|
||||||
"height": 300,
|
|
||||||
"id": "id1",
|
|
||||||
"index": "a1",
|
|
||||||
"isDeleted": false,
|
|
||||||
"link": null,
|
|
||||||
"locked": false,
|
|
||||||
"opacity": 100,
|
|
||||||
"roughness": 1,
|
|
||||||
"roundness": {
|
|
||||||
"type": 3,
|
|
||||||
},
|
|
||||||
"seed": 1150084233,
|
|
||||||
"strokeColor": "#1e1e1e",
|
|
||||||
"strokeStyle": "solid",
|
|
||||||
"strokeWidth": 2,
|
|
||||||
"type": "rectangle",
|
|
||||||
"updated": 1,
|
|
||||||
"version": 7,
|
|
||||||
"versionNonce": 745419401,
|
|
||||||
"width": 300,
|
|
||||||
"x": 201,
|
|
||||||
"y": 2,
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`move element > rectangles with binding arrow 7`] = `
|
|
||||||
{
|
|
||||||
"angle": 0,
|
|
||||||
"backgroundColor": "transparent",
|
|
||||||
"boundElements": null,
|
|
||||||
"customData": undefined,
|
|
||||||
"elbowed": false,
|
|
||||||
"endArrowhead": "arrow",
|
|
||||||
"endBinding": {
|
|
||||||
"elementId": "id1",
|
|
||||||
"focus": "-0.46667",
|
|
||||||
"gap": 10,
|
|
||||||
},
|
|
||||||
"fillStyle": "solid",
|
|
||||||
"frameId": null,
|
|
||||||
"groupIds": [],
|
|
||||||
"height": "87.29887",
|
|
||||||
"id": "id2",
|
|
||||||
"index": "a2",
|
|
||||||
"isDeleted": false,
|
|
||||||
"lastCommittedPoint": null,
|
|
||||||
"link": null,
|
|
||||||
"locked": false,
|
|
||||||
"opacity": 100,
|
|
||||||
"points": [
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"86.85786",
|
|
||||||
"87.29887",
|
|
||||||
],
|
|
||||||
],
|
|
||||||
"roughness": 1,
|
|
||||||
"roundness": {
|
|
||||||
"type": 2,
|
|
||||||
},
|
|
||||||
"seed": 1604849351,
|
|
||||||
"startArrowhead": null,
|
|
||||||
"startBinding": {
|
|
||||||
"elementId": "id0",
|
|
||||||
"focus": "-0.60000",
|
|
||||||
"gap": 10,
|
|
||||||
},
|
|
||||||
"strokeColor": "#1e1e1e",
|
|
||||||
"strokeStyle": "solid",
|
|
||||||
"strokeWidth": 2,
|
|
||||||
"type": "arrow",
|
|
||||||
"updated": 1,
|
|
||||||
"version": 11,
|
|
||||||
"versionNonce": 1051383431,
|
|
||||||
"width": "86.85786",
|
|
||||||
"x": "107.07107",
|
|
||||||
"y": "47.07107",
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
|
@ -52,6 +52,8 @@ import * as StaticScene from "../renderer/staticScene";
|
||||||
import { Snapshot, CaptureUpdateAction } from "../store";
|
import { Snapshot, CaptureUpdateAction } from "../store";
|
||||||
import { AppStateChange, ElementsChange } from "../change";
|
import { AppStateChange, ElementsChange } from "../change";
|
||||||
|
|
||||||
|
import { FIXED_BINDING_DISTANCE } from "../element/binding.js";
|
||||||
|
|
||||||
import { API } from "./helpers/api";
|
import { API } from "./helpers/api";
|
||||||
import { Keyboard, Pointer, UI } from "./helpers/ui";
|
import { Keyboard, Pointer, UI } from "./helpers/ui";
|
||||||
import {
|
import {
|
||||||
|
@ -4779,12 +4781,12 @@ describe("history", () => {
|
||||||
startBinding: expect.objectContaining({
|
startBinding: expect.objectContaining({
|
||||||
elementId: rect1.id,
|
elementId: rect1.id,
|
||||||
focus: 0,
|
focus: 0,
|
||||||
gap: 1,
|
gap: FIXED_BINDING_DISTANCE,
|
||||||
}),
|
}),
|
||||||
endBinding: expect.objectContaining({
|
endBinding: expect.objectContaining({
|
||||||
elementId: rect2.id,
|
elementId: rect2.id,
|
||||||
focus: -0,
|
focus: -0,
|
||||||
gap: 1,
|
gap: FIXED_BINDING_DISTANCE,
|
||||||
}),
|
}),
|
||||||
isDeleted: true,
|
isDeleted: true,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -35,7 +35,7 @@ test("unselected bound arrow updates when rotating its target element", async ()
|
||||||
expect(arrow.endBinding?.elementId).toEqual(rectangle.id);
|
expect(arrow.endBinding?.elementId).toEqual(rectangle.id);
|
||||||
expect(arrow.x).toBeCloseTo(-80);
|
expect(arrow.x).toBeCloseTo(-80);
|
||||||
expect(arrow.y).toBeCloseTo(50);
|
expect(arrow.y).toBeCloseTo(50);
|
||||||
expect(arrow.width).toBeCloseTo(116.7, 1);
|
expect(arrow.width).toBeCloseTo(119.6, 1);
|
||||||
expect(arrow.height).toBeCloseTo(0);
|
expect(arrow.height).toBeCloseTo(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue