diff --git a/packages/excalidraw/shapes.tsx b/packages/excalidraw/shapes.tsx index ef7aeb6cff..be86430051 100644 --- a/packages/excalidraw/shapes.tsx +++ b/packages/excalidraw/shapes.tsx @@ -1,3 +1,4 @@ +import { pointsOnBezierCurves } from "points-on-curve"; import { isPoint, pointFrom, @@ -8,7 +9,6 @@ import { type GlobalPoint, type LocalPoint, polygonFromPoints, - pointAdd, } from "../math"; import { getClosedCurveShape, @@ -16,6 +16,7 @@ import { getCurveShape, getEllipseShape, getFreedrawShape, + getPointsOnRoughCurve, getPolygonShape, type GeometricShape, } from "../utils/geometry/shape"; @@ -209,14 +210,15 @@ export const getElementShapes = ( } if (arrowhead.shape === "circle") { - // TODO: close curve into polygon / ellipse + const polygonPoints = pointsOnBezierCurves( + getPointsOnRoughCurve(arrowhead), + 15, + 2, + ).map((p) => transform(p as Point)) as Point[]; + arrowheadShapes.push({ - ...getCurveShape( - arrowhead, - element.angle, - center, - startingPoint, - ), + type: "polygon", + data: polygonFromPoints(polygonPoints), isClosed: true, }); } diff --git a/packages/utils/geometry/shape.ts b/packages/utils/geometry/shape.ts index 3a67495231..660271a090 100644 --- a/packages/utils/geometry/shape.ts +++ b/packages/utils/geometry/shape.ts @@ -288,6 +288,35 @@ export const getFreedrawShape = ( ) as GeometricShape; }; +export const getPointsOnRoughCurve = ( + roughCurve: Drawable, +) => { + const ops = getCurvePathOps(roughCurve); + + const points: Point[] = []; + let odd = false; + for (const operation of ops) { + if (operation.op === "move") { + odd = !odd; + if (odd) { + points.push(pointFrom(operation.data[0], operation.data[1])); + } + } else if (operation.op === "bcurveTo") { + if (odd) { + points.push(pointFrom(operation.data[0], operation.data[1])); + points.push(pointFrom(operation.data[2], operation.data[3])); + points.push(pointFrom(operation.data[4], operation.data[5])); + } + } else if (operation.op === "lineTo") { + if (odd) { + points.push(pointFrom(operation.data[0], operation.data[1])); + } + } + } + + return points; +}; + export const getClosedCurveShape = ( element: ExcalidrawLinearElement, roughShape: Drawable, @@ -311,31 +340,10 @@ export const getClosedCurveShape = ( }; } - const ops = getCurvePathOps(roughShape); - - const points: Point[] = []; - let odd = false; - for (const operation of ops) { - if (operation.op === "move") { - odd = !odd; - if (odd) { - points.push(pointFrom(operation.data[0], operation.data[1])); - } - } else if (operation.op === "bcurveTo") { - if (odd) { - points.push(pointFrom(operation.data[0], operation.data[1])); - points.push(pointFrom(operation.data[2], operation.data[3])); - points.push(pointFrom(operation.data[4], operation.data[5])); - } - } else if (operation.op === "lineTo") { - if (odd) { - points.push(pointFrom(operation.data[0], operation.data[1])); - } - } - } - - const polygonPoints = pointsOnBezierCurves(points, 10, 5).map((p) => - transform(p as Point), + const polygonPoints = pointsOnBezierCurves( + getPointsOnRoughCurve(roughShape), + 10, + 5, ) as Point[]; return {