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:
Aakansha Doshi 2024-02-16 11:35:01 +05:30 committed by GitHub
parent 73bf50e8a8
commit 47f87f4ecb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 779 additions and 270 deletions

View file

@ -7,6 +7,7 @@ import {
ExcalidrawTextElementWithContainer,
ExcalidrawFrameLikeElement,
NonDeletedSceneElementsMap,
ElementsMap,
} from "../element/types";
import {
isTextElement,
@ -137,6 +138,7 @@ export interface ExcalidrawElementWithCanvas {
const cappedElementCanvasSize = (
element: NonDeletedExcalidrawElement,
elementsMap: ElementsMap,
zoom: Zoom,
): {
width: number;
@ -155,7 +157,7 @@ const cappedElementCanvasSize = (
const padding = getCanvasPadding(element);
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
const elementWidth =
isLinearElement(element) || isFreeDrawElement(element)
? distance(x1, x2)
@ -200,7 +202,11 @@ const generateElementCanvas = (
const context = canvas.getContext("2d")!;
const padding = getCanvasPadding(element);
const { width, height, scale } = cappedElementCanvasSize(element, zoom);
const { width, height, scale } = cappedElementCanvasSize(
element,
elementsMap,
zoom,
);
canvas.width = width;
canvas.height = height;
@ -209,7 +215,7 @@ const generateElementCanvas = (
let canvasOffsetY = 0;
if (isLinearElement(element) || isFreeDrawElement(element)) {
const [x1, y1] = getElementAbsoluteCoords(element);
const [x1, y1] = getElementAbsoluteCoords(element, elementsMap);
canvasOffsetX =
element.x > x1
@ -468,7 +474,7 @@ const drawElementFromCanvas = (
const element = elementWithCanvas.element;
const padding = getCanvasPadding(element);
const zoom = elementWithCanvas.scale;
let [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
let [x1, y1, x2, y2] = getElementAbsoluteCoords(element, allElementsMap);
// Free draw elements will otherwise "shuffle" as the min x and y change
if (isFreeDrawElement(element)) {
@ -513,8 +519,10 @@ const drawElementFromCanvas = (
elementWithCanvas.canvas.height,
);
const [, , , , boundTextCx, boundTextCy] =
getElementAbsoluteCoords(boundTextElement);
const [, , , , boundTextCx, boundTextCy] = getElementAbsoluteCoords(
boundTextElement,
allElementsMap,
);
tempCanvasContext.rotate(-element.angle);
@ -694,7 +702,7 @@ export const renderElement = (
ShapeCache.generateElementShape(element, null);
if (renderConfig.isExporting) {
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
const cx = (x1 + x2) / 2 + appState.scrollX;
const cy = (y1 + y2) / 2 + appState.scrollY;
const shiftX = (x2 - x1) / 2 - (element.x - x1);
@ -737,7 +745,7 @@ export const renderElement = (
// rely on existing shapes
ShapeCache.generateElementShape(element, renderConfig);
if (renderConfig.isExporting) {
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
const cx = (x1 + x2) / 2 + appState.scrollX;
const cy = (y1 + y2) / 2 + appState.scrollY;
let shiftX = (x2 - x1) / 2 - (element.x - x1);
@ -749,6 +757,7 @@ export const renderElement = (
LinearElementEditor.getBoundTextElementPosition(
container,
element as ExcalidrawTextElementWithContainer,
elementsMap,
);
shiftX = (x2 - x1) / 2 - (boundTextCoords.x - x1);
shiftY = (y2 - y1) / 2 - (boundTextCoords.y - y1);
@ -804,8 +813,10 @@ export const renderElement = (
tempCanvasContext.rotate(-element.angle);
// Shift the canvas to center of bound text
const [, , , , boundTextCx, boundTextCy] =
getElementAbsoluteCoords(boundTextElement);
const [, , , , boundTextCx, boundTextCy] = getElementAbsoluteCoords(
boundTextElement,
elementsMap,
);
const boundTextShiftX = (x1 + x2) / 2 - boundTextCx;
const boundTextShiftY = (y1 + y2) / 2 - boundTextCy;
tempCanvasContext.translate(-boundTextShiftX, -boundTextShiftY);
@ -939,17 +950,18 @@ export const renderElementToSvg = (
renderConfig: SVGRenderConfig,
) => {
const offset = { x: offsetX, y: offsetY };
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
let cx = (x2 - x1) / 2 - (element.x - x1);
let cy = (y2 - y1) / 2 - (element.y - y1);
if (isTextElement(element)) {
const container = getContainerElement(element, elementsMap);
if (isArrowElement(container)) {
const [x1, y1, x2, y2] = getElementAbsoluteCoords(container);
const [x1, y1, x2, y2] = getElementAbsoluteCoords(container, elementsMap);
const boundTextCoords = LinearElementEditor.getBoundTextElementPosition(
container,
element as ExcalidrawTextElementWithContainer,
elementsMap,
);
cx = (x2 - x1) / 2 - (boundTextCoords.x - x1);
cy = (y2 - y1) / 2 - (boundTextCoords.y - y1);
@ -1151,6 +1163,7 @@ export const renderElementToSvg = (
const boundTextCoords = LinearElementEditor.getBoundTextElementPosition(
element,
boundText,
elementsMap,
);
const maskX = offsetX + boundTextCoords.x - element.x;

View file

@ -17,6 +17,7 @@ import {
GroupId,
ExcalidrawBindableElement,
ExcalidrawFrameLikeElement,
ElementsMap,
} from "../element/types";
import {
getElementAbsoluteCoords,
@ -256,7 +257,10 @@ const renderLinearPointHandles = (
context.save();
context.translate(appState.scrollX, appState.scrollY);
context.lineWidth = 1 / appState.zoom.value;
const points = LinearElementEditor.getPointsGlobalCoordinates(element);
const points = LinearElementEditor.getPointsGlobalCoordinates(
element,
elementsMap,
);
const { POINT_HANDLE_SIZE } = LinearElementEditor;
const radius = appState.editingLinearElement
@ -340,6 +344,7 @@ const highlightPoint = (
const renderLinearElementPointHighlight = (
context: CanvasRenderingContext2D,
appState: InteractiveCanvasAppState,
elementsMap: ElementsMap,
) => {
const { elementId, hoverPointIndex } = appState.selectedLinearElement!;
if (
@ -356,6 +361,7 @@ const renderLinearElementPointHighlight = (
const point = LinearElementEditor.getPointAtIndexGlobalCoordinates(
element,
hoverPointIndex,
elementsMap,
);
context.save();
context.translate(appState.scrollX, appState.scrollY);
@ -510,12 +516,22 @@ const _renderInteractiveScene = ({
appState.suggestedBindings
.filter((binding) => binding != null)
.forEach((suggestedBinding) => {
renderBindingHighlight(context, appState, suggestedBinding!);
renderBindingHighlight(
context,
appState,
suggestedBinding!,
elementsMap,
);
});
}
if (appState.frameToHighlight) {
renderFrameHighlight(context, appState, appState.frameToHighlight);
renderFrameHighlight(
context,
appState,
appState.frameToHighlight,
elementsMap,
);
}
if (appState.elementsToHighlight) {
@ -545,7 +561,7 @@ const _renderInteractiveScene = ({
appState.selectedLinearElement &&
appState.selectedLinearElement.hoverPointIndex >= 0
) {
renderLinearElementPointHighlight(context, appState);
renderLinearElementPointHighlight(context, appState, elementsMap);
}
// Paint selected elements
if (!appState.multiElement && !appState.editingLinearElement) {
@ -608,7 +624,7 @@ const _renderInteractiveScene = ({
if (selectionColors.length) {
const [elementX1, elementY1, elementX2, elementY2, cx, cy] =
getElementAbsoluteCoords(element, true);
getElementAbsoluteCoords(element, elementsMap, true);
selections.push({
angle: element.angle,
elementX1,
@ -666,7 +682,8 @@ const _renderInteractiveScene = ({
const transformHandles = getTransformHandles(
selectedElements[0],
appState.zoom,
"mouse", // when we render we don't know which pointer type so use mouse
elementsMap,
"mouse", // when we render we don't know which pointer type so use mouse,
);
if (!appState.viewModeEnabled && showBoundingBox) {
renderTransformHandles(
@ -953,7 +970,11 @@ const _renderStaticScene = ({
element.groupIds.length > 0 &&
appState.frameToHighlight &&
appState.selectedElementIds[element.id] &&
(elementOverlapsWithFrame(element, appState.frameToHighlight) ||
(elementOverlapsWithFrame(
element,
appState.frameToHighlight,
elementsMap,
) ||
element.groupIds.find((groupId) => groupsToBeAddedToFrame.has(groupId)))
) {
element.groupIds.forEach((groupId) =>
@ -1004,7 +1025,7 @@ const _renderStaticScene = ({
);
}
if (!isExporting) {
renderLinkIcon(element, context, appState);
renderLinkIcon(element, context, appState, elementsMap);
}
} catch (error: any) {
console.error(error);
@ -1048,7 +1069,7 @@ const _renderStaticScene = ({
);
}
if (!isExporting) {
renderLinkIcon(element, context, appState);
renderLinkIcon(element, context, appState, elementsMap);
}
};
// - when exporting the whole canvas, we DO NOT apply clipping
@ -1247,6 +1268,7 @@ const renderBindingHighlight = (
context: CanvasRenderingContext2D,
appState: InteractiveCanvasAppState,
suggestedBinding: SuggestedBinding,
elementsMap: ElementsMap,
) => {
const renderHighlight = Array.isArray(suggestedBinding)
? renderBindingHighlightForSuggestedPointBinding
@ -1254,7 +1276,7 @@ const renderBindingHighlight = (
context.save();
context.translate(appState.scrollX, appState.scrollY);
renderHighlight(context, suggestedBinding as any);
renderHighlight(context, suggestedBinding as any, elementsMap);
context.restore();
};
@ -1262,8 +1284,9 @@ const renderBindingHighlight = (
const renderBindingHighlightForBindableElement = (
context: CanvasRenderingContext2D,
element: ExcalidrawBindableElement,
elementsMap: ElementsMap,
) => {
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
const width = x2 - x1;
const height = y2 - y1;
const threshold = maxBindingGap(element, width, height);
@ -1323,8 +1346,9 @@ const renderFrameHighlight = (
context: CanvasRenderingContext2D,
appState: InteractiveCanvasAppState,
frame: NonDeleted<ExcalidrawFrameLikeElement>,
elementsMap: ElementsMap,
) => {
const [x1, y1, x2, y2] = getElementAbsoluteCoords(frame);
const [x1, y1, x2, y2] = getElementAbsoluteCoords(frame, elementsMap);
const width = x2 - x1;
const height = y2 - y1;
@ -1398,6 +1422,7 @@ const renderElementsBoxHighlight = (
const renderBindingHighlightForSuggestedPointBinding = (
context: CanvasRenderingContext2D,
suggestedBinding: SuggestedPointBinding,
elementsMap: ElementsMap,
) => {
const [element, startOrEnd, bindableElement] = suggestedBinding;
@ -1416,6 +1441,7 @@ const renderBindingHighlightForSuggestedPointBinding = (
const [x, y] = LinearElementEditor.getPointAtIndexGlobalCoordinates(
element,
index,
elementsMap,
);
fillCircle(context, x, y, threshold);
});
@ -1426,9 +1452,10 @@ const renderLinkIcon = (
element: NonDeletedExcalidrawElement,
context: CanvasRenderingContext2D,
appState: StaticCanvasAppState,
elementsMap: ElementsMap,
) => {
if (element.link && !appState.selectedElementIds[element.id]) {
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
const [x, y, width, height] = getLinkHandleFromCoords(
[x1, y1, x2, y2],
element.angle,