refactor: simplify code

This commit is contained in:
Ryan Di
2025-08-04 13:46:33 +10:00
parent dceaa53b0c
commit 7332e76d56
3 changed files with 120 additions and 171 deletions

View File

@@ -8,7 +8,6 @@ import {
pointDistance,
vectorFromPoint,
line,
linesIntersectAt,
curveLength,
curvePointAtLength,
} from "@excalidraw/math";
@@ -29,6 +28,7 @@ import {
deconstructLinearOrFreeDrawElement,
isPathALoop,
snapLinearElementPoint,
snapToDiscreteAngle,
type SnapLine,
type Store,
} from "@excalidraw/element";
@@ -397,45 +397,16 @@ export class LinearElementEditor {
pointFrom(referencePointCoords[0], referencePointCoords[1]),
);
const firstSnapLine = snapLines[0];
if (
firstSnapLine.type === "points" &&
firstSnapLine.points.length > 1
) {
const snapLine = line(
firstSnapLine.points[0],
firstSnapLine.points[1],
);
const intersection = linesIntersectAt<GlobalPoint>(
angleLine,
snapLine,
);
const result = snapToDiscreteAngle(
snapLines,
angleLine,
pointFrom(gridX, gridY),
referencePointCoords,
);
if (intersection) {
dxFromReference = intersection[0] - referencePointCoords[0];
dyFromReference = intersection[1] - referencePointCoords[1];
const furthestPoint = firstSnapLine.points.reduce(
(furthest, point) => {
const distance = pointDistance(intersection, point);
if (distance > furthest.distance) {
return { point, distance };
}
return furthest;
},
{
point: firstSnapLine.points[0],
distance: pointDistance(
intersection,
firstSnapLine.points[0],
),
},
);
firstSnapLine.points = [furthestPoint.point, intersection];
_snapLines = [firstSnapLine];
}
}
dxFromReference = result.dxFromReference;
dyFromReference = result.dyFromReference;
_snapLines = result.snapLines;
} else if (snapLines.length > 0) {
const snappedGridX = effectiveGridX + snapOffset.x;
const snappedGridY = effectiveGridY + snapOffset.y;
@@ -1237,49 +1208,16 @@ export class LinearElementEditor {
pointFrom(lastCommittedPointCoords[0], lastCommittedPointCoords[1]),
);
const firstSnapLine = _snapLines[0];
if (
firstSnapLine.type === "points" &&
firstSnapLine.points.length > 1
) {
const snapLine = line(
firstSnapLine.points[0],
firstSnapLine.points[1],
);
const intersection = linesIntersectAt<GlobalPoint>(
angleLine,
snapLine,
);
const result = snapToDiscreteAngle(
_snapLines,
angleLine,
pointFrom(gridX, gridY),
lastCommittedPointCoords,
);
if (intersection) {
dxFromLastCommitted =
intersection[0] - lastCommittedPointCoords[0];
dyFromLastCommitted =
intersection[1] - lastCommittedPointCoords[1];
const furthestPoint = firstSnapLine.points.reduce(
(furthest, point) => {
const distance = pointDistance(intersection, point);
if (distance > furthest.distance) {
return { point, distance };
}
return furthest;
},
{
point: firstSnapLine.points[0],
distance: pointDistance(
intersection,
firstSnapLine.points[0],
),
},
);
firstSnapLine.points = [furthestPoint.point, intersection];
snapLines = [firstSnapLine];
}
} else {
snapLines = [];
}
dxFromLastCommitted = result.dxFromReference;
dyFromLastCommitted = result.dyFromReference;
snapLines = result.snapLines;
} else if (_snapLines.length > 0) {
const snappedGridX = effectiveGridX + snapOffset.x;
const snappedGridY = effectiveGridY + snapOffset.y;

View File

@@ -1,5 +1,8 @@
import {
isCloseTo,
line,
linesIntersectAt,
pointDistance,
pointFrom,
pointRotateRads,
rangeInclusive,
@@ -1643,3 +1646,79 @@ export const isActiveToolNonLinearSnappable = (
activeToolType === TOOL_TYPE.text
);
};
/**
* Snaps to discrete angle rotation logic.
* This function handles the common pattern of finding intersections between
* angle lines and snap lines, and updating the snap lines accordingly.
*
* @param snapLines - The original snap lines from snapping
* @param angleLine - The line representing the discrete angle constraint
* @param gridPosition - The grid position (original pointer position)
* @param referencePosition - The reference position (usually the start point)
* @returns Object containing updated snap lines and position deltas
*/
export const snapToDiscreteAngle = (
snapLines: SnapLine[],
angleLine: [GlobalPoint, GlobalPoint],
gridPosition: GlobalPoint,
referencePosition: GlobalPoint,
): {
snapLines: SnapLine[];
dxFromReference: number;
dyFromReference: number;
} => {
if (snapLines.length === 0) {
return {
snapLines: [],
dxFromReference: gridPosition[0] - referencePosition[0],
dyFromReference: gridPosition[1] - referencePosition[1],
};
}
const firstSnapLine = snapLines[0];
if (firstSnapLine.type === "points" && firstSnapLine.points.length > 1) {
const snapLine = line(firstSnapLine.points[0], firstSnapLine.points[1]);
const intersection = linesIntersectAt<GlobalPoint>(
line(angleLine[0], angleLine[1]),
snapLine,
);
if (intersection) {
const dxFromReference = intersection[0] - referencePosition[0];
const dyFromReference = intersection[1] - referencePosition[1];
const furthestPoint = firstSnapLine.points.reduce(
(furthest, point) => {
const distance = pointDistance(intersection, point);
if (distance > furthest.distance) {
return { point, distance };
}
return furthest;
},
{
point: firstSnapLine.points[0],
distance: pointDistance(intersection, firstSnapLine.points[0]),
},
);
const updatedSnapLine: PointSnapLine = {
type: "points",
points: [furthestPoint.point, intersection],
};
return {
snapLines: [updatedSnapLine],
dxFromReference,
dyFromReference,
};
}
}
// If no intersection found, return original snap lines with grid position
return {
snapLines,
dxFromReference: gridPosition[0] - referencePosition[0],
dyFromReference: gridPosition[1] - referencePosition[1],
};
};

View File

@@ -17,7 +17,6 @@ import {
vectorDot,
vectorNormalize,
line,
linesIntersectAt,
} from "@excalidraw/math";
import {
@@ -240,6 +239,7 @@ import {
isActiveToolNonLinearSnappable,
getSnapLinesAtPointer,
snapLinearElementPoint,
snapToDiscreteAngle,
isSnappingEnabled,
getReferenceSnapPoints,
getVisibleGaps,
@@ -6030,54 +6030,19 @@ class App extends React.Component<AppProps, AppState> {
pointFrom(lastCommittedX + rx, lastCommittedY + ry),
);
// Find intersection with first snap line
const firstSnapLine = snapLines[0];
if (
firstSnapLine.type === "points" &&
firstSnapLine.points.length > 1
) {
const snapLine = line(
firstSnapLine.points[0],
firstSnapLine.points[1],
);
const intersection = linesIntersectAt<GlobalPoint>(
angleLine,
snapLine,
);
const result = snapToDiscreteAngle(
snapLines,
angleLine,
pointFrom(gridX, gridY),
pointFrom(lastCommittedX + rx, lastCommittedY + ry),
);
if (intersection) {
dxFromLastCommitted = intersection[0] - rx - lastCommittedX;
dyFromLastCommitted = intersection[1] - ry - lastCommittedY;
dxFromLastCommitted = result.dxFromReference;
dyFromLastCommitted = result.dyFromReference;
// Find the furthest point from the intersection
const furthestPoint = firstSnapLine.points.reduce(
(furthest, point) => {
const distance = pointDistance(intersection, point);
if (distance > furthest.distance) {
return { point, distance };
}
return furthest;
},
{
point: firstSnapLine.points[0],
distance: pointDistance(
intersection,
firstSnapLine.points[0],
),
},
);
firstSnapLine.points = [furthestPoint.point, intersection];
this.setState({
snapLines: [firstSnapLine],
});
this.setState({
snapLines: [firstSnapLine],
});
}
}
this.setState({
snapLines: result.snapLines,
});
} else {
const snappedGridX = effectiveGridX + snapOffset.x;
const snappedGridY = effectiveGridY + snapOffset.y;
@@ -8814,52 +8779,19 @@ class App extends React.Component<AppProps, AppState> {
pointFrom(newElement.x, newElement.y),
);
const firstSnapLine = snapLines.find(
(snapLine) =>
snapLine.type === "points" && snapLine.points.length > 2,
const result = snapToDiscreteAngle(
snapLines,
angleLine,
pointFrom(gridX, gridY),
pointFrom(newElement.x, newElement.y),
);
if (firstSnapLine && firstSnapLine.points.length > 1) {
const snapLine = line(
firstSnapLine.points[0],
firstSnapLine.points[1],
);
const intersection = linesIntersectAt<GlobalPoint>(
angleLine,
snapLine,
);
if (intersection) {
dx = intersection[0] - newElement.x;
dy = intersection[1] - newElement.y;
// Find the furthest point from the intersection
const furthestPoint = firstSnapLine.points.reduce(
(furthest, point) => {
const distance = pointDistance(intersection, point);
if (distance > furthest.distance) {
return { point, distance };
}
return furthest;
},
{
point: firstSnapLine.points[0],
distance: pointDistance(
intersection,
firstSnapLine.points[0],
),
},
);
dx = result.dxFromReference;
dy = result.dyFromReference;
firstSnapLine.points = [furthestPoint.point, intersection];
this.setState({
snapLines: [firstSnapLine],
});
} else {
this.setState({
snapLines: [],
});
}
}
this.setState({
snapLines: result.snapLines,
});
} else {
dx = gridX + snapOffset.x - newElement.x;
dy = gridY + snapOffset.y - newElement.y;