mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
fix: make arrow binding area adapt to zoom levels (#8927)
* make binding area adapt to zoom * revert stroke color * normalize binding gap * reduce normalized gap
This commit is contained in:
parent
873698a1a2
commit
1e3399eac8
14 changed files with 247 additions and 119 deletions
|
@ -161,6 +161,7 @@ export const actionDeleteSelected = register({
|
||||||
element,
|
element,
|
||||||
selectedPointsIndices,
|
selectedPointsIndices,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
|
appState.zoom,
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -153,6 +153,7 @@ const flipElements = (
|
||||||
app.scene,
|
app.scene,
|
||||||
isBindingEnabled(appState),
|
isBindingEnabled(appState),
|
||||||
[],
|
[],
|
||||||
|
appState.zoom,
|
||||||
);
|
);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
@ -1591,6 +1591,7 @@ export const actionChangeArrowType = register({
|
||||||
tupleToCoors(startGlobalPoint),
|
tupleToCoors(startGlobalPoint),
|
||||||
elements,
|
elements,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
|
appState.zoom,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
const endHoveredElement =
|
const endHoveredElement =
|
||||||
|
@ -1599,6 +1600,7 @@ export const actionChangeArrowType = register({
|
||||||
tupleToCoors(endGlobalPoint),
|
tupleToCoors(endGlobalPoint),
|
||||||
elements,
|
elements,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
|
appState.zoom,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
const startElement = startHoveredElement
|
const startElement = startHoveredElement
|
||||||
|
|
|
@ -3215,6 +3215,10 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
[el.points[0], el.points[el.points.length - 1]],
|
[el.points[0], el.points[el.points.length - 1]],
|
||||||
|
undefined,
|
||||||
|
{
|
||||||
|
zoom: this.state.zoom,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -4372,6 +4376,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
|
|
||||||
updateBoundElements(element, this.scene.getNonDeletedElementsMap(), {
|
updateBoundElements(element, this.scene.getNonDeletedElementsMap(), {
|
||||||
simultaneouslyUpdated: selectedElements,
|
simultaneouslyUpdated: selectedElements,
|
||||||
|
zoom: this.state.zoom,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4381,6 +4386,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
(element) => element.id !== elbowArrow?.id || step !== 0,
|
(element) => element.id !== elbowArrow?.id || step !== 0,
|
||||||
),
|
),
|
||||||
this.scene.getNonDeletedElementsMap(),
|
this.scene.getNonDeletedElementsMap(),
|
||||||
|
this.state.zoom,
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4596,6 +4602,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
this.scene,
|
this.scene,
|
||||||
isBindingEnabled(this.state),
|
isBindingEnabled(this.state),
|
||||||
this.state.selectedLinearElement?.selectedPointsIndices ?? [],
|
this.state.selectedLinearElement?.selectedPointsIndices ?? [],
|
||||||
|
this.state.zoom,
|
||||||
);
|
);
|
||||||
this.setState({ suggestedBindings: [] });
|
this.setState({ suggestedBindings: [] });
|
||||||
}
|
}
|
||||||
|
@ -5854,6 +5861,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
{
|
{
|
||||||
isDragging: true,
|
isDragging: true,
|
||||||
informMutation: false,
|
informMutation: false,
|
||||||
|
zoom: this.state.zoom,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -7401,6 +7409,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
pointerDownState.origin,
|
pointerDownState.origin,
|
||||||
this.scene.getNonDeletedElements(),
|
this.scene.getNonDeletedElements(),
|
||||||
this.scene.getNonDeletedElementsMap(),
|
this.scene.getNonDeletedElementsMap(),
|
||||||
|
this.state.zoom,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -7698,6 +7707,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
pointerDownState.origin,
|
pointerDownState.origin,
|
||||||
this.scene.getNonDeletedElements(),
|
this.scene.getNonDeletedElements(),
|
||||||
this.scene.getNonDeletedElementsMap(),
|
this.scene.getNonDeletedElementsMap(),
|
||||||
|
this.state.zoom,
|
||||||
isElbowArrow(element),
|
isElbowArrow(element),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -8276,6 +8286,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
suggestedBindings: getSuggestedBindingsForArrows(
|
suggestedBindings: getSuggestedBindingsForArrows(
|
||||||
selectedElements,
|
selectedElements,
|
||||||
this.scene.getNonDeletedElementsMap(),
|
this.scene.getNonDeletedElementsMap(),
|
||||||
|
this.state.zoom,
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -8444,6 +8455,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
{
|
{
|
||||||
isDragging: true,
|
isDragging: true,
|
||||||
informMutation: false,
|
informMutation: false,
|
||||||
|
zoom: this.state.zoom,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} else if (points.length === 2) {
|
} else if (points.length === 2) {
|
||||||
|
@ -9408,6 +9420,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
this.scene,
|
this.scene,
|
||||||
isBindingEnabled(this.state),
|
isBindingEnabled(this.state),
|
||||||
this.state.selectedLinearElement?.selectedPointsIndices ?? [],
|
this.state.selectedLinearElement?.selectedPointsIndices ?? [],
|
||||||
|
this.state.zoom,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9900,6 +9913,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
pointerCoords,
|
pointerCoords,
|
||||||
this.scene.getNonDeletedElements(),
|
this.scene.getNonDeletedElements(),
|
||||||
this.scene.getNonDeletedElementsMap(),
|
this.scene.getNonDeletedElementsMap(),
|
||||||
|
this.state.zoom,
|
||||||
);
|
);
|
||||||
this.setState({
|
this.setState({
|
||||||
suggestedBindings:
|
suggestedBindings:
|
||||||
|
@ -9928,6 +9942,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
coords,
|
coords,
|
||||||
this.scene.getNonDeletedElements(),
|
this.scene.getNonDeletedElements(),
|
||||||
this.scene.getNonDeletedElementsMap(),
|
this.scene.getNonDeletedElementsMap(),
|
||||||
|
this.state.zoom,
|
||||||
isArrowElement(linearElement) && isElbowArrow(linearElement),
|
isArrowElement(linearElement) && isElbowArrow(linearElement),
|
||||||
);
|
);
|
||||||
if (
|
if (
|
||||||
|
@ -10569,6 +10584,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
const suggestedBindings = getSuggestedBindingsForArrows(
|
const suggestedBindings = getSuggestedBindingsForArrows(
|
||||||
selectedElements,
|
selectedElements,
|
||||||
this.scene.getNonDeletedElementsMap(),
|
this.scene.getNonDeletedElementsMap(),
|
||||||
|
this.state.zoom,
|
||||||
);
|
);
|
||||||
|
|
||||||
const elementsToHighlight = new Set<ExcalidrawElement>();
|
const elementsToHighlight = new Set<ExcalidrawElement>();
|
||||||
|
|
|
@ -300,6 +300,7 @@ export const updateBindings = (
|
||||||
options?: {
|
options?: {
|
||||||
simultaneouslyUpdated?: readonly ExcalidrawElement[];
|
simultaneouslyUpdated?: readonly ExcalidrawElement[];
|
||||||
newSize?: { width: number; height: number };
|
newSize?: { width: number; height: number };
|
||||||
|
zoom?: AppState["zoom"];
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
if (isLinearElement(latestElement)) {
|
if (isLinearElement(latestElement)) {
|
||||||
|
@ -310,6 +311,7 @@ export const updateBindings = (
|
||||||
scene,
|
scene,
|
||||||
true,
|
true,
|
||||||
[],
|
[],
|
||||||
|
options?.zoom,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
updateBoundElements(latestElement, elementsMap, options);
|
updateBoundElements(latestElement, elementsMap, options);
|
||||||
|
|
|
@ -95,7 +95,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 35,
|
"height": 33.519031369643244,
|
||||||
"id": Any<String>,
|
"id": Any<String>,
|
||||||
"index": "a2",
|
"index": "a2",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
|
@ -109,8 +109,8 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
||||||
0.5,
|
0.5,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
394.5,
|
382.47606040672997,
|
||||||
34.5,
|
34.019031369643244,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
@ -128,9 +128,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 4,
|
"version": 7,
|
||||||
"versionNonce": Any<Number>,
|
"versionNonce": Any<Number>,
|
||||||
"width": 395,
|
"width": 381.97606040672997,
|
||||||
"x": 247,
|
"x": 247,
|
||||||
"y": 420,
|
"y": 420,
|
||||||
}
|
}
|
||||||
|
@ -167,7 +167,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
399.5,
|
389.5,
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -186,10 +186,10 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 4,
|
"version": 6,
|
||||||
"versionNonce": Any<Number>,
|
"versionNonce": Any<Number>,
|
||||||
"width": 400,
|
"width": 390,
|
||||||
"x": 227,
|
"x": 237,
|
||||||
"y": 450,
|
"y": 450,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -319,7 +319,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
|
||||||
"verticalAlign": "top",
|
"verticalAlign": "top",
|
||||||
"width": 100,
|
"width": 100,
|
||||||
"x": 560,
|
"x": 560,
|
||||||
"y": 226.5,
|
"y": 236.95454545454544,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -339,13 +339,13 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "text-2",
|
"elementId": "text-2",
|
||||||
"fixedPoint": null,
|
"fixedPoint": null,
|
||||||
"focus": 0,
|
"focus": 1.625925925925924,
|
||||||
"gap": 205,
|
"gap": 14,
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 0,
|
"height": 18.278619528619487,
|
||||||
"id": Any<String>,
|
"id": Any<String>,
|
||||||
"index": "a2",
|
"index": "a2",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
|
@ -356,11 +356,11 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
|
||||||
"points": [
|
"points": [
|
||||||
[
|
[
|
||||||
0.5,
|
0.5,
|
||||||
0,
|
-0.5,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
99.5,
|
357.2037037037038,
|
||||||
0,
|
-17.778619528619487,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
@ -378,11 +378,11 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 4,
|
"version": 6,
|
||||||
"versionNonce": Any<Number>,
|
"versionNonce": Any<Number>,
|
||||||
"width": 100,
|
"width": 357.7037037037038,
|
||||||
"x": 255,
|
"x": 171,
|
||||||
"y": 239,
|
"y": 249.45454545454544,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -482,7 +482,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 4,
|
"version": 6,
|
||||||
"versionNonce": Any<Number>,
|
"versionNonce": Any<Number>,
|
||||||
"width": 100,
|
"width": 100,
|
||||||
"x": 255,
|
"x": 255,
|
||||||
|
@ -660,7 +660,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 4,
|
"version": 6,
|
||||||
"versionNonce": Any<Number>,
|
"versionNonce": Any<Number>,
|
||||||
"width": 100,
|
"width": 100,
|
||||||
"x": 255,
|
"x": 255,
|
||||||
|
@ -1505,7 +1505,7 @@ exports[`Test Transform > should transform the elements correctly when linear el
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
272.485,
|
270.98528125,
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -1526,10 +1526,10 @@ exports[`Test Transform > should transform the elements correctly when linear el
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 4,
|
"version": 7,
|
||||||
"versionNonce": Any<Number>,
|
"versionNonce": Any<Number>,
|
||||||
"width": 272.985,
|
"width": 270.48528125,
|
||||||
"x": 111.262,
|
"x": 112.76171875,
|
||||||
"y": 57,
|
"y": 57,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -1587,11 +1587,11 @@ exports[`Test Transform > should transform the elements correctly when linear el
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 4,
|
"version": 6,
|
||||||
"versionNonce": Any<Number>,
|
"versionNonce": Any<Number>,
|
||||||
"width": 0,
|
"width": 0,
|
||||||
"x": 77.017,
|
"x": 83.015625,
|
||||||
"y": 79,
|
"y": 81.5,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
|
@ -779,7 +779,7 @@ describe("Test Transform", () => {
|
||||||
elementId: "rect-1",
|
elementId: "rect-1",
|
||||||
fixedPoint: null,
|
fixedPoint: null,
|
||||||
focus: 0,
|
focus: 0,
|
||||||
gap: 205,
|
gap: 14,
|
||||||
});
|
});
|
||||||
expect(rect.boundElements).toStrictEqual([
|
expect(rect.boundElements).toStrictEqual([
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,7 +40,6 @@ import {
|
||||||
isBoundToContainer,
|
isBoundToContainer,
|
||||||
isElbowArrow,
|
isElbowArrow,
|
||||||
isFixedPointBinding,
|
isFixedPointBinding,
|
||||||
isFrameLikeElement,
|
|
||||||
isLinearElement,
|
isLinearElement,
|
||||||
isRectangularElement,
|
isRectangularElement,
|
||||||
isTextElement,
|
isTextElement,
|
||||||
|
@ -97,6 +96,8 @@ export const isBindingEnabled = (appState: AppState): boolean => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FIXED_BINDING_DISTANCE = 5;
|
export const FIXED_BINDING_DISTANCE = 5;
|
||||||
|
export const BINDING_HIGHLIGHT_THICKNESS = 10;
|
||||||
|
export const BINDING_HIGHLIGHT_OFFSET = 4;
|
||||||
|
|
||||||
const getNonDeletedElements = (
|
const getNonDeletedElements = (
|
||||||
scene: Scene,
|
scene: Scene,
|
||||||
|
@ -213,6 +214,7 @@ const getOriginalBindingIfStillCloseOfLinearElementEdge = (
|
||||||
linearElement: NonDeleted<ExcalidrawLinearElement>,
|
linearElement: NonDeleted<ExcalidrawLinearElement>,
|
||||||
edge: "start" | "end",
|
edge: "start" | "end",
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
|
zoom?: AppState["zoom"],
|
||||||
): NonDeleted<ExcalidrawElement> | null => {
|
): NonDeleted<ExcalidrawElement> | null => {
|
||||||
const coors = getLinearElementEdgeCoors(linearElement, edge, elementsMap);
|
const coors = getLinearElementEdgeCoors(linearElement, edge, elementsMap);
|
||||||
const elementId =
|
const elementId =
|
||||||
|
@ -223,7 +225,7 @@ const getOriginalBindingIfStillCloseOfLinearElementEdge = (
|
||||||
const element = elementsMap.get(elementId);
|
const element = elementsMap.get(elementId);
|
||||||
if (
|
if (
|
||||||
isBindableElement(element) &&
|
isBindableElement(element) &&
|
||||||
bindingBorderTest(element, coors, elementsMap)
|
bindingBorderTest(element, coors, elementsMap, zoom)
|
||||||
) {
|
) {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
@ -235,12 +237,14 @@ const getOriginalBindingIfStillCloseOfLinearElementEdge = (
|
||||||
const getOriginalBindingsIfStillCloseToArrowEnds = (
|
const getOriginalBindingsIfStillCloseToArrowEnds = (
|
||||||
linearElement: NonDeleted<ExcalidrawLinearElement>,
|
linearElement: NonDeleted<ExcalidrawLinearElement>,
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
|
zoom?: AppState["zoom"],
|
||||||
): (NonDeleted<ExcalidrawElement> | null)[] =>
|
): (NonDeleted<ExcalidrawElement> | null)[] =>
|
||||||
["start", "end"].map((edge) =>
|
["start", "end"].map((edge) =>
|
||||||
getOriginalBindingIfStillCloseOfLinearElementEdge(
|
getOriginalBindingIfStillCloseOfLinearElementEdge(
|
||||||
linearElement,
|
linearElement,
|
||||||
edge as "start" | "end",
|
edge as "start" | "end",
|
||||||
elementsMap,
|
elementsMap,
|
||||||
|
zoom,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -250,6 +254,7 @@ const getBindingStrategyForDraggingArrowEndpoints = (
|
||||||
draggingPoints: readonly number[],
|
draggingPoints: readonly number[],
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
elements: readonly NonDeletedExcalidrawElement[],
|
elements: readonly NonDeletedExcalidrawElement[],
|
||||||
|
zoom?: AppState["zoom"],
|
||||||
): (NonDeleted<ExcalidrawBindableElement> | null | "keep")[] => {
|
): (NonDeleted<ExcalidrawBindableElement> | null | "keep")[] => {
|
||||||
const startIdx = 0;
|
const startIdx = 0;
|
||||||
const endIdx = selectedElement.points.length - 1;
|
const endIdx = selectedElement.points.length - 1;
|
||||||
|
@ -262,6 +267,7 @@ const getBindingStrategyForDraggingArrowEndpoints = (
|
||||||
"start",
|
"start",
|
||||||
elementsMap,
|
elementsMap,
|
||||||
elements,
|
elements,
|
||||||
|
zoom,
|
||||||
)
|
)
|
||||||
: null // If binding is disabled and start is dragged, break all binds
|
: null // If binding is disabled and start is dragged, break all binds
|
||||||
: // We have to update the focus and gap of the binding, so let's rebind
|
: // We have to update the focus and gap of the binding, so let's rebind
|
||||||
|
@ -270,6 +276,7 @@ const getBindingStrategyForDraggingArrowEndpoints = (
|
||||||
"start",
|
"start",
|
||||||
elementsMap,
|
elementsMap,
|
||||||
elements,
|
elements,
|
||||||
|
zoom,
|
||||||
);
|
);
|
||||||
const end = endDragged
|
const end = endDragged
|
||||||
? isBindingEnabled
|
? isBindingEnabled
|
||||||
|
@ -278,6 +285,7 @@ const getBindingStrategyForDraggingArrowEndpoints = (
|
||||||
"end",
|
"end",
|
||||||
elementsMap,
|
elementsMap,
|
||||||
elements,
|
elements,
|
||||||
|
zoom,
|
||||||
)
|
)
|
||||||
: null // If binding is disabled and end is dragged, break all binds
|
: null // If binding is disabled and end is dragged, break all binds
|
||||||
: // We have to update the focus and gap of the binding, so let's rebind
|
: // We have to update the focus and gap of the binding, so let's rebind
|
||||||
|
@ -286,6 +294,7 @@ const getBindingStrategyForDraggingArrowEndpoints = (
|
||||||
"end",
|
"end",
|
||||||
elementsMap,
|
elementsMap,
|
||||||
elements,
|
elements,
|
||||||
|
zoom,
|
||||||
);
|
);
|
||||||
|
|
||||||
return [start, end];
|
return [start, end];
|
||||||
|
@ -296,10 +305,12 @@ const getBindingStrategyForDraggingArrowOrJoints = (
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
elements: readonly NonDeletedExcalidrawElement[],
|
elements: readonly NonDeletedExcalidrawElement[],
|
||||||
isBindingEnabled: boolean,
|
isBindingEnabled: boolean,
|
||||||
|
zoom?: AppState["zoom"],
|
||||||
): (NonDeleted<ExcalidrawBindableElement> | null | "keep")[] => {
|
): (NonDeleted<ExcalidrawBindableElement> | null | "keep")[] => {
|
||||||
const [startIsClose, endIsClose] = getOriginalBindingsIfStillCloseToArrowEnds(
|
const [startIsClose, endIsClose] = getOriginalBindingsIfStillCloseToArrowEnds(
|
||||||
selectedElement,
|
selectedElement,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
|
zoom,
|
||||||
);
|
);
|
||||||
const start = startIsClose
|
const start = startIsClose
|
||||||
? isBindingEnabled
|
? isBindingEnabled
|
||||||
|
@ -308,6 +319,7 @@ const getBindingStrategyForDraggingArrowOrJoints = (
|
||||||
"start",
|
"start",
|
||||||
elementsMap,
|
elementsMap,
|
||||||
elements,
|
elements,
|
||||||
|
zoom,
|
||||||
)
|
)
|
||||||
: null
|
: null
|
||||||
: null;
|
: null;
|
||||||
|
@ -318,6 +330,7 @@ const getBindingStrategyForDraggingArrowOrJoints = (
|
||||||
"end",
|
"end",
|
||||||
elementsMap,
|
elementsMap,
|
||||||
elements,
|
elements,
|
||||||
|
zoom,
|
||||||
)
|
)
|
||||||
: null
|
: null
|
||||||
: null;
|
: null;
|
||||||
|
@ -332,6 +345,7 @@ export const bindOrUnbindLinearElements = (
|
||||||
scene: Scene,
|
scene: Scene,
|
||||||
isBindingEnabled: boolean,
|
isBindingEnabled: boolean,
|
||||||
draggingPoints: readonly number[] | null,
|
draggingPoints: readonly number[] | null,
|
||||||
|
zoom?: AppState["zoom"],
|
||||||
): void => {
|
): void => {
|
||||||
selectedElements.forEach((selectedElement) => {
|
selectedElements.forEach((selectedElement) => {
|
||||||
const [start, end] = draggingPoints?.length
|
const [start, end] = draggingPoints?.length
|
||||||
|
@ -342,6 +356,7 @@ export const bindOrUnbindLinearElements = (
|
||||||
draggingPoints ?? [],
|
draggingPoints ?? [],
|
||||||
elementsMap,
|
elementsMap,
|
||||||
elements,
|
elements,
|
||||||
|
zoom,
|
||||||
)
|
)
|
||||||
: // The arrow itself (the shaft) or the inner joins are dragged
|
: // The arrow itself (the shaft) or the inner joins are dragged
|
||||||
getBindingStrategyForDraggingArrowOrJoints(
|
getBindingStrategyForDraggingArrowOrJoints(
|
||||||
|
@ -349,6 +364,7 @@ export const bindOrUnbindLinearElements = (
|
||||||
elementsMap,
|
elementsMap,
|
||||||
elements,
|
elements,
|
||||||
isBindingEnabled,
|
isBindingEnabled,
|
||||||
|
zoom,
|
||||||
);
|
);
|
||||||
|
|
||||||
bindOrUnbindLinearElement(selectedElement, start, end, elementsMap, scene);
|
bindOrUnbindLinearElement(selectedElement, start, end, elementsMap, scene);
|
||||||
|
@ -358,6 +374,7 @@ export const bindOrUnbindLinearElements = (
|
||||||
export const getSuggestedBindingsForArrows = (
|
export const getSuggestedBindingsForArrows = (
|
||||||
selectedElements: NonDeleted<ExcalidrawElement>[],
|
selectedElements: NonDeleted<ExcalidrawElement>[],
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
|
zoom: AppState["zoom"],
|
||||||
): SuggestedBinding[] => {
|
): SuggestedBinding[] => {
|
||||||
// HOT PATH: Bail out if selected elements list is too large
|
// HOT PATH: Bail out if selected elements list is too large
|
||||||
if (selectedElements.length > 50) {
|
if (selectedElements.length > 50) {
|
||||||
|
@ -368,7 +385,7 @@ export const getSuggestedBindingsForArrows = (
|
||||||
selectedElements
|
selectedElements
|
||||||
.filter(isLinearElement)
|
.filter(isLinearElement)
|
||||||
.flatMap((element) =>
|
.flatMap((element) =>
|
||||||
getOriginalBindingsIfStillCloseToArrowEnds(element, elementsMap),
|
getOriginalBindingsIfStillCloseToArrowEnds(element, elementsMap, zoom),
|
||||||
)
|
)
|
||||||
.filter(
|
.filter(
|
||||||
(element): element is NonDeleted<ExcalidrawBindableElement> =>
|
(element): element is NonDeleted<ExcalidrawBindableElement> =>
|
||||||
|
@ -406,6 +423,7 @@ export const maybeBindLinearElement = (
|
||||||
pointerCoords,
|
pointerCoords,
|
||||||
elements,
|
elements,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
|
appState.zoom,
|
||||||
isElbowArrow(linearElement) && isElbowArrow(linearElement),
|
isElbowArrow(linearElement) && isElbowArrow(linearElement),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -422,6 +440,26 @@ 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,
|
||||||
|
@ -433,12 +471,15 @@ export const bindLinearElement = (
|
||||||
}
|
}
|
||||||
const binding: PointBinding = {
|
const binding: PointBinding = {
|
||||||
elementId: hoveredElement.id,
|
elementId: hoveredElement.id,
|
||||||
...calculateFocusAndGap(
|
...normalizePointBinding(
|
||||||
|
calculateFocusAndGap(
|
||||||
linearElement,
|
linearElement,
|
||||||
hoveredElement,
|
hoveredElement,
|
||||||
startOrEnd,
|
startOrEnd,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
),
|
),
|
||||||
|
hoveredElement,
|
||||||
|
),
|
||||||
...(isElbowArrow(linearElement)
|
...(isElbowArrow(linearElement)
|
||||||
? calculateFixedPointForElbowArrowBinding(
|
? calculateFixedPointForElbowArrowBinding(
|
||||||
linearElement,
|
linearElement,
|
||||||
|
@ -462,6 +503,12 @@ export const bindLinearElement = (
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update bound elements to make sure the binding tips are in sync with
|
||||||
|
// the normalized gap from above
|
||||||
|
if (!isElbowArrow(linearElement)) {
|
||||||
|
updateBoundElements(hoveredElement, elementsMap);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Don't bind both ends of a simple segment
|
// Don't bind both ends of a simple segment
|
||||||
|
@ -514,6 +561,7 @@ export const getHoveredElementForBinding = (
|
||||||
},
|
},
|
||||||
elements: readonly NonDeletedExcalidrawElement[],
|
elements: readonly NonDeletedExcalidrawElement[],
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
|
zoom?: AppState["zoom"],
|
||||||
fullShape?: boolean,
|
fullShape?: boolean,
|
||||||
): NonDeleted<ExcalidrawBindableElement> | null => {
|
): NonDeleted<ExcalidrawBindableElement> | null => {
|
||||||
const hoveredElement = getElementAtPosition(
|
const hoveredElement = getElementAtPosition(
|
||||||
|
@ -524,11 +572,13 @@ export const getHoveredElementForBinding = (
|
||||||
element,
|
element,
|
||||||
pointerCoords,
|
pointerCoords,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
|
zoom,
|
||||||
// disable fullshape snapping for frame elements so we
|
// disable fullshape snapping for frame elements so we
|
||||||
// can bind to frame children
|
// can bind to frame children
|
||||||
fullShape && !isFrameLikeElement(element),
|
fullShape,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return hoveredElement as NonDeleted<ExcalidrawBindableElement> | null;
|
return hoveredElement as NonDeleted<ExcalidrawBindableElement> | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -578,9 +628,11 @@ export const updateBoundElements = (
|
||||||
simultaneouslyUpdated?: readonly ExcalidrawElement[];
|
simultaneouslyUpdated?: readonly ExcalidrawElement[];
|
||||||
newSize?: { width: number; height: number };
|
newSize?: { width: number; height: number };
|
||||||
changedElements?: Map<string, OrderedExcalidrawElement>;
|
changedElements?: Map<string, OrderedExcalidrawElement>;
|
||||||
|
zoom?: AppState["zoom"];
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
const { newSize, simultaneouslyUpdated, changedElements } = options ?? {};
|
const { newSize, simultaneouslyUpdated, changedElements, zoom } =
|
||||||
|
options ?? {};
|
||||||
const simultaneouslyUpdatedElementIds = getSimultaneouslyUpdatedElementIds(
|
const simultaneouslyUpdatedElementIds = getSimultaneouslyUpdatedElementIds(
|
||||||
simultaneouslyUpdated,
|
simultaneouslyUpdated,
|
||||||
);
|
);
|
||||||
|
@ -670,6 +722,7 @@ export const updateBoundElements = (
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
changedElements,
|
changedElements,
|
||||||
|
zoom,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -703,6 +756,7 @@ export const getHeadingForElbowArrowSnap = (
|
||||||
aabb: Bounds | undefined | null,
|
aabb: Bounds | undefined | null,
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
origPoint: GlobalPoint,
|
origPoint: GlobalPoint,
|
||||||
|
zoom?: AppState["zoom"],
|
||||||
): Heading => {
|
): Heading => {
|
||||||
const otherPointHeading = vectorToHeading(vectorFromPoint(otherPoint, p));
|
const otherPointHeading = vectorToHeading(vectorFromPoint(otherPoint, p));
|
||||||
|
|
||||||
|
@ -714,6 +768,7 @@ export const getHeadingForElbowArrowSnap = (
|
||||||
origPoint,
|
origPoint,
|
||||||
bindableElement,
|
bindableElement,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
|
zoom,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!distance) {
|
if (!distance) {
|
||||||
|
@ -737,6 +792,7 @@ const getDistanceForBinding = (
|
||||||
point: Readonly<GlobalPoint>,
|
point: Readonly<GlobalPoint>,
|
||||||
bindableElement: ExcalidrawBindableElement,
|
bindableElement: ExcalidrawBindableElement,
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
|
zoom?: AppState["zoom"],
|
||||||
) => {
|
) => {
|
||||||
const distance = distanceToBindableElement(
|
const distance = distanceToBindableElement(
|
||||||
bindableElement,
|
bindableElement,
|
||||||
|
@ -747,6 +803,7 @@ const getDistanceForBinding = (
|
||||||
bindableElement,
|
bindableElement,
|
||||||
bindableElement.width,
|
bindableElement.width,
|
||||||
bindableElement.height,
|
bindableElement.height,
|
||||||
|
zoom,
|
||||||
);
|
);
|
||||||
|
|
||||||
return distance > bindDistance ? null : distance;
|
return distance > bindDistance ? null : distance;
|
||||||
|
@ -1174,11 +1231,13 @@ const getElligibleElementForBindingElement = (
|
||||||
startOrEnd: "start" | "end",
|
startOrEnd: "start" | "end",
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
elements: readonly NonDeletedExcalidrawElement[],
|
elements: readonly NonDeletedExcalidrawElement[],
|
||||||
|
zoom?: AppState["zoom"],
|
||||||
): NonDeleted<ExcalidrawBindableElement> | null => {
|
): NonDeleted<ExcalidrawBindableElement> | null => {
|
||||||
return getHoveredElementForBinding(
|
return getHoveredElementForBinding(
|
||||||
getLinearElementEdgeCoors(linearElement, startOrEnd, elementsMap),
|
getLinearElementEdgeCoors(linearElement, startOrEnd, elementsMap),
|
||||||
elements,
|
elements,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
|
zoom,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1341,9 +1400,11 @@ export const bindingBorderTest = (
|
||||||
element: NonDeleted<ExcalidrawBindableElement>,
|
element: NonDeleted<ExcalidrawBindableElement>,
|
||||||
{ x, y }: { x: number; y: number },
|
{ x, y }: { x: number; y: number },
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
|
zoom?: AppState["zoom"],
|
||||||
fullShape?: boolean,
|
fullShape?: boolean,
|
||||||
): boolean => {
|
): boolean => {
|
||||||
const threshold = maxBindingGap(element, element.width, element.height);
|
const threshold = maxBindingGap(element, element.width, element.height, zoom);
|
||||||
|
|
||||||
const shape = getElementShape(element, elementsMap);
|
const shape = getElementShape(element, elementsMap);
|
||||||
return (
|
return (
|
||||||
isPointOnShape(pointFrom(x, y), shape, threshold) ||
|
isPointOnShape(pointFrom(x, y), shape, threshold) ||
|
||||||
|
@ -1356,12 +1417,21 @@ export const maxBindingGap = (
|
||||||
element: ExcalidrawElement,
|
element: ExcalidrawElement,
|
||||||
elementWidth: number,
|
elementWidth: number,
|
||||||
elementHeight: number,
|
elementHeight: number,
|
||||||
|
zoom?: AppState["zoom"],
|
||||||
): number => {
|
): number => {
|
||||||
|
const zoomValue = zoom?.value && zoom.value < 1 ? zoom.value : 1;
|
||||||
|
|
||||||
// Aligns diamonds with rectangles
|
// Aligns diamonds with rectangles
|
||||||
const shapeRatio = element.type === "diamond" ? 1 / Math.sqrt(2) : 1;
|
const shapeRatio = element.type === "diamond" ? 1 / Math.sqrt(2) : 1;
|
||||||
const smallerDimension = shapeRatio * Math.min(elementWidth, elementHeight);
|
const smallerDimension = shapeRatio * Math.min(elementWidth, elementHeight);
|
||||||
// We make the bindable boundary bigger for bigger elements
|
|
||||||
return Math.max(16, Math.min(0.25 * smallerDimension, 32));
|
return Math.max(
|
||||||
|
16,
|
||||||
|
// bigger bindable boundary for bigger elements
|
||||||
|
Math.min(0.25 * smallerDimension, 32),
|
||||||
|
// keep in sync with the zoomed highlight
|
||||||
|
BINDING_HIGHLIGHT_THICKNESS / zoomValue + BINDING_HIGHLIGHT_OFFSET,
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const distanceToBindableElement = (
|
export const distanceToBindableElement = (
|
||||||
|
|
|
@ -448,6 +448,7 @@ export class LinearElementEditor {
|
||||||
),
|
),
|
||||||
elements,
|
elements,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
|
appState.zoom,
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
@ -787,6 +788,7 @@ export class LinearElementEditor {
|
||||||
scenePointer,
|
scenePointer,
|
||||||
elements,
|
elements,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
|
app.state.zoom,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -911,6 +913,7 @@ export class LinearElementEditor {
|
||||||
element,
|
element,
|
||||||
[points.length - 1],
|
[points.length - 1],
|
||||||
elementsMap,
|
elementsMap,
|
||||||
|
app.state.zoom,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@ -964,6 +967,7 @@ export class LinearElementEditor {
|
||||||
element,
|
element,
|
||||||
[{ point: newPoint }],
|
[{ point: newPoint }],
|
||||||
elementsMap,
|
elementsMap,
|
||||||
|
app.state.zoom,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@ -1218,6 +1222,7 @@ export class LinearElementEditor {
|
||||||
element: NonDeleted<ExcalidrawLinearElement>,
|
element: NonDeleted<ExcalidrawLinearElement>,
|
||||||
pointIndices: readonly number[],
|
pointIndices: readonly number[],
|
||||||
elementsMap: NonDeletedSceneElementsMap | SceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap | SceneElementsMap,
|
||||||
|
zoom: AppState["zoom"],
|
||||||
) {
|
) {
|
||||||
let offsetX = 0;
|
let offsetX = 0;
|
||||||
let offsetY = 0;
|
let offsetY = 0;
|
||||||
|
@ -1260,6 +1265,7 @@ export class LinearElementEditor {
|
||||||
element: NonDeleted<ExcalidrawLinearElement>,
|
element: NonDeleted<ExcalidrawLinearElement>,
|
||||||
targetPoints: { point: LocalPoint }[],
|
targetPoints: { point: LocalPoint }[],
|
||||||
elementsMap: NonDeletedSceneElementsMap | SceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap | SceneElementsMap,
|
||||||
|
zoom: AppState["zoom"],
|
||||||
) {
|
) {
|
||||||
const offsetX = 0;
|
const offsetX = 0;
|
||||||
const offsetY = 0;
|
const offsetY = 0;
|
||||||
|
@ -1285,6 +1291,7 @@ export class LinearElementEditor {
|
||||||
options?: {
|
options?: {
|
||||||
changedElements?: Map<string, OrderedExcalidrawElement>;
|
changedElements?: Map<string, OrderedExcalidrawElement>;
|
||||||
isDragging?: boolean;
|
isDragging?: boolean;
|
||||||
|
zoom?: AppState["zoom"];
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
const { points } = element;
|
const { points } = element;
|
||||||
|
@ -1337,6 +1344,7 @@ export class LinearElementEditor {
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
changedElements: options?.changedElements,
|
changedElements: options?.changedElements,
|
||||||
|
zoom: options?.zoom,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1451,6 +1459,7 @@ export class LinearElementEditor {
|
||||||
options?: {
|
options?: {
|
||||||
changedElements?: Map<string, OrderedExcalidrawElement>;
|
changedElements?: Map<string, OrderedExcalidrawElement>;
|
||||||
isDragging?: boolean;
|
isDragging?: boolean;
|
||||||
|
zoom?: AppState["zoom"];
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
if (isElbowArrow(element)) {
|
if (isElbowArrow(element)) {
|
||||||
|
@ -1487,6 +1496,7 @@ export class LinearElementEditor {
|
||||||
bindings,
|
bindings,
|
||||||
{
|
{
|
||||||
isDragging: options?.isDragging,
|
isDragging: options?.isDragging,
|
||||||
|
zoom: options?.zoom,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {
|
||||||
import BinaryHeap from "../binaryheap";
|
import BinaryHeap from "../binaryheap";
|
||||||
import { getSizeFromPoints } from "../points";
|
import { getSizeFromPoints } from "../points";
|
||||||
import { aabbForElement, pointInsideBounds } from "../shapes";
|
import { aabbForElement, pointInsideBounds } from "../shapes";
|
||||||
|
import type { AppState } from "../types";
|
||||||
import { isAnyTrue, toBrandedType, tupleToCoors } from "../utils";
|
import { isAnyTrue, toBrandedType, tupleToCoors } from "../utils";
|
||||||
import {
|
import {
|
||||||
bindPointToSnapToElementOutline,
|
bindPointToSnapToElementOutline,
|
||||||
|
@ -79,6 +80,7 @@ export const mutateElbowArrow = (
|
||||||
options?: {
|
options?: {
|
||||||
isDragging?: boolean;
|
isDragging?: boolean;
|
||||||
informMutation?: boolean;
|
informMutation?: boolean;
|
||||||
|
zoom?: AppState["zoom"];
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
const update = updateElbowArrow(
|
const update = updateElbowArrow(
|
||||||
|
@ -112,6 +114,7 @@ export const updateElbowArrow = (
|
||||||
isDragging?: boolean;
|
isDragging?: boolean;
|
||||||
disableBinding?: boolean;
|
disableBinding?: boolean;
|
||||||
informMutation?: boolean;
|
informMutation?: boolean;
|
||||||
|
zoom?: AppState["zoom"];
|
||||||
},
|
},
|
||||||
): ElementUpdate<ExcalidrawElbowArrowElement> | null => {
|
): ElementUpdate<ExcalidrawElbowArrowElement> | null => {
|
||||||
const origStartGlobalPoint: GlobalPoint = pointTranslate(
|
const origStartGlobalPoint: GlobalPoint = pointTranslate(
|
||||||
|
@ -136,7 +139,12 @@ export const updateElbowArrow = (
|
||||||
arrow.endBinding &&
|
arrow.endBinding &&
|
||||||
getBindableElementForId(arrow.endBinding.elementId, elementsMap);
|
getBindableElementForId(arrow.endBinding.elementId, elementsMap);
|
||||||
const [hoveredStartElement, hoveredEndElement] = options?.isDragging
|
const [hoveredStartElement, hoveredEndElement] = options?.isDragging
|
||||||
? getHoveredElements(origStartGlobalPoint, origEndGlobalPoint, elementsMap)
|
? getHoveredElements(
|
||||||
|
origStartGlobalPoint,
|
||||||
|
origEndGlobalPoint,
|
||||||
|
elementsMap,
|
||||||
|
options?.zoom,
|
||||||
|
)
|
||||||
: [startElement, endElement];
|
: [startElement, endElement];
|
||||||
const startGlobalPoint = getGlobalPoint(
|
const startGlobalPoint = getGlobalPoint(
|
||||||
arrow.startBinding?.fixedPoint,
|
arrow.startBinding?.fixedPoint,
|
||||||
|
@ -1072,6 +1080,7 @@ const getHoveredElements = (
|
||||||
origStartGlobalPoint: GlobalPoint,
|
origStartGlobalPoint: GlobalPoint,
|
||||||
origEndGlobalPoint: GlobalPoint,
|
origEndGlobalPoint: GlobalPoint,
|
||||||
elementsMap: NonDeletedSceneElementsMap | SceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap | SceneElementsMap,
|
||||||
|
zoom?: AppState["zoom"],
|
||||||
) => {
|
) => {
|
||||||
// TODO: Might be a performance bottleneck and the Map type
|
// TODO: Might be a performance bottleneck and the Map type
|
||||||
// remembers the insertion order anyway...
|
// remembers the insertion order anyway...
|
||||||
|
@ -1084,12 +1093,14 @@ const getHoveredElements = (
|
||||||
tupleToCoors(origStartGlobalPoint),
|
tupleToCoors(origStartGlobalPoint),
|
||||||
elements,
|
elements,
|
||||||
nonDeletedSceneElementsMap,
|
nonDeletedSceneElementsMap,
|
||||||
|
zoom,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
getHoveredElementForBinding(
|
getHoveredElementForBinding(
|
||||||
tupleToCoors(origEndGlobalPoint),
|
tupleToCoors(origEndGlobalPoint),
|
||||||
elements,
|
elements,
|
||||||
nonDeletedSceneElementsMap,
|
nonDeletedSceneElementsMap,
|
||||||
|
zoom,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
|
@ -43,7 +43,11 @@ import type {
|
||||||
SuggestedBinding,
|
SuggestedBinding,
|
||||||
SuggestedPointBinding,
|
SuggestedPointBinding,
|
||||||
} from "../element/binding";
|
} from "../element/binding";
|
||||||
import { maxBindingGap } from "../element/binding";
|
import {
|
||||||
|
BINDING_HIGHLIGHT_OFFSET,
|
||||||
|
BINDING_HIGHLIGHT_THICKNESS,
|
||||||
|
maxBindingGap,
|
||||||
|
} from "../element/binding";
|
||||||
import { LinearElementEditor } from "../element/linearElementEditor";
|
import { LinearElementEditor } from "../element/linearElementEditor";
|
||||||
import {
|
import {
|
||||||
bootstrapCanvas,
|
bootstrapCanvas,
|
||||||
|
@ -217,17 +221,18 @@ const renderBindingHighlightForBindableElement = (
|
||||||
context: CanvasRenderingContext2D,
|
context: CanvasRenderingContext2D,
|
||||||
element: ExcalidrawBindableElement,
|
element: ExcalidrawBindableElement,
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
|
zoom: InteractiveCanvasAppState["zoom"],
|
||||||
) => {
|
) => {
|
||||||
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
|
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
|
||||||
const width = x2 - x1;
|
const width = x2 - x1;
|
||||||
const height = y2 - y1;
|
const height = y2 - y1;
|
||||||
const thickness = 10;
|
|
||||||
|
|
||||||
// So that we don't overlap the element itself
|
|
||||||
const strokeOffset = 4;
|
|
||||||
context.strokeStyle = "rgba(0,0,0,.05)";
|
context.strokeStyle = "rgba(0,0,0,.05)";
|
||||||
context.lineWidth = thickness - strokeOffset;
|
// When zooming out, make line width greater for visibility
|
||||||
const padding = strokeOffset / 2 + thickness / 2;
|
const zoomValue = zoom.value < 1 ? zoom.value : 1;
|
||||||
|
context.lineWidth = BINDING_HIGHLIGHT_THICKNESS / zoomValue;
|
||||||
|
// To ensure the binding highlight doesn't overlap the element itself
|
||||||
|
const padding = context.lineWidth / 2 + BINDING_HIGHLIGHT_OFFSET;
|
||||||
|
|
||||||
const radius = getCornerRadius(
|
const radius = getCornerRadius(
|
||||||
Math.min(element.width, element.height),
|
Math.min(element.width, element.height),
|
||||||
|
@ -285,6 +290,7 @@ const renderBindingHighlightForSuggestedPointBinding = (
|
||||||
context: CanvasRenderingContext2D,
|
context: CanvasRenderingContext2D,
|
||||||
suggestedBinding: SuggestedPointBinding,
|
suggestedBinding: SuggestedPointBinding,
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
|
zoom: InteractiveCanvasAppState["zoom"],
|
||||||
) => {
|
) => {
|
||||||
const [element, startOrEnd, bindableElement] = suggestedBinding;
|
const [element, startOrEnd, bindableElement] = suggestedBinding;
|
||||||
|
|
||||||
|
@ -292,6 +298,7 @@ const renderBindingHighlightForSuggestedPointBinding = (
|
||||||
bindableElement,
|
bindableElement,
|
||||||
bindableElement.width,
|
bindableElement.width,
|
||||||
bindableElement.height,
|
bindableElement.height,
|
||||||
|
zoom,
|
||||||
);
|
);
|
||||||
|
|
||||||
context.strokeStyle = "rgba(0,0,0,0)";
|
context.strokeStyle = "rgba(0,0,0,0)";
|
||||||
|
@ -390,7 +397,7 @@ const renderBindingHighlight = (
|
||||||
|
|
||||||
context.save();
|
context.save();
|
||||||
context.translate(appState.scrollX, appState.scrollY);
|
context.translate(appState.scrollX, appState.scrollY);
|
||||||
renderHighlight(context, suggestedBinding as any, elementsMap);
|
renderHighlight(context, suggestedBinding as any, elementsMap, appState.zoom);
|
||||||
|
|
||||||
context.restore();
|
context.restore();
|
||||||
};
|
};
|
||||||
|
|
|
@ -197,7 +197,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 99,
|
"height": 125,
|
||||||
"id": "id166",
|
"id": "id166",
|
||||||
"index": "a2",
|
"index": "a2",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
|
@ -211,8 +211,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"98.20800",
|
125,
|
||||||
99,
|
125,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
@ -226,9 +226,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 40,
|
"version": 47,
|
||||||
"width": "98.20800",
|
"width": 125,
|
||||||
"x": 1,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -298,7 +298,7 @@ History {
|
||||||
"focus": "0.00990",
|
"focus": "0.00990",
|
||||||
"gap": 1,
|
"gap": 1,
|
||||||
},
|
},
|
||||||
"height": "0.98017",
|
"height": "0.98000",
|
||||||
"points": [
|
"points": [
|
||||||
[
|
[
|
||||||
0,
|
0,
|
||||||
|
@ -306,7 +306,7 @@ History {
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
98,
|
98,
|
||||||
"-0.98017",
|
"-0.98000",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
|
@ -320,10 +320,10 @@ History {
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id165",
|
"elementId": "id165",
|
||||||
"fixedPoint": null,
|
"fixedPoint": null,
|
||||||
"focus": "-0.02000",
|
"focus": "-0.02040",
|
||||||
"gap": 1,
|
"gap": 1,
|
||||||
},
|
},
|
||||||
"height": "0.00169",
|
"height": "0.02000",
|
||||||
"points": [
|
"points": [
|
||||||
[
|
[
|
||||||
0,
|
0,
|
||||||
|
@ -331,13 +331,13 @@ History {
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
98,
|
98,
|
||||||
"0.00169",
|
"0.02000",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id164",
|
"elementId": "id164",
|
||||||
"fixedPoint": null,
|
"fixedPoint": null,
|
||||||
"focus": "0.02000",
|
"focus": "0.01959",
|
||||||
"gap": 1,
|
"gap": 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -393,18 +393,20 @@ History {
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 1,
|
||||||
},
|
},
|
||||||
"height": 99,
|
"height": 125,
|
||||||
"points": [
|
"points": [
|
||||||
[
|
[
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"98.20800",
|
125,
|
||||||
99,
|
125,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": null,
|
"startBinding": null,
|
||||||
|
"width": 125,
|
||||||
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
@ -414,7 +416,7 @@ History {
|
||||||
"focus": "0.00990",
|
"focus": "0.00990",
|
||||||
"gap": 1,
|
"gap": 1,
|
||||||
},
|
},
|
||||||
"height": "0.98161",
|
"height": "0.98000",
|
||||||
"points": [
|
"points": [
|
||||||
[
|
[
|
||||||
0,
|
0,
|
||||||
|
@ -422,7 +424,7 @@ History {
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
98,
|
98,
|
||||||
"-0.98161",
|
"-0.98000",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
|
@ -431,7 +433,9 @@ History {
|
||||||
"focus": "0.02970",
|
"focus": "0.02970",
|
||||||
"gap": 1,
|
"gap": 1,
|
||||||
},
|
},
|
||||||
"y": "0.99245",
|
"width": 98,
|
||||||
|
"x": 1,
|
||||||
|
"y": "0.99000",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"id169" => Delta {
|
"id169" => Delta {
|
||||||
|
@ -823,9 +827,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 30,
|
"version": 37,
|
||||||
"width": 0,
|
"width": 100,
|
||||||
"x": 200,
|
"x": 150,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -862,6 +866,8 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
"width": 0,
|
||||||
|
"x": 149,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"points": [
|
"points": [
|
||||||
|
@ -870,10 +876,12 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"98.00000",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
"width": "98.00000",
|
||||||
|
"x": "1.00000",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -930,6 +938,8 @@ History {
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": null,
|
"startBinding": null,
|
||||||
|
"width": 100,
|
||||||
|
"x": 150,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
|
@ -954,6 +964,8 @@ History {
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 1,
|
||||||
},
|
},
|
||||||
|
"width": 0,
|
||||||
|
"x": 149,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -2363,9 +2375,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 10,
|
"version": 12,
|
||||||
"width": 498,
|
"width": 498,
|
||||||
"x": 1,
|
"x": "1.00000",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -2504,7 +2516,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"98.00000",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -2523,8 +2535,8 @@ History {
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": 100,
|
"width": "98.00000",
|
||||||
"x": 0,
|
"x": 1,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
@ -15167,9 +15179,9 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 10,
|
"version": 12,
|
||||||
"width": "98.00000",
|
"width": "98.00000",
|
||||||
"x": 1,
|
"x": "1.00000",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -15208,7 +15220,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"98.00000",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -15221,7 +15233,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"98.00000",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -15517,7 +15529,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"98.00000",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -15536,8 +15548,8 @@ History {
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": 100,
|
"width": "98.00000",
|
||||||
"x": 0,
|
"x": 1,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
@ -15866,9 +15878,9 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 10,
|
"version": 12,
|
||||||
"width": "98.00000",
|
"width": "98.00000",
|
||||||
"x": 1,
|
"x": "1.00000",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -16140,7 +16152,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"98.00000",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -16159,8 +16171,8 @@ History {
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": 100,
|
"width": "98.00000",
|
||||||
"x": 0,
|
"x": 1,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
@ -16489,9 +16501,9 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 10,
|
"version": 12,
|
||||||
"width": "98.00000",
|
"width": "98.00000",
|
||||||
"x": 1,
|
"x": "1.00000",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -16763,7 +16775,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"98.00000",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -16782,8 +16794,8 @@ History {
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": 100,
|
"width": "98.00000",
|
||||||
"x": 0,
|
"x": 1,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
@ -17110,9 +17122,9 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 10,
|
"version": 12,
|
||||||
"width": "98.00000",
|
"width": "98.00000",
|
||||||
"x": 1,
|
"x": "1.00000",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -17168,7 +17180,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"98.00000",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -17186,7 +17198,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"98.00000",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -17455,7 +17467,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"98.00000",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -17474,8 +17486,8 @@ History {
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": 100,
|
"width": "98.00000",
|
||||||
"x": 0,
|
"x": 1,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
@ -17828,9 +17840,9 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 11,
|
"version": 13,
|
||||||
"width": "98.00000",
|
"width": "98.00000",
|
||||||
"x": 1,
|
"x": "1.00000",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -17901,7 +17913,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"98.00000",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -17920,7 +17932,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"98.00000",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -18189,7 +18201,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
100,
|
"98.00000",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -18208,8 +18220,8 @@ History {
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": 100,
|
"width": "98.00000",
|
||||||
"x": 0,
|
"x": 1,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
|
|
@ -173,7 +173,7 @@ exports[`move element > rectangles with binding arrow 6`] = `
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 7,
|
"version": 7,
|
||||||
"versionNonce": 745419401,
|
"versionNonce": 2066753033,
|
||||||
"width": 300,
|
"width": 300,
|
||||||
"x": 201,
|
"x": 201,
|
||||||
"y": 2,
|
"y": 2,
|
||||||
|
@ -232,8 +232,8 @@ exports[`move element > rectangles with binding arrow 7`] = `
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 11,
|
"version": 15,
|
||||||
"versionNonce": 1996028265,
|
"versionNonce": 271613161,
|
||||||
"width": 81,
|
"width": 81,
|
||||||
"x": 110,
|
"x": 110,
|
||||||
"y": 50,
|
"y": 50,
|
||||||
|
|
|
@ -4785,21 +4785,17 @@ describe("history", () => {
|
||||||
expect.objectContaining({ id: rect2.id, boundElements: [] }),
|
expect.objectContaining({ id: rect2.id, boundElements: [] }),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: arrowId,
|
id: arrowId,
|
||||||
points: [
|
|
||||||
[0, 0],
|
|
||||||
[100, 0],
|
|
||||||
],
|
|
||||||
startBinding: expect.objectContaining({
|
startBinding: expect.objectContaining({
|
||||||
elementId: rect1.id,
|
elementId: rect1.id,
|
||||||
fixedPoint: null,
|
fixedPoint: null,
|
||||||
focus: expect.toBeNonNaNNumber(),
|
focus: 0,
|
||||||
gap: expect.toBeNonNaNNumber(),
|
gap: 1,
|
||||||
}),
|
}),
|
||||||
endBinding: expect.objectContaining({
|
endBinding: expect.objectContaining({
|
||||||
elementId: rect2.id,
|
elementId: rect2.id,
|
||||||
fixedPoint: null,
|
fixedPoint: null,
|
||||||
focus: expect.toBeNonNaNNumber(),
|
focus: 0,
|
||||||
gap: expect.toBeNonNaNNumber(),
|
gap: 1,
|
||||||
}),
|
}),
|
||||||
isDeleted: true,
|
isDeleted: true,
|
||||||
}),
|
}),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue