Restoring unnecessarily removed pieces

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
Mark Tolmacs 2025-03-17 23:34:28 +01:00
parent 4c3516a5b9
commit b7b28d5d54
No known key found for this signature in database
3 changed files with 88 additions and 79 deletions

View file

@ -1215,8 +1215,12 @@ export class ElementsChange implements Change<SceneElementsMap> {
flags: { flags: {
containsVisibleDifference: boolean; containsVisibleDifference: boolean;
containsZindexDifference: boolean; containsZindexDifference: boolean;
} = {
// by default we don't care about about the flags
containsVisibleDifference: true,
containsZindexDifference: true,
}, },
): OrderedExcalidrawElement { ) {
const { boundElements, ...directlyApplicablePartial } = delta.inserted; const { boundElements, ...directlyApplicablePartial } = delta.inserted;
if ( if (

View file

@ -739,13 +739,13 @@ 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>;
preservePoints?: boolean; // [FIX] added preservePoints?: boolean;
}, },
) => { ) => {
const { const {
newSize, newSize,
simultaneouslyUpdated, simultaneouslyUpdated,
preservePoints = false, // [FIX] default false preservePoints = false,
} = options ?? {}; } = options ?? {};
const simultaneouslyUpdatedElementIds = getSimultaneouslyUpdatedElementIds( const simultaneouslyUpdatedElementIds = getSimultaneouslyUpdatedElementIds(
simultaneouslyUpdated, simultaneouslyUpdated,
@ -760,10 +760,12 @@ export const updateBoundElements = (
return; return;
} }
// In case the boundElements are stale
if (!doesNeedUpdate(element, changedElement)) { if (!doesNeedUpdate(element, changedElement)) {
return; return;
} }
// Check for intersections before updating bound elements incase connected elements overlap
const startBindingElement = element.startBinding const startBindingElement = element.startBinding
? elementsMap.get(element.startBinding.elementId) ? elementsMap.get(element.startBinding.elementId)
: null; : null;
@ -791,12 +793,13 @@ export const updateBoundElements = (
), ),
}; };
// `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, bindings, true);
return; return;
} }
// [FIX] If preservePoints is true, skip adjusting arrow geometry. // If preservePoints is true, skip adjusting arrow geometry.
if (preservePoints && isArrowElement(element)) { if (preservePoints && isArrowElement(element)) {
// Only update the binding fields // Only update the binding fields
mutateElement(element, { mutateElement(element, {

View file

@ -683,7 +683,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"scrollX": 0, "scrollX": 0,
"scrollY": 0, "scrollY": 0,
"searchMatches": [], "searchMatches": [],
"selectedElementIds": {}, "selectedElementIds": {
"id167": true,
},
"selectedElementsAreBeingDragged": false, "selectedElementsAreBeingDragged": false,
"selectedGroupIds": {}, "selectedGroupIds": {},
"selectionElement": null, "selectionElement": null,
@ -735,7 +737,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"strokeWidth": 2, "strokeWidth": 2,
"type": "rectangle", "type": "rectangle",
"updated": 1, "updated": 1,
"version": 7, "version": 9,
"width": 100, "width": 100,
"x": 150, "x": 150,
"y": -50, "y": -50,
@ -767,7 +769,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"strokeWidth": 2, "strokeWidth": 2,
"type": "rectangle", "type": "rectangle",
"updated": 1, "updated": 1,
"version": 7, "version": 9,
"width": 100, "width": 100,
"x": 150, "x": 150,
"y": -50, "y": -50,
@ -789,7 +791,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"height": 0, "height": 0,
"id": "id167", "id": "id167",
"index": "a2", "index": "a2",
"isDeleted": true, "isDeleted": false,
"lastCommittedPoint": null, "lastCommittedPoint": null,
"link": null, "link": null,
"locked": false, "locked": false,
@ -815,7 +817,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"strokeWidth": 2, "strokeWidth": 2,
"type": "arrow", "type": "arrow",
"updated": 1, "updated": 1,
"version": 22, "version": 30,
"width": 100, "width": 100,
"x": 150, "x": 150,
"y": 0, "y": 0,
@ -949,75 +951,6 @@ History {
}, },
}, },
}, },
HistoryEntry {
"appStateChange": AppStateChange {
"delta": Delta {
"deleted": {
"selectedElementIds": {},
"selectedLinearElementId": null,
},
"inserted": {
"selectedElementIds": {
"id167": true,
},
"selectedLinearElementId": "id167",
},
},
},
"elementsChange": ElementsChange {
"added": Map {
"id167" => Delta {
"deleted": {
"isDeleted": true,
},
"inserted": {
"angle": 0,
"backgroundColor": "transparent",
"boundElements": null,
"customData": undefined,
"elbowed": false,
"endArrowhead": "arrow",
"endBinding": null,
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": 0,
"index": "a2",
"isDeleted": false,
"lastCommittedPoint": null,
"link": null,
"locked": false,
"opacity": 100,
"points": [
[
0,
0,
],
[
100,
0,
],
],
"roughness": 1,
"roundness": {
"type": 2,
},
"startArrowhead": null,
"startBinding": null,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 2,
"type": "arrow",
"width": 100,
"x": 150,
"y": 0,
},
},
},
"removed": Map {},
"updated": Map {},
},
},
], ],
"undoStack": [ "undoStack": [
HistoryEntry { HistoryEntry {
@ -1096,13 +1029,82 @@ History {
"updated": Map {}, "updated": Map {},
}, },
}, },
HistoryEntry {
"appStateChange": AppStateChange {
"delta": Delta {
"deleted": {
"selectedElementIds": {
"id167": true,
},
"selectedLinearElementId": "id167",
},
"inserted": {
"selectedElementIds": {},
"selectedLinearElementId": null,
},
},
},
"elementsChange": ElementsChange {
"added": Map {},
"removed": Map {
"id167" => Delta {
"deleted": {
"angle": 0,
"backgroundColor": "transparent",
"boundElements": null,
"customData": undefined,
"elbowed": false,
"endArrowhead": "arrow",
"endBinding": null,
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": 0,
"index": "a2",
"isDeleted": false,
"lastCommittedPoint": null,
"link": null,
"locked": false,
"opacity": 100,
"points": [
[
0,
0,
],
[
100,
0,
],
],
"roughness": 1,
"roundness": {
"type": 2,
},
"startArrowhead": null,
"startBinding": null,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 2,
"type": "arrow",
"width": 100,
"x": 0,
"y": 0,
},
"inserted": {
"isDeleted": true,
},
},
},
"updated": Map {},
},
},
], ],
} }
`; `;
exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] number of elements 1`] = `3`; exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] number of elements 1`] = `3`;
exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] number of renders 1`] = `19`; exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] number of renders 1`] = `23`;
exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added arrow when it's bindable elements are added through the history > [end of test] appState 1`] = ` exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added arrow when it's bindable elements are added through the history > [end of test] appState 1`] = `
{ {