mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap (#7663)
* fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap * lint * fix * use non deleted elements where possible * use non deleted elements map in actions * pass elementsMap instead of array to elementOverlapsWithFrame * lint * fix * pass elementsMap to getElementsCorners * pass elementsMap to getEligibleElementsForBinding * pass elementsMap in bindOrUnbindSelectedElements and unbindLinearElements * pass elementsMap in elementsAreInFrameBounds,elementOverlapsWithFrame,isCursorInFrame,getElementsInResizingFrame * pass elementsMap in getElementsWithinSelection, getElementsCompletelyInFrame, isElementContainingFrame, getElementsInNewFrame * pass elementsMap to getElementWithTransformHandleType * pass elementsMap to getVisibleGaps, getMaximumGroups,getReferenceSnapPoints,snapDraggedElements * lint * pass elementsMap to bindTextToShapeAfterDuplication,bindLinearElementToElement,getTextBindableContainerAtPosition * revert changes for bindTextToShapeAfterDuplication
This commit is contained in:
parent
73bf50e8a8
commit
47f87f4ecb
36 changed files with 779 additions and 270 deletions
|
@ -1536,6 +1536,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
<Hyperlink
|
||||
key={firstSelectedElement.id}
|
||||
element={firstSelectedElement}
|
||||
elementsMap={allElementsMap}
|
||||
setAppState={this.setAppState}
|
||||
onLinkOpen={this.props.onLinkOpen}
|
||||
setToast={this.setToast}
|
||||
|
@ -1549,6 +1550,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
isMagicFrameElement(firstSelectedElement) && (
|
||||
<ElementCanvasButtons
|
||||
element={firstSelectedElement}
|
||||
elementsMap={elementsMap}
|
||||
>
|
||||
<ElementCanvasButton
|
||||
title={t("labels.convertToCode")}
|
||||
|
@ -1569,6 +1571,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
?.status === "done" && (
|
||||
<ElementCanvasButtons
|
||||
element={firstSelectedElement}
|
||||
elementsMap={elementsMap}
|
||||
>
|
||||
<ElementCanvasButton
|
||||
title={t("labels.copySource")}
|
||||
|
@ -2599,10 +2602,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||
|
||||
componentDidUpdate(prevProps: AppProps, prevState: AppState) {
|
||||
this.updateEmbeddables();
|
||||
if (
|
||||
!this.state.showWelcomeScreen &&
|
||||
!this.scene.getElementsIncludingDeleted().length
|
||||
) {
|
||||
const elements = this.scene.getElementsIncludingDeleted();
|
||||
const elementsMap = this.scene.getElementsMapIncludingDeleted();
|
||||
|
||||
if (!this.state.showWelcomeScreen && !elements.length) {
|
||||
this.setState({ showWelcomeScreen: true });
|
||||
}
|
||||
|
||||
|
@ -2756,27 +2759,21 @@ class App extends React.Component<AppProps, AppState> {
|
|||
LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||
multiElement,
|
||||
-1,
|
||||
elementsMap,
|
||||
),
|
||||
),
|
||||
elementsMap,
|
||||
);
|
||||
}
|
||||
this.history.record(this.state, this.scene.getElementsIncludingDeleted());
|
||||
this.history.record(this.state, elements);
|
||||
|
||||
// Do not notify consumers if we're still loading the scene. Among other
|
||||
// potential issues, this fixes a case where the tab isn't focused during
|
||||
// init, which would trigger onChange with empty elements, which would then
|
||||
// override whatever is in localStorage currently.
|
||||
if (!this.state.isLoading) {
|
||||
this.props.onChange?.(
|
||||
this.scene.getElementsIncludingDeleted(),
|
||||
this.state,
|
||||
this.files,
|
||||
);
|
||||
this.onChangeEmitter.trigger(
|
||||
this.scene.getElementsIncludingDeleted(),
|
||||
this.state,
|
||||
this.files,
|
||||
);
|
||||
this.props.onChange?.(elements, this.state, this.files);
|
||||
this.onChangeEmitter.trigger(elements, this.state, this.files);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3126,7 +3123,11 @@ class App extends React.Component<AppProps, AppState> {
|
|||
newElement,
|
||||
this.scene.getElementsMapIncludingDeleted(),
|
||||
);
|
||||
redrawTextBoundingBox(newElement, container);
|
||||
redrawTextBoundingBox(
|
||||
newElement,
|
||||
container,
|
||||
this.scene.getElementsMapIncludingDeleted(),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -3836,7 +3837,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
y: element.y + offsetY,
|
||||
});
|
||||
|
||||
updateBoundElements(element, {
|
||||
updateBoundElements(element, this.scene.getNonDeletedElementsMap(), {
|
||||
simultaneouslyUpdated: selectedElements,
|
||||
});
|
||||
});
|
||||
|
@ -4010,9 +4011,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||
}
|
||||
if (isArrowKey(event.key)) {
|
||||
const selectedElements = this.scene.getSelectedElements(this.state);
|
||||
const elementsMap = this.scene.getNonDeletedElementsMap();
|
||||
isBindingEnabled(this.state)
|
||||
? bindOrUnbindSelectedElements(selectedElements)
|
||||
: unbindLinearElements(selectedElements);
|
||||
? bindOrUnbindSelectedElements(selectedElements, elementsMap)
|
||||
: unbindLinearElements(selectedElements, elementsMap);
|
||||
this.setState({ suggestedBindings: [] });
|
||||
}
|
||||
});
|
||||
|
@ -4193,20 +4195,21 @@ class App extends React.Component<AppProps, AppState> {
|
|||
isExistingElement?: boolean;
|
||||
},
|
||||
) {
|
||||
const elementsMap = this.scene.getElementsMapIncludingDeleted();
|
||||
|
||||
const updateElement = (
|
||||
text: string,
|
||||
originalText: string,
|
||||
isDeleted: boolean,
|
||||
) => {
|
||||
this.scene.replaceAllElements([
|
||||
// Not sure why we include deleted elements as well hence using deleted elements map
|
||||
...this.scene.getElementsIncludingDeleted().map((_element) => {
|
||||
if (_element.id === element.id && isTextElement(_element)) {
|
||||
return updateTextElement(
|
||||
_element,
|
||||
getContainerElement(
|
||||
_element,
|
||||
this.scene.getElementsMapIncludingDeleted(),
|
||||
),
|
||||
getContainerElement(_element, elementsMap),
|
||||
elementsMap,
|
||||
{
|
||||
text,
|
||||
isDeleted,
|
||||
|
@ -4238,7 +4241,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
onChange: withBatchedUpdates((text) => {
|
||||
updateElement(text, text, false);
|
||||
if (isNonDeletedElement(element)) {
|
||||
updateBoundElements(element);
|
||||
updateBoundElements(element, elementsMap);
|
||||
}
|
||||
}),
|
||||
onSubmit: withBatchedUpdates(({ text, viaKeyboard, originalText }) => {
|
||||
|
@ -4377,6 +4380,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
!(isTextElement(element) && element.containerId)),
|
||||
);
|
||||
|
||||
const elementsMap = this.scene.getNonDeletedElementsMap();
|
||||
return getElementsAtPosition(elements, (element) =>
|
||||
hitTest(
|
||||
element,
|
||||
|
@ -4384,7 +4388,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.frameNameBoundsCache,
|
||||
x,
|
||||
y,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
elementsMap,
|
||||
),
|
||||
).filter((element) => {
|
||||
// hitting a frame's element from outside the frame is not considered a hit
|
||||
|
@ -4392,7 +4396,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
return containingFrame &&
|
||||
this.state.frameRendering.enabled &&
|
||||
this.state.frameRendering.clip
|
||||
? isCursorInFrame({ x, y }, containingFrame)
|
||||
? isCursorInFrame({ x, y }, containingFrame, elementsMap)
|
||||
: true;
|
||||
});
|
||||
}
|
||||
|
@ -4637,6 +4641,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.state,
|
||||
sceneX,
|
||||
sceneY,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
);
|
||||
|
||||
if (container) {
|
||||
|
@ -4648,6 +4653,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.state,
|
||||
this.frameNameBoundsCache,
|
||||
[sceneX, sceneY],
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
)
|
||||
) {
|
||||
const midPoint = getContainerCenter(
|
||||
|
@ -4688,6 +4694,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
index <= hitElementIndex &&
|
||||
isPointHittingLink(
|
||||
element,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
this.state,
|
||||
[scenePointer.x, scenePointer.y],
|
||||
this.device.editor.isMobile,
|
||||
|
@ -4718,8 +4725,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.lastPointerDownEvent!,
|
||||
this.state,
|
||||
);
|
||||
const elementsMap = this.scene.getNonDeletedElementsMap();
|
||||
const lastPointerDownHittingLinkIcon = isPointHittingLink(
|
||||
this.hitLinkElement,
|
||||
elementsMap,
|
||||
this.state,
|
||||
[lastPointerDownCoords.x, lastPointerDownCoords.y],
|
||||
this.device.editor.isMobile,
|
||||
|
@ -4730,6 +4739,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
);
|
||||
const lastPointerUpHittingLinkIcon = isPointHittingLink(
|
||||
this.hitLinkElement,
|
||||
elementsMap,
|
||||
this.state,
|
||||
[lastPointerUpCoords.x, lastPointerUpCoords.y],
|
||||
this.device.editor.isMobile,
|
||||
|
@ -4766,10 +4776,11 @@ class App extends React.Component<AppProps, AppState> {
|
|||
x: number;
|
||||
y: number;
|
||||
}) => {
|
||||
const elementsMap = this.scene.getNonDeletedElementsMap();
|
||||
const frames = this.scene
|
||||
.getNonDeletedFramesLikes()
|
||||
.filter((frame): frame is ExcalidrawFrameLikeElement =>
|
||||
isCursorInFrame(sceneCoords, frame),
|
||||
isCursorInFrame(sceneCoords, frame, elementsMap),
|
||||
);
|
||||
|
||||
return frames.length ? frames[frames.length - 1] : null;
|
||||
|
@ -4873,6 +4884,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
y: scenePointerY,
|
||||
},
|
||||
event,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
);
|
||||
|
||||
this.setState((prevState) => {
|
||||
|
@ -4912,6 +4924,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
scenePointerX,
|
||||
scenePointerY,
|
||||
this.state,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
);
|
||||
|
||||
if (
|
||||
|
@ -5062,6 +5075,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
scenePointerY,
|
||||
this.state.zoom,
|
||||
event.pointerType,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
);
|
||||
if (
|
||||
elementWithTransformHandleType &&
|
||||
|
@ -5109,7 +5123,11 @@ class App extends React.Component<AppProps, AppState> {
|
|||
!this.state.selectedElementIds[this.hitLinkElement.id]
|
||||
) {
|
||||
setCursor(this.interactiveCanvas, CURSOR_TYPE.POINTER);
|
||||
showHyperlinkTooltip(this.hitLinkElement, this.state);
|
||||
showHyperlinkTooltip(
|
||||
this.hitLinkElement,
|
||||
this.state,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
);
|
||||
} else {
|
||||
hideHyperlinkToolip();
|
||||
if (
|
||||
|
@ -5305,10 +5323,12 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.state,
|
||||
this.frameNameBoundsCache,
|
||||
[scenePointerX, scenePointerY],
|
||||
elementsMap,
|
||||
)
|
||||
) {
|
||||
hoverPointIndex = LinearElementEditor.getPointIndexUnderCursor(
|
||||
element,
|
||||
elementsMap,
|
||||
this.state.zoom,
|
||||
scenePointerX,
|
||||
scenePointerY,
|
||||
|
@ -5738,10 +5758,12 @@ class App extends React.Component<AppProps, AppState> {
|
|||
if (
|
||||
clicklength < 300 &&
|
||||
isIframeLikeElement(this.hitLinkElement) &&
|
||||
!isPointHittingLinkIcon(this.hitLinkElement, this.state, [
|
||||
scenePointer.x,
|
||||
scenePointer.y,
|
||||
])
|
||||
!isPointHittingLinkIcon(
|
||||
this.hitLinkElement,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
this.state,
|
||||
[scenePointer.x, scenePointer.y],
|
||||
)
|
||||
) {
|
||||
this.handleEmbeddableCenterClick(this.hitLinkElement);
|
||||
} else {
|
||||
|
@ -6039,7 +6061,9 @@ class App extends React.Component<AppProps, AppState> {
|
|||
): boolean => {
|
||||
if (this.state.activeTool.type === "selection") {
|
||||
const elements = this.scene.getNonDeletedElements();
|
||||
const elementsMap = this.scene.getNonDeletedElementsMap();
|
||||
const selectedElements = this.scene.getSelectedElements(this.state);
|
||||
|
||||
if (selectedElements.length === 1 && !this.state.editingLinearElement) {
|
||||
const elementWithTransformHandleType =
|
||||
getElementWithTransformHandleType(
|
||||
|
@ -6049,6 +6073,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
pointerDownState.origin.y,
|
||||
this.state.zoom,
|
||||
event.pointerType,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
);
|
||||
if (elementWithTransformHandleType != null) {
|
||||
this.setState({
|
||||
|
@ -6072,6 +6097,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
getResizeOffsetXY(
|
||||
pointerDownState.resize.handleType,
|
||||
selectedElements,
|
||||
elementsMap,
|
||||
pointerDownState.origin.x,
|
||||
pointerDownState.origin.y,
|
||||
),
|
||||
|
@ -6352,6 +6378,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.state,
|
||||
sceneX,
|
||||
sceneY,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
);
|
||||
|
||||
if (hasBoundTextElement(element)) {
|
||||
|
@ -6846,6 +6873,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.scene.getNonDeletedElements(),
|
||||
selectedElements,
|
||||
this.state,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -6869,6 +6897,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.scene.getNonDeletedElements(),
|
||||
selectedElements,
|
||||
this.state,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -6985,6 +7014,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
pointerCoords,
|
||||
this.state,
|
||||
!event[KEYS.CTRL_OR_CMD],
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
);
|
||||
if (!ret) {
|
||||
return;
|
||||
|
@ -7143,10 +7173,11 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.maybeCacheReferenceSnapPoints(event, selectedElements);
|
||||
|
||||
const { snapOffset, snapLines } = snapDraggedElements(
|
||||
getSelectedElements(originalElements, this.state),
|
||||
originalElements,
|
||||
dragOffset,
|
||||
this.state,
|
||||
event,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
);
|
||||
|
||||
this.setState({ snapLines });
|
||||
|
@ -7330,6 +7361,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
event,
|
||||
this.state,
|
||||
this.setState.bind(this),
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
);
|
||||
// regular box-select
|
||||
} else {
|
||||
|
@ -7360,6 +7392,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
const elementsWithinSelection = getElementsWithinSelection(
|
||||
elements,
|
||||
draggingElement,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
);
|
||||
|
||||
this.setState((prevState) => {
|
||||
|
@ -7491,7 +7524,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.setState({
|
||||
selectedElementsAreBeingDragged: false,
|
||||
});
|
||||
|
||||
const elementsMap = this.scene.getNonDeletedElementsMap();
|
||||
// Handle end of dragging a point of a linear element, might close a loop
|
||||
// and sets binding element
|
||||
if (this.state.editingLinearElement) {
|
||||
|
@ -7506,6 +7539,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
childEvent,
|
||||
this.state.editingLinearElement,
|
||||
this.state,
|
||||
elementsMap,
|
||||
);
|
||||
if (editingLinearElement !== this.state.editingLinearElement) {
|
||||
this.setState({
|
||||
|
@ -7529,6 +7563,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
childEvent,
|
||||
this.state.selectedLinearElement,
|
||||
this.state,
|
||||
elementsMap,
|
||||
);
|
||||
|
||||
const { startBindingElement, endBindingElement } =
|
||||
|
@ -7539,6 +7574,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
element,
|
||||
startBindingElement,
|
||||
endBindingElement,
|
||||
elementsMap,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -7678,6 +7714,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.state,
|
||||
this.scene,
|
||||
pointerCoords,
|
||||
elementsMap,
|
||||
);
|
||||
}
|
||||
this.setState({ suggestedBindings: [], startBoundElement: null });
|
||||
|
@ -7748,7 +7785,13 @@ class App extends React.Component<AppProps, AppState> {
|
|||
const frame = getContainingFrame(linearElement);
|
||||
|
||||
if (frame && linearElement) {
|
||||
if (!elementOverlapsWithFrame(linearElement, frame)) {
|
||||
if (
|
||||
!elementOverlapsWithFrame(
|
||||
linearElement,
|
||||
frame,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
)
|
||||
) {
|
||||
// remove the linear element from all groups
|
||||
// before removing it from the frame as well
|
||||
mutateElement(linearElement, {
|
||||
|
@ -7859,6 +7902,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
const elementsInsideFrame = getElementsInNewFrame(
|
||||
this.scene.getElementsIncludingDeleted(),
|
||||
draggingElement,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
);
|
||||
|
||||
this.scene.replaceAllElements(
|
||||
|
@ -7909,6 +7953,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.scene.getElementsIncludingDeleted(),
|
||||
frame,
|
||||
this.state,
|
||||
elementsMap,
|
||||
),
|
||||
frame,
|
||||
this,
|
||||
|
@ -8189,7 +8234,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||
if (pointerDownState.drag.hasOccurred || isResizing || isRotating) {
|
||||
(isBindingEnabled(this.state)
|
||||
? bindOrUnbindSelectedElements
|
||||
: unbindLinearElements)(this.scene.getSelectedElements(this.state));
|
||||
: unbindLinearElements)(
|
||||
this.scene.getSelectedElements(this.state),
|
||||
elementsMap,
|
||||
);
|
||||
}
|
||||
|
||||
if (activeTool.type === "laser") {
|
||||
|
@ -8719,7 +8767,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||
if (selectedElements.length > 50) {
|
||||
return;
|
||||
}
|
||||
const suggestedBindings = getEligibleElementsForBinding(selectedElements);
|
||||
const suggestedBindings = getEligibleElementsForBinding(
|
||||
selectedElements,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
);
|
||||
this.setState({ suggestedBindings });
|
||||
}
|
||||
|
||||
|
@ -9058,6 +9109,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
x: gridX - pointerDownState.originInGrid.x,
|
||||
y: gridY - pointerDownState.originInGrid.y,
|
||||
},
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
);
|
||||
|
||||
gridX += snapOffset.x;
|
||||
|
@ -9096,6 +9148,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.scene.getNonDeletedElements(),
|
||||
draggingElement as ExcalidrawFrameLikeElement,
|
||||
this.state,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
),
|
||||
});
|
||||
}
|
||||
|
@ -9215,6 +9268,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.scene.getNonDeletedElements(),
|
||||
frame,
|
||||
this.state,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
).forEach((element) => elementsToHighlight.add(element));
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue