mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-09-11 11:30:07 +02:00
@@ -35,7 +35,6 @@ import {
|
|||||||
import {
|
import {
|
||||||
getAllHoveredElementAtPoint,
|
getAllHoveredElementAtPoint,
|
||||||
getHoveredElementForBinding,
|
getHoveredElementForBinding,
|
||||||
hitElementItself,
|
|
||||||
intersectElementWithLineSegment,
|
intersectElementWithLineSegment,
|
||||||
isPointInElement,
|
isPointInElement,
|
||||||
} from "./collision";
|
} from "./collision";
|
||||||
@@ -644,68 +643,6 @@ export const bindOrUnbindBindingElements = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const maybeSuggestBindingsForBindingElementAtCoords = (
|
|
||||||
linearElement: NonDeleted<ExcalidrawArrowElement>,
|
|
||||||
startOrEndOrBoth: "start" | "end" | "both",
|
|
||||||
scene: Scene,
|
|
||||||
pointerCoords: GlobalPoint,
|
|
||||||
): AppState["suggestedBinding"] => {
|
|
||||||
const startCoords =
|
|
||||||
startOrEndOrBoth === "start"
|
|
||||||
? pointerCoords
|
|
||||||
: LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
|
||||||
linearElement,
|
|
||||||
0,
|
|
||||||
scene.getNonDeletedElementsMap(),
|
|
||||||
);
|
|
||||||
const endCoords =
|
|
||||||
startOrEndOrBoth === "end"
|
|
||||||
? pointerCoords
|
|
||||||
: LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
|
||||||
linearElement,
|
|
||||||
-1,
|
|
||||||
scene.getNonDeletedElementsMap(),
|
|
||||||
);
|
|
||||||
const startHovered = getHoveredElementForBinding(
|
|
||||||
startCoords,
|
|
||||||
scene.getNonDeletedElements(),
|
|
||||||
scene.getNonDeletedElementsMap(),
|
|
||||||
);
|
|
||||||
const endHovered = getHoveredElementForBinding(
|
|
||||||
endCoords,
|
|
||||||
scene.getNonDeletedElements(),
|
|
||||||
scene.getNonDeletedElementsMap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let suggestedBinding: AppState["suggestedBinding"] = null;
|
|
||||||
|
|
||||||
if (startHovered != null && startHovered.id === endHovered?.id) {
|
|
||||||
const hitStart = hitElementItself({
|
|
||||||
element: startHovered,
|
|
||||||
elementsMap: scene.getNonDeletedElementsMap(),
|
|
||||||
point: pointFrom<GlobalPoint>(startCoords[0], startCoords[1]),
|
|
||||||
threshold: 0,
|
|
||||||
overrideShouldTestInside: true,
|
|
||||||
});
|
|
||||||
const hitEnd = hitElementItself({
|
|
||||||
element: endHovered,
|
|
||||||
elementsMap: scene.getNonDeletedElementsMap(),
|
|
||||||
point: pointFrom<GlobalPoint>(endCoords[0], endCoords[1]),
|
|
||||||
threshold: 0,
|
|
||||||
overrideShouldTestInside: true,
|
|
||||||
});
|
|
||||||
if (hitStart && hitEnd) {
|
|
||||||
suggestedBinding = startHovered;
|
|
||||||
}
|
|
||||||
} else if (startOrEndOrBoth === "start" && startHovered != null) {
|
|
||||||
suggestedBinding = startHovered;
|
|
||||||
} else if (startOrEndOrBoth === "end" && endHovered != null) {
|
|
||||||
suggestedBinding = endHovered;
|
|
||||||
}
|
|
||||||
|
|
||||||
return suggestedBinding;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const bindBindingElement = (
|
export const bindBindingElement = (
|
||||||
arrow: NonDeleted<ExcalidrawArrowElement>,
|
arrow: NonDeleted<ExcalidrawArrowElement>,
|
||||||
hoveredElement: ExcalidrawBindableElement,
|
hoveredElement: ExcalidrawBindableElement,
|
||||||
|
@@ -45,7 +45,6 @@ import {
|
|||||||
calculateFixedPointForNonElbowArrowBinding,
|
calculateFixedPointForNonElbowArrowBinding,
|
||||||
getBindingStrategyForDraggingBindingElementEndpoints,
|
getBindingStrategyForDraggingBindingElementEndpoints,
|
||||||
isBindingEnabled,
|
isBindingEnabled,
|
||||||
maybeSuggestBindingsForBindingElementAtCoords,
|
|
||||||
updateBoundPoint,
|
updateBoundPoint,
|
||||||
} from "./binding";
|
} from "./binding";
|
||||||
import {
|
import {
|
||||||
@@ -335,6 +334,7 @@ export class LinearElementEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply the point movement if needed
|
// Apply the point movement if needed
|
||||||
|
let suggestedBinding: AppState["suggestedBinding"] = null;
|
||||||
if (deltaX || deltaY) {
|
if (deltaX || deltaY) {
|
||||||
const { positions, updates } = pointDraggingUpdates(
|
const { positions, updates } = pointDraggingUpdates(
|
||||||
[idx],
|
[idx],
|
||||||
@@ -347,6 +347,12 @@ export class LinearElementEditor {
|
|||||||
);
|
);
|
||||||
|
|
||||||
LinearElementEditor.movePoints(element, app.scene, positions, updates);
|
LinearElementEditor.movePoints(element, app.scene, positions, updates);
|
||||||
|
// Set the suggested binding from the updates if available
|
||||||
|
if (isBindingElement(element, false)) {
|
||||||
|
if (isBindingEnabled(app.state)) {
|
||||||
|
suggestedBinding = updates?.suggestedBinding ?? null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Move the arrow over the bindable object in terms of z-index
|
// Move the arrow over the bindable object in terms of z-index
|
||||||
if (isBindingElement(element)) {
|
if (isBindingElement(element)) {
|
||||||
@@ -364,17 +370,6 @@ export class LinearElementEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Suggest bindings for first and last point if selected
|
|
||||||
let suggestedBinding: AppState["suggestedBinding"] = null;
|
|
||||||
if (isBindingElement(element, false)) {
|
|
||||||
suggestedBinding = maybeSuggestBindingsForBindingElementAtCoords(
|
|
||||||
element,
|
|
||||||
"end",
|
|
||||||
app.scene,
|
|
||||||
pointFrom<GlobalPoint>(scenePointerX, scenePointerY),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// PERF: Avoid state updates if not absolutely necessary
|
// PERF: Avoid state updates if not absolutely necessary
|
||||||
if (
|
if (
|
||||||
app.state.selectedLinearElement?.customLineAngle === customLineAngle &&
|
app.state.selectedLinearElement?.customLineAngle === customLineAngle &&
|
||||||
@@ -530,22 +525,6 @@ export class LinearElementEditor {
|
|||||||
handleBindTextResize(element, app.scene, false);
|
handleBindTextResize(element, app.scene, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Suggest bindings for first and last point if selected
|
|
||||||
if (isBindingElement(element, false)) {
|
|
||||||
if (isBindingEnabled(app.state) && (startIsSelected || endIsSelected)) {
|
|
||||||
suggestedBinding = maybeSuggestBindingsForBindingElementAtCoords(
|
|
||||||
element,
|
|
||||||
startIsSelected && endIsSelected
|
|
||||||
? "both"
|
|
||||||
: startIsSelected
|
|
||||||
? "start"
|
|
||||||
: "end",
|
|
||||||
app.scene,
|
|
||||||
pointFrom<GlobalPoint>(scenePointerX, scenePointerY),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update selected points for elbow arrows because elbow arrows add and
|
// Update selected points for elbow arrows because elbow arrows add and
|
||||||
// remove points as they route
|
// remove points as they route
|
||||||
const newSelectedPointsIndices = elbowed
|
const newSelectedPointsIndices = elbowed
|
||||||
@@ -2115,7 +2094,10 @@ const pointDraggingUpdates = (
|
|||||||
if (startIsDragged) {
|
if (startIsDragged) {
|
||||||
updates.suggestedBinding = start.element;
|
updates.suggestedBinding = start.element;
|
||||||
}
|
}
|
||||||
|
} else if (startIsDragged) {
|
||||||
|
updates.suggestedBinding = app.state.suggestedBinding;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end.mode === null) {
|
if (end.mode === null) {
|
||||||
updates.endBinding = null;
|
updates.endBinding = null;
|
||||||
} else if (end.mode) {
|
} else if (end.mode) {
|
||||||
@@ -2134,6 +2116,8 @@ const pointDraggingUpdates = (
|
|||||||
if (endIsDragged) {
|
if (endIsDragged) {
|
||||||
updates.suggestedBinding = end.element;
|
updates.suggestedBinding = end.element;
|
||||||
}
|
}
|
||||||
|
} else if (endIsDragged) {
|
||||||
|
updates.suggestedBinding = app.state.suggestedBinding;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simulate the updated arrow for the bind point calculation
|
// Simulate the updated arrow for the bind point calculation
|
||||||
@@ -2258,11 +2242,13 @@ const pointDraggingUpdates = (
|
|||||||
const indices = Array.from(indicesSet);
|
const indices = Array.from(indicesSet);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
updates: updates.startBinding
|
updates:
|
||||||
? {
|
updates.startBinding || updates.suggestedBinding
|
||||||
startBinding: updates.startBinding,
|
? {
|
||||||
}
|
startBinding: updates.startBinding,
|
||||||
: undefined,
|
suggestedBinding: updates.suggestedBinding,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
positions: new Map(
|
positions: new Map(
|
||||||
indices.map((idx) => {
|
indices.map((idx) => {
|
||||||
return [
|
return [
|
||||||
|
@@ -110,7 +110,6 @@ import {
|
|||||||
import {
|
import {
|
||||||
getObservedAppState,
|
getObservedAppState,
|
||||||
getCommonBounds,
|
getCommonBounds,
|
||||||
maybeSuggestBindingsForBindingElementAtCoords,
|
|
||||||
getElementAbsoluteCoords,
|
getElementAbsoluteCoords,
|
||||||
bindOrUnbindBindingElements,
|
bindOrUnbindBindingElements,
|
||||||
fixBindingsAfterDeletion,
|
fixBindingsAfterDeletion,
|
||||||
@@ -6246,15 +6245,17 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
// Hovering with a selected tool or creating new linear element via click
|
// Hovering with a selected tool or creating new linear element via click
|
||||||
// and point
|
// and point
|
||||||
const { newElement } = this.state;
|
const { newElement } = this.state;
|
||||||
if (isBindingElement(newElement, false) && isBindingEnabled(this.state)) {
|
if (!newElement && isBindingEnabled(this.state)) {
|
||||||
this.setState({
|
const hoveredElement = getHoveredElementForBinding(
|
||||||
suggestedBinding: maybeSuggestBindingsForBindingElementAtCoords(
|
pointFrom<GlobalPoint>(scenePointerX, scenePointerY),
|
||||||
newElement,
|
this.scene.getNonDeletedElements(),
|
||||||
"end",
|
this.scene.getNonDeletedElementsMap(),
|
||||||
this.scene,
|
);
|
||||||
pointFrom<GlobalPoint>(scenePointerX, scenePointerY),
|
if (hoveredElement) {
|
||||||
),
|
this.setState({
|
||||||
});
|
suggestedBinding: hoveredElement,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user