mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-09-19 07:20:21 +02:00
fix: Refactored timeout bind mode handling
This commit is contained in:
@@ -242,7 +242,6 @@ import {
|
|||||||
bindOrUnbindBindingElement,
|
bindOrUnbindBindingElement,
|
||||||
getBindingStrategyForDraggingBindingElementEndpoints,
|
getBindingStrategyForDraggingBindingElementEndpoints,
|
||||||
getStartGlobalEndLocalPointsForSimpleArrowBinding,
|
getStartGlobalEndLocalPointsForSimpleArrowBinding,
|
||||||
snapToCenter,
|
|
||||||
mutateElement,
|
mutateElement,
|
||||||
} from "@excalidraw/element";
|
} from "@excalidraw/element";
|
||||||
|
|
||||||
@@ -785,7 +784,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
// if (newState && Object.hasOwn(newState, "selectedLinearElement")) {
|
// if (newState && Object.hasOwn(newState, "selectedLinearElement")) {
|
||||||
// console.trace(!!newState.selectedLinearElement);
|
// //console.trace(!!newState.selectedLinearElement);
|
||||||
|
// if (!newState.selectedLinearElement?.selectedPointsIndices?.length) {
|
||||||
|
// console.trace(newState.selectedLinearElement?.selectedPointsIndices);
|
||||||
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// super.setState(newState, callback);
|
// super.setState(newState, callback);
|
||||||
@@ -863,6 +865,130 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private handleSkipBindMode() {
|
||||||
|
if (this.state.bindMode === "orbit") {
|
||||||
|
if (this.bindModeHandler) {
|
||||||
|
clearTimeout(this.bindModeHandler);
|
||||||
|
this.bindModeHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
bindMode: "orbit",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private resetDelayedBindMode() {
|
||||||
|
if (this.bindModeHandler) {
|
||||||
|
clearTimeout(this.bindModeHandler);
|
||||||
|
this.bindModeHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.state.bindMode !== "orbit") {
|
||||||
|
// We need this iteration to complete binding and change
|
||||||
|
// back to orbit mode after that
|
||||||
|
setTimeout(() =>
|
||||||
|
this.setState({
|
||||||
|
bindMode: "orbit",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleDelayedBindModeChange(
|
||||||
|
arrow: ExcalidrawArrowElement,
|
||||||
|
hoveredElement: NonDeletedExcalidrawElement | null,
|
||||||
|
) {
|
||||||
|
if (isElbowArrow(arrow)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const effector = () => {
|
||||||
|
this.bindModeHandler = null;
|
||||||
|
|
||||||
|
invariant(
|
||||||
|
this.lastPointerMoveCoords,
|
||||||
|
"Expected lastPointerMoveCoords to be set",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!this.state.selectedLinearElement?.selectedPointsIndices?.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const startDragged =
|
||||||
|
this.state.selectedLinearElement.selectedPointsIndices.includes(0);
|
||||||
|
const endDragged =
|
||||||
|
this.state.selectedLinearElement.selectedPointsIndices.includes(
|
||||||
|
arrow.points.length - 1,
|
||||||
|
);
|
||||||
|
if ((!startDragged && !endDragged) || (startDragged && endDragged)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { x, y } = this.lastPointerMoveCoords;
|
||||||
|
const hoveredElement = getHoveredElementForBinding(
|
||||||
|
pointFrom<GlobalPoint>(x, y),
|
||||||
|
this.scene.getNonDeletedElements(),
|
||||||
|
this.scene.getNonDeletedElementsMap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (hoveredElement) {
|
||||||
|
flushSync(() => {
|
||||||
|
invariant(
|
||||||
|
this.state.selectedLinearElement?.elementId === arrow.id,
|
||||||
|
"The selectedLinearElement is expected to not change while a bind mode timeout is ticking",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Change the global binding mode
|
||||||
|
this.setState({
|
||||||
|
bindMode: "inside",
|
||||||
|
selectedLinearElement: {
|
||||||
|
...this.state.selectedLinearElement,
|
||||||
|
pointerDownState: {
|
||||||
|
...this.state.selectedLinearElement.pointerDownState,
|
||||||
|
arrowStartIsInside: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Make the arrow endpoint "jump" to the cursor
|
||||||
|
const point = LinearElementEditor.createPointAt(
|
||||||
|
arrow,
|
||||||
|
this.scene.getNonDeletedElementsMap(),
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
isBindingEnabled(this.state) ? this.getEffectiveGridSize() : null,
|
||||||
|
);
|
||||||
|
this.scene.mutateElement(arrow, {
|
||||||
|
points: startDragged
|
||||||
|
? [point, ...arrow.points.slice(1)]
|
||||||
|
: [...arrow.points.slice(0, -1), point],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!hoveredElement) {
|
||||||
|
// Clear the timeout if we're not hovering a bindable
|
||||||
|
if (this.bindModeHandler) {
|
||||||
|
clearTimeout(this.bindModeHandler);
|
||||||
|
this.bindModeHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the inside binding mode too
|
||||||
|
if (this.state.bindMode !== "orbit") {
|
||||||
|
flushSync(() => {
|
||||||
|
this.setState({
|
||||||
|
bindMode: "orbit",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (!this.bindModeHandler) {
|
||||||
|
// We are hovering a bindable element
|
||||||
|
this.bindModeHandler = setTimeout(effector, BIND_MODE_TIMEOUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private cacheEmbeddableRef(
|
private cacheEmbeddableRef(
|
||||||
element: ExcalidrawIframeLikeElement,
|
element: ExcalidrawIframeLikeElement,
|
||||||
ref: HTMLIFrameElement | null,
|
ref: HTMLIFrameElement | null,
|
||||||
@@ -4406,16 +4532,8 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle Alt key for bind mode
|
// Handle Alt key for bind mode
|
||||||
if (event.key === KEYS.ALT && this.state.bindMode === "orbit") {
|
if (event.key === KEYS.ALT) {
|
||||||
// Cancel any pending bind mode timer
|
this.handleSkipBindMode();
|
||||||
if (this.bindModeHandler) {
|
|
||||||
clearTimeout(this.bindModeHandler);
|
|
||||||
this.bindModeHandler = null;
|
|
||||||
}
|
|
||||||
// Immediately switch to skip bind mode
|
|
||||||
this.setState({
|
|
||||||
bindMode: "skip",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.actionManager.handleKeyDown(event)) {
|
if (this.actionManager.handleKeyDown(event)) {
|
||||||
@@ -4427,10 +4545,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (event[KEYS.CTRL_OR_CMD] && this.state.isBindingEnabled) {
|
if (event[KEYS.CTRL_OR_CMD] && this.state.isBindingEnabled) {
|
||||||
if (this.bindModeHandler) {
|
this.resetDelayedBindMode();
|
||||||
clearTimeout(this.bindModeHandler);
|
|
||||||
this.bindModeHandler = null;
|
|
||||||
}
|
|
||||||
this.setState({ isBindingEnabled: false });
|
this.setState({ isBindingEnabled: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4743,15 +4858,15 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.scene.getNonDeletedElementsMap(),
|
this.scene.getNonDeletedElementsMap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (hoveredElement && !this.bindModeHandler) {
|
if (this.state.selectedLinearElement) {
|
||||||
this.bindModeHandler = setTimeout(() => {
|
const element = LinearElementEditor.getElement(
|
||||||
if (hoveredElement) {
|
this.state.selectedLinearElement.elementId,
|
||||||
this.setState({
|
this.scene.getNonDeletedElementsMap(),
|
||||||
bindMode: "inside",
|
);
|
||||||
});
|
|
||||||
}
|
if (isBindingElement(element)) {
|
||||||
this.bindModeHandler = null;
|
this.handleDelayedBindModeChange(element, hoveredElement);
|
||||||
}, BIND_MODE_TIMEOUT);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5892,6 +6007,12 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
) => {
|
) => {
|
||||||
this.savePointer(event.clientX, event.clientY, this.state.cursorButton);
|
this.savePointer(event.clientX, event.clientY, this.state.cursorButton);
|
||||||
this.lastPointerMoveEvent = event.nativeEvent;
|
this.lastPointerMoveEvent = event.nativeEvent;
|
||||||
|
const scenePointer = viewportCoordsToSceneCoords(event, this.state);
|
||||||
|
const { x: scenePointerX, y: scenePointerY } = scenePointer;
|
||||||
|
this.lastPointerMoveCoords = {
|
||||||
|
x: scenePointerX,
|
||||||
|
y: scenePointerY,
|
||||||
|
};
|
||||||
|
|
||||||
if (gesture.pointers.has(event.pointerId)) {
|
if (gesture.pointers.has(event.pointerId)) {
|
||||||
gesture.pointers.set(event.pointerId, {
|
gesture.pointers.set(event.pointerId, {
|
||||||
@@ -5980,13 +6101,6 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const scenePointer = viewportCoordsToSceneCoords(event, this.state);
|
|
||||||
const { x: scenePointerX, y: scenePointerY } = scenePointer;
|
|
||||||
this.lastPointerMoveCoords = {
|
|
||||||
x: scenePointerX,
|
|
||||||
y: scenePointerY,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!this.state.newElement &&
|
!this.state.newElement &&
|
||||||
isActiveToolNonLinearSnappable(this.state.activeTool.type)
|
isActiveToolNonLinearSnappable(this.state.activeTool.type)
|
||||||
@@ -6178,54 +6292,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
elementsMap,
|
elementsMap,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Timed bind mode handler for arrow elements
|
this.handleDelayedBindModeChange(multiElement, hoveredElement);
|
||||||
if (this.state.bindMode === "orbit") {
|
|
||||||
if (this.bindModeHandler && !hoveredElement) {
|
|
||||||
clearTimeout(this.bindModeHandler);
|
|
||||||
this.bindModeHandler = null;
|
|
||||||
} else if (!this.bindModeHandler && hoveredElement) {
|
|
||||||
this.bindModeHandler = setTimeout(() => {
|
|
||||||
if (hoveredElement) {
|
|
||||||
flushSync(() => {
|
|
||||||
this.setState({
|
|
||||||
bindMode: "inside",
|
|
||||||
selectedLinearElement: this.state.selectedLinearElement
|
|
||||||
? {
|
|
||||||
...this.state.selectedLinearElement,
|
|
||||||
pointerDownState: {
|
|
||||||
...this.state.selectedLinearElement
|
|
||||||
.pointerDownState,
|
|
||||||
arrowStartIsInside: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this.scene.mutateElement(multiElement, {
|
|
||||||
points: [
|
|
||||||
...multiElement.points.slice(0, -1),
|
|
||||||
pointFrom<LocalPoint>(
|
|
||||||
this.lastPointerMoveCoords!.x - multiElement.x,
|
|
||||||
this.lastPointerMoveCoords!.y - multiElement.y,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.bindModeHandler = null;
|
|
||||||
}, BIND_MODE_TIMEOUT);
|
|
||||||
}
|
|
||||||
} else if (!hoveredElement) {
|
|
||||||
if (this.bindModeHandler) {
|
|
||||||
clearTimeout(this.bindModeHandler);
|
|
||||||
this.bindModeHandler = null;
|
|
||||||
}
|
|
||||||
flushSync(() => {
|
|
||||||
this.setState({
|
|
||||||
bindMode: "orbit",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const point = pointFrom<LocalPoint>(
|
const point = pointFrom<LocalPoint>(
|
||||||
scenePointerX - rx,
|
scenePointerX - rx,
|
||||||
@@ -6635,6 +6702,13 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
private handleCanvasPointerDown = (
|
private handleCanvasPointerDown = (
|
||||||
event: React.PointerEvent<HTMLElement>,
|
event: React.PointerEvent<HTMLElement>,
|
||||||
) => {
|
) => {
|
||||||
|
const scenePointer = viewportCoordsToSceneCoords(event, this.state);
|
||||||
|
const { x: scenePointerX, y: scenePointerY } = scenePointer;
|
||||||
|
this.lastPointerMoveCoords = {
|
||||||
|
x: scenePointerX,
|
||||||
|
y: scenePointerY,
|
||||||
|
};
|
||||||
|
|
||||||
const target = event.target as HTMLElement;
|
const target = event.target as HTMLElement;
|
||||||
// capture subsequent pointer events to the canvas
|
// capture subsequent pointer events to the canvas
|
||||||
// this makes other elements non-interactive until pointer up
|
// this makes other elements non-interactive until pointer up
|
||||||
@@ -7059,29 +7133,19 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
private handleCanvasPointerUp = (
|
private handleCanvasPointerUp = (
|
||||||
event: React.PointerEvent<HTMLCanvasElement>,
|
event: React.PointerEvent<HTMLCanvasElement>,
|
||||||
) => {
|
) => {
|
||||||
|
this.resetDelayedBindMode();
|
||||||
this.removePointer(event);
|
this.removePointer(event);
|
||||||
this.lastPointerUpEvent = event;
|
this.lastPointerUpEvent = event;
|
||||||
|
|
||||||
// Cancel any pending timeout for bind mode change
|
|
||||||
if (this.state.bindMode === "inside" || this.state.bindMode === "skip") {
|
|
||||||
if (this.bindModeHandler) {
|
|
||||||
clearTimeout(this.bindModeHandler);
|
|
||||||
this.bindModeHandler = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need this iteration to complete binding and change
|
|
||||||
// back to orbit mode after that
|
|
||||||
setTimeout(() =>
|
|
||||||
this.setState({
|
|
||||||
bindMode: "orbit",
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const scenePointer = viewportCoordsToSceneCoords(
|
const scenePointer = viewportCoordsToSceneCoords(
|
||||||
{ clientX: event.clientX, clientY: event.clientY },
|
{ clientX: event.clientX, clientY: event.clientY },
|
||||||
this.state,
|
this.state,
|
||||||
);
|
);
|
||||||
|
const { x: scenePointerX, y: scenePointerY } = scenePointer;
|
||||||
|
this.lastPointerMoveCoords = {
|
||||||
|
x: scenePointerX,
|
||||||
|
y: scenePointerY,
|
||||||
|
};
|
||||||
const clicklength =
|
const clicklength =
|
||||||
event.timeStamp - (this.lastPointerDownEvent?.timeStamp ?? 0);
|
event.timeStamp - (this.lastPointerDownEvent?.timeStamp ?? 0);
|
||||||
|
|
||||||
@@ -7181,10 +7245,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
* pointerup handlers manually
|
* pointerup handlers manually
|
||||||
*/
|
*/
|
||||||
private maybeCleanupAfterMissingPointerUp = (event: PointerEvent | null) => {
|
private maybeCleanupAfterMissingPointerUp = (event: PointerEvent | null) => {
|
||||||
if (this.bindModeHandler) {
|
this.resetDelayedBindMode();
|
||||||
clearTimeout(this.bindModeHandler);
|
|
||||||
this.bindModeHandler = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
bindMode: "orbit",
|
bindMode: "orbit",
|
||||||
@@ -8313,28 +8374,8 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.state,
|
this.state,
|
||||||
{ newArrow: true },
|
{ newArrow: true },
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
if (isSimpleArrow(element)) {
|
this.handleDelayedBindModeChange(element, boundElement);
|
||||||
if (this.bindModeHandler) {
|
|
||||||
clearTimeout(this.bindModeHandler);
|
|
||||||
this.bindModeHandler = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.bindModeHandler = setTimeout(() => {
|
|
||||||
this.setState({
|
|
||||||
bindMode: "inside",
|
|
||||||
selectedLinearElement: this.state.selectedLinearElement
|
|
||||||
? {
|
|
||||||
...this.state.selectedLinearElement,
|
|
||||||
pointerDownState: {
|
|
||||||
...this.state.selectedLinearElement?.pointerDownState,
|
|
||||||
arrowStartIsInside: !!boundElement,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
});
|
|
||||||
}, BIND_MODE_TIMEOUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState((prevState) => {
|
this.setState((prevState) => {
|
||||||
@@ -8354,6 +8395,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
pointerDownState.origin.y,
|
pointerDownState.origin.y,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
selectedPointsIndices: [1],
|
||||||
};
|
};
|
||||||
nextSelectedElementIds = makeNextSelectedElementIds(
|
nextSelectedElementIds = makeNextSelectedElementIds(
|
||||||
{ [element.id]: true },
|
{ [element.id]: true },
|
||||||
@@ -8726,7 +8768,6 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
linearElementEditor.elementId,
|
linearElementEditor.elementId,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
);
|
);
|
||||||
let [x, y] = [pointerCoords.x, pointerCoords.y];
|
|
||||||
|
|
||||||
if (isBindingElement(element)) {
|
if (isBindingElement(element)) {
|
||||||
const hoveredElement = getHoveredElementForBinding(
|
const hoveredElement = getHoveredElementForBinding(
|
||||||
@@ -8735,122 +8776,19 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
elementsMap,
|
elementsMap,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Timed bind mode handler for arrow elements
|
this.handleDelayedBindModeChange(element, hoveredElement);
|
||||||
if (this.state.bindMode === "orbit") {
|
|
||||||
if (this.bindModeHandler && !hoveredElement) {
|
|
||||||
clearTimeout(this.bindModeHandler);
|
|
||||||
this.bindModeHandler = null;
|
|
||||||
} else if (!this.bindModeHandler && hoveredElement) {
|
|
||||||
this.bindModeHandler = setTimeout(() => {
|
|
||||||
if (hoveredElement) {
|
|
||||||
flushSync(() => {
|
|
||||||
this.setState({
|
|
||||||
bindMode: "inside",
|
|
||||||
selectedLinearElement: this.state.selectedLinearElement
|
|
||||||
? {
|
|
||||||
...this.state.selectedLinearElement,
|
|
||||||
pointerDownState: {
|
|
||||||
...this.state.selectedLinearElement
|
|
||||||
.pointerDownState,
|
|
||||||
arrowStartIsInside: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const [lastX, lastY] =
|
|
||||||
hoveredElement && element.startBinding?.mode !== "inside"
|
|
||||||
? snapToCenter(
|
|
||||||
hoveredElement,
|
|
||||||
elementsMap,
|
|
||||||
pointFrom<GlobalPoint>(
|
|
||||||
this.lastPointerMoveCoords?.x ??
|
|
||||||
pointerDownState.origin.x,
|
|
||||||
this.lastPointerMoveCoords?.y ??
|
|
||||||
pointerDownState.origin.y,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: [
|
|
||||||
this.lastPointerMoveCoords?.x ??
|
|
||||||
pointerDownState.origin.x,
|
|
||||||
this.lastPointerMoveCoords?.y ??
|
|
||||||
pointerDownState.origin.y,
|
|
||||||
];
|
|
||||||
|
|
||||||
const newState = LinearElementEditor.handlePointDragging(
|
|
||||||
event,
|
|
||||||
this,
|
|
||||||
lastX,
|
|
||||||
lastY,
|
|
||||||
linearElementEditor,
|
|
||||||
);
|
|
||||||
if (newState) {
|
|
||||||
pointerDownState.lastCoords.x =
|
|
||||||
this.lastPointerMoveCoords?.x ??
|
|
||||||
pointerDownState.origin.x;
|
|
||||||
pointerDownState.lastCoords.y =
|
|
||||||
this.lastPointerMoveCoords?.y ??
|
|
||||||
pointerDownState.origin.y;
|
|
||||||
pointerDownState.drag.hasOccurred = true;
|
|
||||||
|
|
||||||
flushSync(() => {
|
|
||||||
this.setState(newState);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const selectedPointIndices =
|
|
||||||
this.state.selectedLinearElement?.selectedPointsIndices;
|
|
||||||
const nextPoint = pointFrom<LocalPoint>(
|
|
||||||
(this.lastPointerMoveCoords?.x ??
|
|
||||||
pointerDownState.origin.x) - element.x,
|
|
||||||
(this.lastPointerMoveCoords?.y ??
|
|
||||||
pointerDownState.origin.y) - element.y,
|
|
||||||
);
|
|
||||||
if (
|
|
||||||
selectedPointIndices?.length === 1 &&
|
|
||||||
selectedPointIndices[0] === 0
|
|
||||||
) {
|
|
||||||
this.scene.mutateElement(element, {
|
|
||||||
points: [nextPoint, ...element.points.slice(1)],
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.scene.mutateElement(element, {
|
|
||||||
points: [...element.points.slice(0, -1), nextPoint],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.bindModeHandler = null;
|
|
||||||
}, BIND_MODE_TIMEOUT);
|
|
||||||
}
|
|
||||||
} else if (!hoveredElement) {
|
|
||||||
flushSync(() => {
|
|
||||||
this.setState({
|
|
||||||
bindMode: "orbit",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[x, y] =
|
|
||||||
hoveredElement && element.startBinding?.mode !== "inside"
|
|
||||||
? snapToCenter(
|
|
||||||
hoveredElement,
|
|
||||||
elementsMap,
|
|
||||||
pointFrom<GlobalPoint>(pointerCoords.x, pointerCoords.y),
|
|
||||||
)
|
|
||||||
: [pointerCoords.x, pointerCoords.y];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const newState = LinearElementEditor.handlePointDragging(
|
const newState = LinearElementEditor.handlePointDragging(
|
||||||
event,
|
event,
|
||||||
this,
|
this,
|
||||||
x,
|
pointerCoords.x,
|
||||||
y,
|
pointerCoords.y,
|
||||||
linearElementEditor,
|
linearElementEditor,
|
||||||
);
|
);
|
||||||
if (newState) {
|
if (newState) {
|
||||||
pointerDownState.lastCoords.x = x;
|
pointerDownState.lastCoords.x = pointerCoords.x;
|
||||||
pointerDownState.lastCoords.y = y;
|
pointerDownState.lastCoords.y = pointerCoords.y;
|
||||||
pointerDownState.drag.hasOccurred = true;
|
pointerDownState.drag.hasOccurred = true;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -9604,7 +9542,6 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
// just in case, tool changes mid drag, always clean up
|
// just in case, tool changes mid drag, always clean up
|
||||||
this.lassoTrail.endPath();
|
this.lassoTrail.endPath();
|
||||||
this.lastPointerMoveCoords = null;
|
|
||||||
|
|
||||||
SnapCache.setReferenceSnapPoints(null);
|
SnapCache.setReferenceSnapPoints(null);
|
||||||
SnapCache.setVisibleGaps(null);
|
SnapCache.setVisibleGaps(null);
|
||||||
@@ -9656,10 +9593,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.bindModeHandler) {
|
this.resetDelayedBindMode();
|
||||||
clearTimeout(this.bindModeHandler);
|
|
||||||
this.bindModeHandler = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedElementsAreBeingDragged: false,
|
selectedElementsAreBeingDragged: false,
|
||||||
|
Reference in New Issue
Block a user