Refactoring points

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
Mark Tolmacs 2024-09-20 21:32:32 +02:00
parent 8ca4cf3260
commit b4cb314090
No known key found for this signature in database
40 changed files with 746 additions and 783 deletions

View file

@ -5,6 +5,7 @@ import { getElementAbsoluteCoords } from ".";
import { useExcalidrawAppState } from "../components/App";
import "./ElementCanvasButtons.scss";
import { point } from "../../math";
const CONTAINER_PADDING = 5;
@ -14,8 +15,8 @@ const getContainerCoords = (
elementsMap: ElementsMap,
) => {
const [x1, y1] = getElementAbsoluteCoords(element, elementsMap);
const { x: viewportX, y: viewportY } = sceneCoordsToViewportCoords(
{ sceneX: x1 + element.width, sceneY: y1 },
const [viewportX, viewportY] = sceneCoordsToViewportCoords(
point(x1 + element.width, y1),
appState,
);
const x = viewportX - appState.offsetLeft + 10;

View file

@ -49,7 +49,7 @@ import type { ElementUpdate } from "./mutateElement";
import { mutateElement } from "./mutateElement";
import type Scene from "../scene/Scene";
import { LinearElementEditor } from "./linearElementEditor";
import { arrayToMap, tupleToCoors } from "../utils";
import { arrayToMap } from "../utils";
import { KEYS } from "../keys";
import { getBoundTextElement, handleBindTextResize } from "./textElement";
import { aabbForElement, getElementShape, pointInsideBounds } from "../shapes";
@ -389,7 +389,7 @@ export const getSuggestedBindingsForArrows = (
export const maybeBindLinearElement = (
linearElement: NonDeleted<ExcalidrawLinearElement>,
appState: AppState,
pointerCoords: { x: number; y: number },
pointerCoords: GlobalPoint,
elementsMap: NonDeletedSceneElementsMap,
elements: readonly NonDeletedExcalidrawElement[],
): void => {
@ -508,10 +508,7 @@ const unbindLinearElement = (
};
export const getHoveredElementForBinding = (
pointerCoords: {
x: number;
y: number;
},
pointer: GlobalPoint,
elements: readonly NonDeletedExcalidrawElement[],
elementsMap: NonDeletedSceneElementsMap,
fullShape?: boolean,
@ -522,7 +519,7 @@ export const getHoveredElementForBinding = (
isBindableElement(element, false) &&
bindingBorderTest(
element,
pointerCoords,
pointer,
elementsMap,
// disable fullshape snapping for frame elements so we
// can bind to frame children
@ -1177,14 +1174,12 @@ const getLinearElementEdgeCoors = (
linearElement: NonDeleted<ExcalidrawLinearElement>,
startOrEnd: "start" | "end",
elementsMap: NonDeletedSceneElementsMap,
): { x: number; y: number } => {
): GlobalPoint => {
const index = startOrEnd === "start" ? 0 : -1;
return tupleToCoors(
LinearElementEditor.getPointAtIndexGlobalCoordinates(
linearElement,
index,
elementsMap,
),
return LinearElementEditor.getPointAtIndexGlobalCoordinates(
linearElement,
index,
elementsMap,
);
};
@ -1330,7 +1325,7 @@ const newBoundElements = (
export const bindingBorderTest = (
element: NonDeleted<ExcalidrawBindableElement>,
{ x, y }: { x: number; y: number },
[x, y]: GlobalPoint,
elementsMap: NonDeletedSceneElementsMap,
fullShape?: boolean,
): boolean => {

View file

@ -42,35 +42,33 @@ export const shouldTestInside = (element: ExcalidrawElement) => {
};
export type HitTestArgs<Point extends GlobalPoint | LocalPoint> = {
x: number;
y: number;
sceneCoords: Point;
element: ExcalidrawElement;
shape: GeometricShape<Point>;
threshold?: number;
frameNameBound?: FrameNameBounds | null;
};
export const hitElementItself = <Point extends GlobalPoint | LocalPoint>({
x,
y,
export const hitElementItself = ({
sceneCoords,
element,
shape,
threshold = 10,
frameNameBound = null,
}: HitTestArgs<Point>) => {
}: HitTestArgs<GlobalPoint>) => {
let hit = shouldTestInside(element)
? // Since `inShape` tests STRICTLY againt the insides of a shape
// we would need `onShape` as well to include the "borders"
isPointInShape(point(x, y), shape) ||
isPointOnShape(point(x, y), shape, threshold)
: isPointOnShape(point(x, y), shape, threshold);
isPointInShape(sceneCoords, shape) ||
isPointOnShape(sceneCoords, shape, threshold)
: isPointOnShape(sceneCoords, shape, threshold);
// hit test against a frame's name
if (!hit && frameNameBound) {
hit = isPointInShape(point(x, y), {
hit = isPointInShape(sceneCoords, {
type: "polygon",
data: getPolygonShape(frameNameBound as ExcalidrawRectangleElement)
.data as Polygon<Point>,
.data as Polygon<GlobalPoint>,
});
}
@ -78,8 +76,7 @@ export const hitElementItself = <Point extends GlobalPoint | LocalPoint>({
};
export const hitElementBoundingBox = (
x: number,
y: number,
scenePointer: GlobalPoint,
element: ExcalidrawElement,
elementsMap: ElementsMap,
tolerance = 0,
@ -89,31 +86,27 @@ export const hitElementBoundingBox = (
y1 -= tolerance;
x2 += tolerance;
y2 += tolerance;
return isPointWithinBounds(point(x1, y1), point(x, y), point(x2, y2));
return isPointWithinBounds(point(x1, y1), scenePointer, point(x2, y2));
};
export const hitElementBoundingBoxOnly = <
Point extends GlobalPoint | LocalPoint,
>(
hitArgs: HitTestArgs<Point>,
export const hitElementBoundingBoxOnly = (
hitArgs: HitTestArgs<GlobalPoint>,
elementsMap: ElementsMap,
) => {
return (
!hitElementItself(hitArgs) &&
// bound text is considered part of the element (even if it's outside the bounding box)
!hitElementBoundText(
hitArgs.x,
hitArgs.y,
hitArgs.sceneCoords,
getBoundTextShape(hitArgs.element, elementsMap),
) &&
hitElementBoundingBox(hitArgs.x, hitArgs.y, hitArgs.element, elementsMap)
hitElementBoundingBox(hitArgs.sceneCoords, hitArgs.element, elementsMap)
);
};
export const hitElementBoundText = <Point extends GlobalPoint | LocalPoint>(
x: number,
y: number,
textShape: GeometricShape<Point> | null,
export const hitElementBoundText = (
scenePointer: GlobalPoint,
textShape: GeometricShape<GlobalPoint> | null,
): boolean => {
return !!textShape && isPointInShape(point(x, y), textShape);
return !!textShape && isPointInShape(scenePointer, textShape);
};

View file

@ -4,6 +4,7 @@ import type {
Triangle,
Vector,
Radians,
ViewportPoint,
} from "../../math";
import {
point,
@ -21,7 +22,9 @@ export const HEADING_LEFT = [-1, 0] as Heading;
export const HEADING_UP = [0, -1] as Heading;
export type Heading = [1, 0] | [0, 1] | [-1, 0] | [0, -1];
export const headingForDiamond = <Point extends GlobalPoint | LocalPoint>(
export const headingForDiamond = <
Point extends GlobalPoint | LocalPoint | ViewportPoint,
>(
a: Point,
b: Point,
) => {

View file

@ -20,7 +20,6 @@ import {
} from "./bounds";
import type {
AppState,
PointerCoords,
InteractiveCanvasAppState,
AppClassProperties,
NullableGridSize,
@ -32,7 +31,7 @@ import {
getHoveredElementForBinding,
isBindingEnabled,
} from "./binding";
import { invariant, toBrandedType, tupleToCoors } from "../utils";
import { invariant, toBrandedType } from "../utils";
import {
isBindingElement,
isElbowArrow,
@ -56,6 +55,8 @@ import {
type GlobalPoint,
type LocalPoint,
pointDistance,
pointSubtract,
pointFromPair,
} from "../../math";
import {
getBezierCurveLength,
@ -83,7 +84,7 @@ export class LinearElementEditor {
/** index */
lastClickedPoint: number;
lastClickedIsEndPoint: boolean;
origin: Readonly<{ x: number; y: number }> | null;
origin: GlobalPoint | null;
segmentMidpoint: {
value: GlobalPoint | null;
index: number | null;
@ -94,7 +95,7 @@ export class LinearElementEditor {
/** whether you're dragging a point */
public readonly isDragging: boolean;
public readonly lastUncommittedPoint: LocalPoint | null;
public readonly pointerOffset: Readonly<{ x: number; y: number }>;
public readonly pointerOffset: GlobalPoint;
public readonly startBindingElement:
| ExcalidrawBindableElement
| null
@ -115,7 +116,7 @@ export class LinearElementEditor {
this.selectedPointsIndices = null;
this.lastUncommittedPoint = null;
this.isDragging = false;
this.pointerOffset = { x: 0, y: 0 };
this.pointerOffset = point(0, 0);
this.startBindingElement = "keep";
this.endBindingElement = "keep";
this.pointerDownState = {
@ -219,11 +220,10 @@ export class LinearElementEditor {
static handlePointDragging(
event: PointerEvent,
app: AppClassProperties,
scenePointerX: number,
scenePointerY: number,
scenePointer: GlobalPoint,
maybeSuggestBinding: (
element: NonDeleted<ExcalidrawLinearElement>,
pointSceneCoords: { x: number; y: number }[],
pointSceneCoords: GlobalPoint[],
) => void,
linearElementEditor: LinearElementEditor,
scene: Scene,
@ -287,7 +287,7 @@ export class LinearElementEditor {
element,
elementsMap,
referencePoint,
point(scenePointerX, scenePointerY),
scenePointer,
event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(),
);
@ -309,8 +309,7 @@ export class LinearElementEditor {
const newDraggingPointPosition = LinearElementEditor.createPointAt(
element,
elementsMap,
scenePointerX - linearElementEditor.pointerOffset.x,
scenePointerY - linearElementEditor.pointerOffset.y,
pointSubtract(scenePointer, linearElementEditor.pointerOffset),
event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(),
);
@ -325,8 +324,10 @@ export class LinearElementEditor {
? LinearElementEditor.createPointAt(
element,
elementsMap,
scenePointerX - linearElementEditor.pointerOffset.x,
scenePointerY - linearElementEditor.pointerOffset.y,
pointSubtract(
scenePointer,
linearElementEditor.pointerOffset,
),
event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(),
)
: point(
@ -350,17 +351,15 @@ export class LinearElementEditor {
// suggest bindings for first and last point if selected
if (isBindingElement(element, false)) {
const coords: { x: number; y: number }[] = [];
const coords: GlobalPoint[] = [];
const firstSelectedIndex = selectedPointsIndices[0];
if (firstSelectedIndex === 0) {
coords.push(
tupleToCoors(
LinearElementEditor.getPointGlobalCoordinates(
element,
element.points[0],
elementsMap,
),
LinearElementEditor.getPointGlobalCoordinates(
element,
element.points[0],
elementsMap,
),
);
}
@ -369,12 +368,10 @@ export class LinearElementEditor {
selectedPointsIndices[selectedPointsIndices.length - 1];
if (lastSelectedIndex === element.points.length - 1) {
coords.push(
tupleToCoors(
LinearElementEditor.getPointGlobalCoordinates(
element,
element.points[lastSelectedIndex],
elementsMap,
),
LinearElementEditor.getPointGlobalCoordinates(
element,
element.points[lastSelectedIndex],
elementsMap,
),
);
}
@ -439,12 +436,10 @@ export class LinearElementEditor {
const bindingElement = isBindingEnabled(appState)
? getHoveredElementForBinding(
tupleToCoors(
LinearElementEditor.getPointAtIndexGlobalCoordinates(
element,
selectedPoint!,
elementsMap,
),
LinearElementEditor.getPointAtIndexGlobalCoordinates(
element,
selectedPoint!,
elementsMap,
),
elements,
elementsMap,
@ -481,7 +476,7 @@ export class LinearElementEditor {
? [pointerDownState.lastClickedPoint]
: selectedPointsIndices,
isDragging: false,
pointerOffset: { x: 0, y: 0 },
pointerOffset: point(0, 0),
};
}
@ -556,7 +551,7 @@ export class LinearElementEditor {
static getSegmentMidpointHitCoords = (
linearElementEditor: LinearElementEditor,
scenePointer: { x: number; y: number },
scenePointer: GlobalPoint,
appState: AppState,
elementsMap: ElementsMap,
): GlobalPoint | null => {
@ -569,8 +564,7 @@ export class LinearElementEditor {
element,
elementsMap,
appState.zoom,
scenePointer.x,
scenePointer.y,
scenePointer,
);
if (clickedPointIndex >= 0) {
return null;
@ -594,7 +588,7 @@ export class LinearElementEditor {
existingSegmentMidpointHitCoords[0],
existingSegmentMidpointHitCoords[1],
),
point(scenePointer.x, scenePointer.y),
scenePointer,
);
if (distance <= threshold) {
return existingSegmentMidpointHitCoords;
@ -607,7 +601,7 @@ export class LinearElementEditor {
if (midPoints[index] !== null) {
const distance = pointDistance(
point(midPoints[index]![0], midPoints[index]![1]),
point(scenePointer.x, scenePointer.y),
scenePointer,
);
if (distance <= threshold) {
return midPoints[index];
@ -705,7 +699,7 @@ export class LinearElementEditor {
event: React.PointerEvent<HTMLElement>,
app: AppClassProperties,
store: Store,
scenePointer: { x: number; y: number },
scenePointer: GlobalPoint,
linearElementEditor: LinearElementEditor,
scene: Scene,
): {
@ -759,8 +753,7 @@ export class LinearElementEditor {
LinearElementEditor.createPointAt(
element,
elementsMap,
scenePointer.x,
scenePointer.y,
scenePointer,
event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(),
),
],
@ -774,7 +767,7 @@ export class LinearElementEditor {
prevSelectedPointsIndices: linearElementEditor.selectedPointsIndices,
lastClickedPoint: -1,
lastClickedIsEndPoint: false,
origin: { x: scenePointer.x, y: scenePointer.y },
origin: scenePointer,
segmentMidpoint: {
value: segmentMidpoint,
index: segmentMidpointIndex,
@ -798,8 +791,7 @@ export class LinearElementEditor {
element,
elementsMap,
appState.zoom,
scenePointer.x,
scenePointer.y,
scenePointer,
);
// if we clicked on a point, set the element as hitElement otherwise
// it would get deselected if the point is outside the hitbox area
@ -828,7 +820,7 @@ export class LinearElementEditor {
const cy = (y1 + y2) / 2;
const targetPoint =
clickedPointIndex > -1 &&
pointRotateRads(
pointRotateRads<GlobalPoint>(
point(
element.x + element.points[clickedPointIndex][0],
element.y + element.points[clickedPointIndex][1],
@ -853,7 +845,7 @@ export class LinearElementEditor {
prevSelectedPointsIndices: linearElementEditor.selectedPointsIndices,
lastClickedPoint: clickedPointIndex,
lastClickedIsEndPoint: clickedPointIndex === element.points.length - 1,
origin: { x: scenePointer.x, y: scenePointer.y },
origin: scenePointer,
segmentMidpoint: {
value: segmentMidpoint,
index: segmentMidpointIndex,
@ -862,11 +854,8 @@ export class LinearElementEditor {
},
selectedPointsIndices: nextSelectedPointsIndices,
pointerOffset: targetPoint
? {
x: scenePointer.x - targetPoint[0],
y: scenePointer.y - targetPoint[1],
}
: { x: 0, y: 0 },
? pointSubtract(scenePointer, targetPoint)
: point(0, 0),
};
return ret;
@ -887,8 +876,7 @@ export class LinearElementEditor {
static handlePointerMove(
event: React.PointerEvent<HTMLCanvasElement>,
scenePointerX: number,
scenePointerY: number,
scenePointer: GlobalPoint,
app: AppClassProperties,
elementsMap: NonDeletedSceneElementsMap | SceneElementsMap,
): LinearElementEditor | null {
@ -928,7 +916,7 @@ export class LinearElementEditor {
element,
elementsMap,
lastCommittedPoint,
point(scenePointerX, scenePointerY),
scenePointer,
event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(),
);
@ -940,8 +928,10 @@ export class LinearElementEditor {
newPoint = LinearElementEditor.createPointAt(
element,
elementsMap,
scenePointerX - appState.editingLinearElement.pointerOffset.x,
scenePointerY - appState.editingLinearElement.pointerOffset.y,
pointSubtract(
scenePointer,
appState.editingLinearElement.pointerOffset,
),
event[KEYS.CTRL_OR_CMD] || isElbowArrow(element)
? null
: app.getEffectiveGridSize(),
@ -1057,8 +1047,7 @@ export class LinearElementEditor {
element: NonDeleted<ExcalidrawLinearElement>,
elementsMap: ElementsMap,
zoom: AppState["zoom"],
x: number,
y: number,
p: GlobalPoint,
) {
const pointHandles = LinearElementEditor.getPointsGlobalCoordinates(
element,
@ -1069,9 +1058,9 @@ export class LinearElementEditor {
// points on the left, thus should take precedence when clicking, if they
// overlap
while (--idx > -1) {
const p = pointHandles[idx];
const handles = pointHandles[idx];
if (
pointDistance(point(x, y), point(p[0], p[1])) * zoom.value <
pointDistance(p, pointFromPair(handles)) * zoom.value <
// +1px to account for outline stroke
LinearElementEditor.POINT_HANDLE_SIZE + 1
) {
@ -1084,11 +1073,14 @@ export class LinearElementEditor {
static createPointAt(
element: NonDeleted<ExcalidrawLinearElement>,
elementsMap: ElementsMap,
scenePointerX: number,
scenePointerY: number,
scenePointer: GlobalPoint,
gridSize: NullableGridSize,
): LocalPoint {
const pointerOnGrid = getGridPoint(scenePointerX, scenePointerY, gridSize);
const pointerOnGrid = getGridPoint(
scenePointer[0],
scenePointer[1],
gridSize,
);
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
const cx = (x1 + x2) / 2;
const cy = (y1 + y2) / 2;
@ -1337,7 +1329,7 @@ export class LinearElementEditor {
static shouldAddMidpoint(
linearElementEditor: LinearElementEditor,
pointerCoords: PointerCoords,
pointerCoords: GlobalPoint,
appState: AppState,
elementsMap: ElementsMap,
) {
@ -1367,10 +1359,7 @@ export class LinearElementEditor {
}
const origin = linearElementEditor.pointerDownState.origin!;
const dist = pointDistance(
point(origin.x, origin.y),
point(pointerCoords.x, pointerCoords.y),
);
const dist = pointDistance(origin, pointerCoords);
if (
!appState.editingLinearElement &&
dist < DRAGGING_THRESHOLD / appState.zoom.value
@ -1382,7 +1371,7 @@ export class LinearElementEditor {
static addMidpoint(
linearElementEditor: LinearElementEditor,
pointerCoords: PointerCoords,
pointerCoords: GlobalPoint,
app: AppClassProperties,
snapToGrid: boolean,
elementsMap: ElementsMap,
@ -1406,8 +1395,7 @@ export class LinearElementEditor {
const midpoint = LinearElementEditor.createPointAt(
element,
elementsMap,
pointerCoords.x,
pointerCoords.y,
pointerCoords,
snapToGrid && !isElbowArrow(element) ? app.getEffectiveGridSize() : null,
);
const points = [

View file

@ -1089,8 +1089,7 @@ export const getResizeOffsetXY = (
transformHandleType: MaybeTransformHandleType,
selectedElements: NonDeletedExcalidrawElement[],
elementsMap: ElementsMap,
x: number,
y: number,
[x, y]: GlobalPoint,
): [number, number] => {
const [x1, y1, x2, y2] =
selectedElements.length === 1

View file

@ -92,7 +92,7 @@ export const resizeTest = <Point extends GlobalPoint | LocalPoint>(
if (!(isLinearElement(element) && element.points.length <= 2)) {
const SPACING = SIDE_RESIZING_THRESHOLD / zoom.value;
const sides = getSelectionBorders(
point(x1 - SPACING, y1 - SPACING),
point<Point>(x1 - SPACING, y1 - SPACING),
point(x2 + SPACING, y2 + SPACING),
point(cx, cy),
element.angle,
@ -101,7 +101,11 @@ export const resizeTest = <Point extends GlobalPoint | LocalPoint>(
for (const [dir, side] of Object.entries(sides)) {
// test to see if x, y are on the line segment
if (
pointOnLineSegment(point(x, y), side as LineSegment<Point>, SPACING)
pointOnLineSegment(
point<Point>(x, y),
side as LineSegment<Point>,
SPACING,
)
) {
return dir as TransformHandleType;
}
@ -115,8 +119,7 @@ export const resizeTest = <Point extends GlobalPoint | LocalPoint>(
export const getElementWithTransformHandleType = (
elements: readonly NonDeletedExcalidrawElement[],
appState: AppState,
scenePointerX: number,
scenePointerY: number,
scenePointer: GlobalPoint,
zoom: Zoom,
pointerType: PointerType,
elementsMap: ElementsMap,
@ -130,8 +133,8 @@ export const getElementWithTransformHandleType = (
element,
elementsMap,
appState,
scenePointerX,
scenePointerY,
scenePointer[0],
scenePointer[1],
zoom,
pointerType,
device,
@ -140,12 +143,9 @@ export const getElementWithTransformHandleType = (
}, null as { element: NonDeletedExcalidrawElement; transformHandleType: MaybeTransformHandleType } | null);
};
export const getTransformHandleTypeFromCoords = <
Point extends GlobalPoint | LocalPoint,
>(
export const getTransformHandleTypeFromCoords = (
[x1, y1, x2, y2]: Bounds,
scenePointerX: number,
scenePointerY: number,
scenePointer: GlobalPoint,
zoom: Zoom,
pointerType: PointerType,
device: Device,
@ -163,7 +163,7 @@ export const getTransformHandleTypeFromCoords = <
transformHandles[key as Exclude<TransformHandleType, "rotation">]!;
return (
transformHandle &&
isInsideTransformHandle(transformHandle, scenePointerX, scenePointerY)
isInsideTransformHandle(transformHandle, scenePointer[0], scenePointer[1])
);
});
@ -178,7 +178,7 @@ export const getTransformHandleTypeFromCoords = <
const SPACING = SIDE_RESIZING_THRESHOLD / zoom.value;
const sides = getSelectionBorders(
point(x1 - SPACING, y1 - SPACING),
point<GlobalPoint>(x1 - SPACING, y1 - SPACING),
point(x2 + SPACING, y2 + SPACING),
point(cx, cy),
0 as Radians,
@ -188,8 +188,8 @@ export const getTransformHandleTypeFromCoords = <
// test to see if x, y are on the line segment
if (
pointOnLineSegment(
point(scenePointerX, scenePointerY),
side as LineSegment<Point>,
scenePointer,
side as LineSegment<GlobalPoint>,
SPACING,
)
) {

View file

@ -14,7 +14,7 @@ import {
import BinaryHeap from "../binaryheap";
import { getSizeFromPoints } from "../points";
import { aabbForElement, pointInsideBounds } from "../shapes";
import { isAnyTrue, toBrandedType, tupleToCoors } from "../utils";
import { isAnyTrue, toBrandedType } from "../utils";
import {
bindPointToSnapToElementOutline,
distanceToBindableElement,
@ -1081,13 +1081,13 @@ const getHoveredElements = (
const elements = Array.from(elementsMap.values());
return [
getHoveredElementForBinding(
tupleToCoors(origStartGlobalPoint),
origStartGlobalPoint,
elements,
nonDeletedSceneElementsMap,
true,
),
getHoveredElementForBinding(
tupleToCoors(origEndGlobalPoint),
origEndGlobalPoint,
elements,
nonDeletedSceneElementsMap,
true,

View file

@ -5,6 +5,7 @@ import { SHIFT_LOCKING_ANGLE } from "../constants";
import type { AppState, Offsets, Zoom } from "../types";
import { getCommonBounds, getElementBounds } from "./bounds";
import { viewportCoordsToSceneCoords } from "../utils";
import { point } from "../../math";
// TODO: remove invisible elements consistently actions, so that invisible elements are not recorded by the store, exported, broadcasted or persisted
// - perhaps could be as part of a standalone 'cleanup' action, in addition to 'finalize'
@ -33,25 +34,22 @@ export const isElementInViewport = (
) => {
const [x1, y1, x2, y2] = getElementBounds(element, elementsMap); // scene coordinates
const topLeftSceneCoords = viewportCoordsToSceneCoords(
{
clientX: viewTransformations.offsetLeft,
clientY: viewTransformations.offsetTop,
},
point(viewTransformations.offsetLeft, viewTransformations.offsetTop),
viewTransformations,
);
const bottomRightSceneCoords = viewportCoordsToSceneCoords(
{
clientX: viewTransformations.offsetLeft + width,
clientY: viewTransformations.offsetTop + height,
},
point(
viewTransformations.offsetLeft + width,
viewTransformations.offsetTop + height,
),
viewTransformations,
);
return (
topLeftSceneCoords.x <= x2 &&
topLeftSceneCoords.y <= y2 &&
bottomRightSceneCoords.x >= x1 &&
bottomRightSceneCoords.y >= y1
topLeftSceneCoords[0] <= x2 &&
topLeftSceneCoords[1] <= y2 &&
bottomRightSceneCoords[0] >= x1 &&
bottomRightSceneCoords[1] >= y1
);
};
@ -71,25 +69,25 @@ export const isElementCompletelyInViewport = (
) => {
const [x1, y1, x2, y2] = getCommonBounds(elements, elementsMap); // scene coordinates
const topLeftSceneCoords = viewportCoordsToSceneCoords(
{
clientX: viewTransformations.offsetLeft + (padding?.left || 0),
clientY: viewTransformations.offsetTop + (padding?.top || 0),
},
point(
viewTransformations.offsetLeft + (padding?.left || 0),
viewTransformations.offsetTop + (padding?.top || 0),
),
viewTransformations,
);
const bottomRightSceneCoords = viewportCoordsToSceneCoords(
{
clientX: viewTransformations.offsetLeft + width - (padding?.right || 0),
clientY: viewTransformations.offsetTop + height - (padding?.bottom || 0),
},
point(
viewTransformations.offsetLeft + width - (padding?.right || 0),
viewTransformations.offsetTop + height - (padding?.bottom || 0),
),
viewTransformations,
);
return (
x1 >= topLeftSceneCoords.x &&
y1 >= topLeftSceneCoords.y &&
x2 <= bottomRightSceneCoords.x &&
y2 <= bottomRightSceneCoords.y
x1 >= topLeftSceneCoords[0] &&
y1 >= topLeftSceneCoords[1] &&
x2 <= bottomRightSceneCoords[0] &&
y2 <= bottomRightSceneCoords[1]
);
};

View file

@ -29,6 +29,8 @@ import {
updateOriginalContainerCache,
} from "./containerCache";
import type { ExtractSetType } from "../utility-types";
import type { GlobalPoint } from "../../math";
import { point } from "../../math";
export const normalizeText = (text: string) => {
return (
@ -674,12 +676,12 @@ export const getContainerCenter = (
container: ExcalidrawElement,
appState: AppState,
elementsMap: ElementsMap,
) => {
): GlobalPoint => {
if (!isArrowElement(container)) {
return {
x: container.x + container.width / 2,
y: container.y + container.height / 2,
};
return point(
container.x + container.width / 2,
container.y + container.height / 2,
);
}
const points = LinearElementEditor.getPointsGlobalCoordinates(
container,
@ -692,7 +694,7 @@ export const getContainerCenter = (
container.points[index],
elementsMap,
);
return { x: midPoint[0], y: midPoint[1] };
return point(midPoint[0], midPoint[1]);
}
const index = container.points.length / 2 - 1;
let midSegmentMidpoint = LinearElementEditor.getEditorMidPoints(
@ -709,7 +711,7 @@ export const getContainerCenter = (
elementsMap,
);
}
return { x: midSegmentMidpoint[0], y: midSegmentMidpoint[1] };
return point(midSegmentMidpoint[0], midSegmentMidpoint[1]);
};
export const getContainerCoords = (container: NonDeletedExcalidrawElement) => {