@tldraw/editor 3.13.0-canary.a2884bb1bab2 → 3.13.0-canary.ae38fb277ff7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +114 -111
- package/dist-cjs/index.js +7 -22
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +2 -1
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/Shape.js +12 -8
- package/dist-cjs/lib/components/Shape.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +27 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +14 -12
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +17 -11
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultSpinner.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultSpinner.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +65 -35
- package/dist-cjs/lib/editor/Editor.js.map +3 -3
- package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TextManager.js +10 -0
- package/dist-cjs/lib/editor/managers/TextManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js.map +2 -2
- package/dist-cjs/lib/exports/getSvgJsx.js +12 -3
- package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
- package/dist-cjs/lib/hooks/useDocumentEvents.js +3 -2
- package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useEditorComponents.js +16 -15
- package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
- package/dist-cjs/lib/license/LicenseManager.js +8 -1
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/options.js.map +2 -2
- package/dist-cjs/lib/primitives/Box.js +16 -0
- package/dist-cjs/lib/primitives/Box.js.map +2 -2
- package/dist-cjs/lib/primitives/Mat.js +1 -1
- package/dist-cjs/lib/primitives/Mat.js.map +2 -2
- package/dist-cjs/lib/primitives/Vec.js +20 -0
- package/dist-cjs/lib/primitives/Vec.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Arc2d.js +2 -2
- package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Circle2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/CubicSpline2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Edge2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Edge2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js +91 -20
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Group2d.js +55 -2
- package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Point2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Polyline2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Stadium2d.js.map +2 -2
- package/dist-cjs/lib/utils/areShapesContentEqual.js +25 -0
- package/dist-cjs/lib/utils/areShapesContentEqual.js.map +7 -0
- package/dist-cjs/lib/utils/debug-flags.js +5 -2
- package/dist-cjs/lib/utils/debug-flags.js.map +2 -2
- package/dist-cjs/lib/utils/dom.js +3 -3
- package/dist-cjs/lib/utils/dom.js.map +2 -2
- package/dist-cjs/lib/utils/nearestMultiple.js +34 -0
- package/dist-cjs/lib/utils/nearestMultiple.js.map +7 -0
- package/dist-cjs/lib/utils/rotation.js +5 -5
- package/dist-cjs/lib/utils/rotation.js.map +2 -2
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +114 -111
- package/dist-esm/index.mjs +9 -41
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +2 -1
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/Shape.mjs +12 -8
- package/dist-esm/lib/components/Shape.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +27 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +14 -12
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +17 -11
- package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultSpinner.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultSpinner.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +65 -35
- package/dist-esm/lib/editor/Editor.mjs.map +3 -3
- package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TextManager.mjs +10 -0
- package/dist-esm/lib/editor/managers/TextManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs.map +2 -2
- package/dist-esm/lib/exports/getSvgJsx.mjs +12 -3
- package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
- package/dist-esm/lib/hooks/useDocumentEvents.mjs +3 -2
- package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useEditorComponents.mjs +16 -15
- package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseManager.mjs +8 -1
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/options.mjs.map +2 -2
- package/dist-esm/lib/primitives/Box.mjs +16 -0
- package/dist-esm/lib/primitives/Box.mjs.map +2 -2
- package/dist-esm/lib/primitives/Mat.mjs +1 -1
- package/dist-esm/lib/primitives/Mat.mjs.map +2 -2
- package/dist-esm/lib/primitives/Vec.mjs +20 -0
- package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs +2 -2
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Circle2d.mjs +1 -1
- package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +1 -1
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/CubicSpline2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Edge2d.mjs +1 -1
- package/dist-esm/lib/primitives/geometry/Edge2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +92 -21
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs +55 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Point2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Polyline2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Stadium2d.mjs.map +2 -2
- package/dist-esm/lib/utils/areShapesContentEqual.mjs +5 -0
- package/dist-esm/lib/utils/areShapesContentEqual.mjs.map +7 -0
- package/dist-esm/lib/utils/debug-flags.mjs +5 -2
- package/dist-esm/lib/utils/debug-flags.mjs.map +2 -2
- package/dist-esm/lib/utils/dom.mjs +3 -3
- package/dist-esm/lib/utils/dom.mjs.map +2 -2
- package/dist-esm/lib/utils/nearestMultiple.mjs +14 -0
- package/dist-esm/lib/utils/nearestMultiple.mjs.map +7 -0
- package/dist-esm/lib/utils/rotation.mjs +5 -5
- package/dist-esm/lib/utils/rotation.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +40 -4
- package/package.json +7 -7
- package/src/index.ts +16 -31
- package/src/lib/TldrawEditor.tsx +6 -1
- package/src/lib/components/Shape.tsx +14 -10
- package/src/lib/components/default-components/DefaultCanvas.tsx +32 -2
- package/src/lib/components/default-components/DefaultErrorFallback.tsx +25 -14
- package/src/lib/components/default-components/DefaultShapeIndicator.tsx +17 -8
- package/src/lib/components/default-components/DefaultSpinner.tsx +1 -1
- package/src/lib/editor/Editor.test.ts +1 -1
- package/src/lib/editor/Editor.ts +62 -34
- package/src/lib/editor/managers/SnapManager/HandleSnaps.ts +0 -1
- package/src/lib/editor/managers/TextManager.ts +12 -0
- package/src/lib/editor/shapes/ShapeUtil.ts +22 -2
- package/src/lib/editor/shapes/shared/getPerfectDashProps.ts +9 -9
- package/src/lib/exports/getSvgJsx.tsx +16 -7
- package/src/lib/hooks/useDocumentEvents.ts +7 -2
- package/src/lib/hooks/useEditorComponents.tsx +32 -28
- package/src/lib/license/LicenseManager.test.ts +40 -0
- package/src/lib/license/LicenseManager.ts +13 -1
- package/src/lib/options.ts +4 -0
- package/src/lib/primitives/Box.ts +20 -0
- package/src/lib/primitives/Mat.ts +5 -4
- package/src/lib/primitives/Vec.ts +23 -0
- package/src/lib/primitives/geometry/Arc2d.ts +5 -5
- package/src/lib/primitives/geometry/Circle2d.ts +4 -4
- package/src/lib/primitives/geometry/CubicBezier2d.ts +4 -4
- package/src/lib/primitives/geometry/CubicSpline2d.ts +3 -3
- package/src/lib/primitives/geometry/Edge2d.ts +3 -3
- package/src/lib/primitives/geometry/Ellipse2d.ts +3 -3
- package/src/lib/primitives/geometry/Geometry2d.test.ts +42 -0
- package/src/lib/primitives/geometry/Geometry2d.ts +123 -35
- package/src/lib/primitives/geometry/Group2d.ts +70 -7
- package/src/lib/primitives/geometry/Point2d.ts +2 -2
- package/src/lib/primitives/geometry/Polyline2d.ts +3 -3
- package/src/lib/primitives/geometry/Stadium2d.ts +3 -3
- package/src/lib/test/currentToolIdMask.test.ts +1 -1
- package/src/lib/test/user.test.ts +1 -1
- package/src/lib/utils/areShapesContentEqual.ts +4 -0
- package/src/lib/utils/debug-flags.ts +7 -2
- package/src/lib/utils/dom.ts +4 -4
- package/src/lib/utils/nearestMultiple.ts +13 -0
- package/src/lib/utils/rotation.ts +8 -6
- package/src/lib/utils/sync/LocalIndexedDb.test.ts +1 -1
- package/src/lib/utils/sync/TLLocalSyncClient.test.ts +1 -1
- package/src/version.ts +3 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/primitives/geometry/Geometry2d.ts"],
|
|
4
|
-
"sourcesContent": ["import { assert } from '@tldraw/utils'\nimport { Box } from '../Box'\nimport { Mat, MatModel } from '../Mat'\nimport { Vec, VecLike } from '../Vec'\nimport {\n\tintersectCirclePolygon,\n\tintersectCirclePolyline,\n\tintersectLineSegmentPolygon,\n\tintersectLineSegmentPolyline,\n\tintersectPolys,\n} from '../intersect'\nimport { approximately, pointInPolygon } from '../utils'\n\n/**\n * Filter geometry within a group.\n *\n * Filters are ignored when called directly on primitive geometries, but can be used to narrow down\n * the results of an operation on `Group2d` geometries.\n *\n * @public\n */\nexport interface Geometry2dFilters {\n\treadonly includeLabels?: boolean\n\treadonly includeInternal?: boolean\n}\n\n/** @public */\nexport const Geometry2dFilters: {\n\tEXCLUDE_NON_STANDARD: Geometry2dFilters\n\tINCLUDE_ALL: Geometry2dFilters\n\tEXCLUDE_LABELS: Geometry2dFilters\n\tEXCLUDE_INTERNAL: Geometry2dFilters\n} = {\n\tEXCLUDE_NON_STANDARD: {\n\t\tincludeLabels: false,\n\t\tincludeInternal: false,\n\t},\n\tINCLUDE_ALL: { includeLabels: true, includeInternal: true },\n\tEXCLUDE_LABELS: { includeLabels: false, includeInternal: true },\n\tEXCLUDE_INTERNAL: { includeLabels: true, includeInternal: false },\n}\n\n/** @public */\nexport interface TransformedGeometry2dOptions {\n\tisLabel?: boolean\n\tisInternal?: boolean\n\tdebugColor?: string\n\tignore?: boolean\n}\n\n/** @public */\nexport interface Geometry2dOptions extends TransformedGeometry2dOptions {\n\tisFilled: boolean\n\tisClosed: boolean\n}\n\n/** @public */\nexport abstract class Geometry2d {\n\tisFilled = false\n\tisClosed = true\n\tisLabel = false\n\tisInternal = false\n\tdebugColor?: string\n\tignore?: boolean\n\n\tconstructor(opts: Geometry2dOptions) {\n\t\tthis.isFilled = opts.isFilled\n\t\tthis.isClosed = opts.isClosed\n\t\tthis.isLabel = opts.isLabel ?? false\n\t\tthis.isInternal = opts.isInternal ?? false\n\t\tthis.debugColor = opts.debugColor\n\t\tthis.ignore = opts.ignore\n\t}\n\n\tisExcludedByFilter(filters?: Geometry2dFilters) {\n\t\tif (!filters) return false\n\t\tif (this.isLabel && !filters.includeLabels) return true\n\t\tif (this.isInternal && !filters.includeInternal) return true\n\t\treturn false\n\t}\n\n\tabstract getVertices(filters: Geometry2dFilters): Vec[]\n\n\tabstract nearestPoint(point: Vec, _filters?: Geometry2dFilters): Vec\n\n\thitTestPoint(point: Vec, margin = 0, hitInside = false, _filters?: Geometry2dFilters) {\n\t\t// First check whether the point is inside\n\t\tif (this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices)) {\n\t\t\treturn true\n\t\t}\n\t\t// Then check whether the distance is within the margin\n\t\treturn Vec.Dist2(point, this.nearestPoint(point)) <= margin * margin\n\t}\n\n\tdistanceToPoint(point: Vec, hitInside = false, filters?: Geometry2dFilters) {\n\t\treturn (\n\t\t\tpoint.dist(this.nearestPoint(point, filters)) *\n\t\t\t(this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices)\n\t\t\t\t? -1\n\t\t\t\t: 1)\n\t\t)\n\t}\n\n\tdistanceToLineSegment(A: Vec, B: Vec, filters?: Geometry2dFilters) {\n\t\tif (A.equals(B)) return this.distanceToPoint(A, false, filters)\n\t\tconst { vertices } = this\n\t\tlet nearest: Vec | undefined\n\t\tlet dist = Infinity\n\t\tlet d: number, p: Vec, q: Vec\n\t\tfor (let i = 0; i < vertices.length; i++) {\n\t\t\tp = vertices[i]\n\t\t\tq = Vec.NearestPointOnLineSegment(A, B, p, true)\n\t\t\td = Vec.Dist2(p, q)\n\t\t\tif (d < dist) {\n\t\t\t\tdist = d\n\t\t\t\tnearest = q\n\t\t\t}\n\t\t}\n\t\tif (!nearest) throw Error('nearest point not found')\n\t\treturn this.isClosed && this.isFilled && pointInPolygon(nearest, this.vertices) ? -dist : dist\n\t}\n\n\thitTestLineSegment(A: Vec, B: Vec, distance = 0, filters?: Geometry2dFilters): boolean {\n\t\treturn this.distanceToLineSegment(A, B, filters) <= distance\n\t}\n\n\tintersectLineSegment(A: VecLike, B: VecLike, _filters?: Geometry2dFilters): VecLike[] {\n\t\tconst intersections = this.isClosed\n\t\t\t? intersectLineSegmentPolygon(A, B, this.vertices)\n\t\t\t: intersectLineSegmentPolyline(A, B, this.vertices)\n\n\t\treturn intersections ?? []\n\t}\n\n\tintersectCircle(center: VecLike, radius: number, _filters?: Geometry2dFilters): VecLike[] {\n\t\tconst intersections = this.isClosed\n\t\t\t? intersectCirclePolygon(center, radius, this.vertices)\n\t\t\t: intersectCirclePolyline(center, radius, this.vertices)\n\n\t\treturn intersections ?? []\n\t}\n\n\tintersectPolygon(polygon: VecLike[], _filters?: Geometry2dFilters): VecLike[] {\n\t\treturn intersectPolys(polygon, this.vertices, true, this.isClosed)\n\t}\n\n\tintersectPolyline(polyline: VecLike[], _filters?: Geometry2dFilters): VecLike[] {\n\t\treturn intersectPolys(polyline, this.vertices, false, this.isClosed)\n\t}\n\n\t/** @deprecated Iterate the vertices instead. */\n\tnearestPointOnLineSegment(A: Vec, B: Vec): Vec {\n\t\tconst { vertices } = this\n\t\tlet nearest: Vec | undefined\n\t\tlet dist = Infinity\n\t\tlet d: number, p: Vec, q: Vec\n\t\tfor (let i = 0; i < vertices.length; i++) {\n\t\t\tp = vertices[i]\n\t\t\tq = Vec.NearestPointOnLineSegment(A, B, p, true)\n\t\t\td = Vec.Dist2(p, q)\n\t\t\tif (d < dist) {\n\t\t\t\tdist = d\n\t\t\t\tnearest = q\n\t\t\t}\n\t\t}\n\t\tif (!nearest) throw Error('nearest point not found')\n\t\treturn nearest\n\t}\n\n\tisPointInBounds(point: Vec, margin = 0) {\n\t\tconst { bounds } = this\n\t\treturn !(\n\t\t\tpoint.x < bounds.minX - margin ||\n\t\t\tpoint.y < bounds.minY - margin ||\n\t\t\tpoint.x > bounds.maxX + margin ||\n\t\t\tpoint.y > bounds.maxY + margin\n\t\t)\n\t}\n\n\ttransform(transform: MatModel, opts?: TransformedGeometry2dOptions): Geometry2d {\n\t\treturn new TransformedGeometry2d(this, transform, opts)\n\t}\n\n\tprivate _vertices: Vec[] | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget vertices(): Vec[] {\n\t\tif (!this._vertices) {\n\t\t\tthis._vertices = this.getVertices(Geometry2dFilters.EXCLUDE_LABELS)\n\t\t}\n\n\t\treturn this._vertices\n\t}\n\n\tgetBounds() {\n\t\treturn Box.FromPoints(this.vertices)\n\t}\n\n\tprivate _bounds: Box | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget bounds(): Box {\n\t\tif (!this._bounds) {\n\t\t\tthis._bounds = this.getBounds()\n\t\t}\n\t\treturn this._bounds\n\t}\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget center() {\n\t\treturn this.bounds.center\n\t}\n\n\tprivate _area: number | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget area() {\n\t\tif (!this._area) {\n\t\t\tthis._area = this.getArea()\n\t\t}\n\t\treturn this._area\n\t}\n\n\tgetArea() {\n\t\tif (!this.isClosed) {\n\t\t\treturn 0\n\t\t}\n\t\tconst { vertices } = this\n\t\tlet area = 0\n\t\tfor (let i = 0, n = vertices.length; i < n; i++) {\n\t\t\tconst curr = vertices[i]\n\t\t\tconst next = vertices[(i + 1) % n]\n\t\t\tarea += curr.x * next.y - next.x * curr.y\n\t\t}\n\t\treturn area / 2\n\t}\n\n\ttoSimpleSvgPath() {\n\t\tlet path = ''\n\n\t\tconst { vertices } = this\n\t\tconst n = vertices.length\n\n\t\tif (n === 0) return path\n\n\t\tpath += `M${vertices[0].x},${vertices[0].y}`\n\n\t\tfor (let i = 1; i < n; i++) {\n\t\t\tpath += `L${vertices[i].x},${vertices[i].y}`\n\t\t}\n\n\t\tif (this.isClosed) {\n\t\t\tpath += 'Z'\n\t\t}\n\n\t\treturn path\n\t}\n\n\tprivate _length?: number\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget length() {\n\t\tif (this._length) return this._length\n\t\tthis._length = this.getLength()\n\t\treturn this._length\n\t}\n\n\tgetLength() {\n\t\tconst { vertices } = this\n\t\tlet n1: Vec,\n\t\t\tp1 = vertices[0],\n\t\t\tlength = 0\n\t\tfor (let i = 1; i < vertices.length; i++) {\n\t\t\tn1 = vertices[i]\n\t\t\tlength += Vec.Dist2(p1, n1)\n\t\t\tp1 = n1\n\t\t}\n\t\treturn Math.sqrt(length)\n\t}\n\n\tabstract getSvgPathData(first: boolean): string\n}\n\n// =================================================================================================\n// Because Geometry2d.transform depends on TransformedGeometry2d, we need to define it here instead\n// of in its own files. This prevents a circular import error.\n// =================================================================================================\n\n/** @public */\nexport class TransformedGeometry2d extends Geometry2d {\n\tprivate readonly inverse: MatModel\n\tprivate readonly decomposed\n\n\tconstructor(\n\t\tprivate readonly geometry: Geometry2d,\n\t\tprivate readonly matrix: MatModel,\n\t\topts?: TransformedGeometry2dOptions\n\t) {\n\t\tsuper(geometry)\n\t\tthis.inverse = Mat.Inverse(matrix)\n\t\tthis.decomposed = Mat.Decompose(matrix)\n\n\t\tif (opts) {\n\t\t\tif (opts.isLabel != null) this.isLabel = opts.isLabel\n\t\t\tif (opts.isInternal != null) this.isInternal = opts.isInternal\n\t\t\tif (opts.debugColor != null) this.debugColor = opts.debugColor\n\t\t\tif (opts.ignore != null) this.ignore = opts.ignore\n\t\t}\n\n\t\tassert(\n\t\t\tapproximately(this.decomposed.scaleX, this.decomposed.scaleY),\n\t\t\t'non-uniform scaling is not yet supported'\n\t\t)\n\t}\n\n\tgetVertices(filters: Geometry2dFilters): Vec[] {\n\t\treturn this.geometry.getVertices(filters).map((v) => Mat.applyToPoint(this.matrix, v))\n\t}\n\n\tnearestPoint(point: Vec, filters?: Geometry2dFilters): Vec {\n\t\treturn Mat.applyToPoint(\n\t\t\tthis.matrix,\n\t\t\tthis.geometry.nearestPoint(Mat.applyToPoint(this.inverse, point), filters)\n\t\t)\n\t}\n\n\toverride hitTestPoint(\n\t\tpoint: Vec,\n\t\tmargin = 0,\n\t\thitInside?: boolean,\n\t\tfilters?: Geometry2dFilters\n\t): boolean {\n\t\treturn this.geometry.hitTestPoint(\n\t\t\tMat.applyToPoint(this.inverse, point),\n\t\t\tmargin / this.decomposed.scaleX,\n\t\t\thitInside,\n\t\t\tfilters\n\t\t)\n\t}\n\n\toverride distanceToPoint(point: Vec, hitInside = false, filters?: Geometry2dFilters) {\n\t\treturn (\n\t\t\tthis.geometry.distanceToPoint(Mat.applyToPoint(this.inverse, point), hitInside, filters) *\n\t\t\tthis.decomposed.scaleX\n\t\t)\n\t}\n\n\toverride distanceToLineSegment(A: Vec, B: Vec, filters?: Geometry2dFilters) {\n\t\treturn (\n\t\t\tthis.geometry.distanceToLineSegment(\n\t\t\t\tMat.applyToPoint(this.inverse, A),\n\t\t\t\tMat.applyToPoint(this.inverse, B),\n\t\t\t\tfilters\n\t\t\t) * this.decomposed.scaleX\n\t\t)\n\t}\n\n\toverride hitTestLineSegment(A: Vec, B: Vec, distance = 0, filters?: Geometry2dFilters): boolean {\n\t\treturn this.geometry.hitTestLineSegment(\n\t\t\tMat.applyToPoint(this.inverse, A),\n\t\t\tMat.applyToPoint(this.inverse, B),\n\t\t\tdistance / this.decomposed.scaleX,\n\t\t\tfilters\n\t\t)\n\t}\n\n\toverride intersectLineSegment(A: VecLike, B: VecLike, filters?: Geometry2dFilters) {\n\t\treturn this.geometry.intersectLineSegment(\n\t\t\tMat.applyToPoint(this.inverse, A),\n\t\t\tMat.applyToPoint(this.inverse, B),\n\t\t\tfilters\n\t\t)\n\t}\n\n\toverride intersectCircle(center: VecLike, radius: number, filters?: Geometry2dFilters) {\n\t\treturn this.geometry.intersectCircle(\n\t\t\tMat.applyToPoint(this.inverse, center),\n\t\t\tradius / this.decomposed.scaleX,\n\t\t\tfilters\n\t\t)\n\t}\n\n\toverride intersectPolygon(polygon: VecLike[], filters?: Geometry2dFilters): VecLike[] {\n\t\treturn this.geometry.intersectPolygon(Mat.applyToPoints(this.inverse, polygon), filters)\n\t}\n\n\toverride intersectPolyline(polyline: VecLike[], filters?: Geometry2dFilters): VecLike[] {\n\t\treturn this.geometry.intersectPolyline(Mat.applyToPoints(this.inverse, polyline), filters)\n\t}\n\n\toverride transform(transform: MatModel, opts?: TransformedGeometry2dOptions): Geometry2d {\n\t\treturn new TransformedGeometry2d(this.geometry, Mat.Multiply(transform, this.matrix), {\n\t\t\tisLabel: opts?.isLabel ?? this.isLabel,\n\t\t\tisInternal: opts?.isInternal ?? this.isInternal,\n\t\t\tdebugColor: opts?.debugColor ?? this.debugColor,\n\t\t\tignore: opts?.ignore ?? this.ignore,\n\t\t})\n\t}\n\n\tgetSvgPathData(): string {\n\t\tthrow new Error('Cannot get SVG path data for transformed geometry.')\n\t}\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,
|
|
4
|
+
"sourcesContent": ["import { assert, invLerp } from '@tldraw/utils'\nimport { Box } from '../Box'\nimport { Mat, MatModel } from '../Mat'\nimport { Vec, VecLike } from '../Vec'\nimport {\n\tintersectCirclePolygon,\n\tintersectCirclePolyline,\n\tintersectLineSegmentPolygon,\n\tintersectLineSegmentPolyline,\n\tintersectPolys,\n} from '../intersect'\nimport { approximately, pointInPolygon } from '../utils'\n\n/**\n * Filter geometry within a group.\n *\n * Filters are ignored when called directly on primitive geometries, but can be used to narrow down\n * the results of an operation on `Group2d` geometries.\n *\n * @public\n */\nexport interface Geometry2dFilters {\n\treadonly includeLabels?: boolean\n\treadonly includeInternal?: boolean\n}\n\n/** @public */\nexport const Geometry2dFilters: {\n\tEXCLUDE_NON_STANDARD: Geometry2dFilters\n\tINCLUDE_ALL: Geometry2dFilters\n\tEXCLUDE_LABELS: Geometry2dFilters\n\tEXCLUDE_INTERNAL: Geometry2dFilters\n} = {\n\tEXCLUDE_NON_STANDARD: {\n\t\tincludeLabels: false,\n\t\tincludeInternal: false,\n\t},\n\tINCLUDE_ALL: { includeLabels: true, includeInternal: true },\n\tEXCLUDE_LABELS: { includeLabels: false, includeInternal: true },\n\tEXCLUDE_INTERNAL: { includeLabels: true, includeInternal: false },\n}\n\n/** @public */\nexport interface TransformedGeometry2dOptions {\n\tisLabel?: boolean\n\tisInternal?: boolean\n\tdebugColor?: string\n\tignore?: boolean\n}\n\n/** @public */\nexport interface Geometry2dOptions extends TransformedGeometry2dOptions {\n\tisFilled: boolean\n\tisClosed: boolean\n}\n\n/** @public */\nexport abstract class Geometry2d {\n\tisFilled = false\n\tisClosed = true\n\tisLabel = false\n\tisInternal = false\n\tdebugColor?: string\n\tignore?: boolean\n\n\tconstructor(opts: Geometry2dOptions) {\n\t\tthis.isFilled = opts.isFilled\n\t\tthis.isClosed = opts.isClosed\n\t\tthis.isLabel = opts.isLabel ?? false\n\t\tthis.isInternal = opts.isInternal ?? false\n\t\tthis.debugColor = opts.debugColor\n\t\tthis.ignore = opts.ignore\n\t}\n\n\tisExcludedByFilter(filters?: Geometry2dFilters) {\n\t\tif (!filters) return false\n\t\tif (this.isLabel && !filters.includeLabels) return true\n\t\tif (this.isInternal && !filters.includeInternal) return true\n\t\treturn false\n\t}\n\n\tabstract getVertices(filters: Geometry2dFilters): Vec[]\n\n\tabstract nearestPoint(point: VecLike, _filters?: Geometry2dFilters): Vec\n\n\thitTestPoint(point: VecLike, margin = 0, hitInside = false, _filters?: Geometry2dFilters) {\n\t\t// First check whether the point is inside\n\t\tif (this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices)) {\n\t\t\treturn true\n\t\t}\n\t\t// Then check whether the distance is within the margin\n\t\treturn Vec.Dist2(point, this.nearestPoint(point)) <= margin * margin\n\t}\n\n\tdistanceToPoint(point: VecLike, hitInside = false, filters?: Geometry2dFilters) {\n\t\treturn (\n\t\t\tVec.Dist(point, this.nearestPoint(point, filters)) *\n\t\t\t(this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices)\n\t\t\t\t? -1\n\t\t\t\t: 1)\n\t\t)\n\t}\n\n\tdistanceToLineSegment(A: VecLike, B: VecLike, filters?: Geometry2dFilters) {\n\t\tif (Vec.Equals(A, B)) return this.distanceToPoint(A, false, filters)\n\t\tconst { vertices } = this\n\t\tlet nearest: Vec | undefined\n\t\tlet dist = Infinity\n\t\tlet d: number, p: Vec, q: Vec\n\t\tfor (let i = 0; i < vertices.length; i++) {\n\t\t\tp = vertices[i]\n\t\t\tq = Vec.NearestPointOnLineSegment(A, B, p, true)\n\t\t\td = Vec.Dist2(p, q)\n\t\t\tif (d < dist) {\n\t\t\t\tdist = d\n\t\t\t\tnearest = q\n\t\t\t}\n\t\t}\n\t\tif (!nearest) throw Error('nearest point not found')\n\t\treturn this.isClosed && this.isFilled && pointInPolygon(nearest, this.vertices) ? -dist : dist\n\t}\n\n\thitTestLineSegment(A: VecLike, B: VecLike, distance = 0, filters?: Geometry2dFilters): boolean {\n\t\treturn this.distanceToLineSegment(A, B, filters) <= distance\n\t}\n\n\tintersectLineSegment(A: VecLike, B: VecLike, _filters?: Geometry2dFilters): VecLike[] {\n\t\tconst intersections = this.isClosed\n\t\t\t? intersectLineSegmentPolygon(A, B, this.vertices)\n\t\t\t: intersectLineSegmentPolyline(A, B, this.vertices)\n\n\t\treturn intersections ?? []\n\t}\n\n\tintersectCircle(center: VecLike, radius: number, _filters?: Geometry2dFilters): VecLike[] {\n\t\tconst intersections = this.isClosed\n\t\t\t? intersectCirclePolygon(center, radius, this.vertices)\n\t\t\t: intersectCirclePolyline(center, radius, this.vertices)\n\n\t\treturn intersections ?? []\n\t}\n\n\tintersectPolygon(polygon: VecLike[], _filters?: Geometry2dFilters): VecLike[] {\n\t\treturn intersectPolys(polygon, this.vertices, true, this.isClosed)\n\t}\n\n\tintersectPolyline(polyline: VecLike[], _filters?: Geometry2dFilters): VecLike[] {\n\t\treturn intersectPolys(polyline, this.vertices, false, this.isClosed)\n\t}\n\n\t/**\n\t * Find a point along the edge of the geometry that is a fraction `t` along the entire way round.\n\t */\n\tinterpolateAlongEdge(t: number, _filters?: Geometry2dFilters): Vec {\n\t\tconst { vertices } = this\n\n\t\tif (t <= 0) return vertices[0]\n\n\t\tconst distanceToTravel = t * this.length\n\t\tlet distanceTraveled = 0\n\n\t\tfor (let i = 0; i < (this.isClosed ? vertices.length : vertices.length - 1); i++) {\n\t\t\tconst curr = vertices[i]\n\t\t\tconst next = vertices[(i + 1) % vertices.length]\n\t\t\tconst dist = Vec.Dist(curr, next)\n\t\t\tconst newDistanceTraveled = distanceTraveled + dist\n\t\t\tif (newDistanceTraveled >= distanceToTravel) {\n\t\t\t\tconst p = Vec.Lrp(\n\t\t\t\t\tcurr,\n\t\t\t\t\tnext,\n\t\t\t\t\tinvLerp(distanceTraveled, newDistanceTraveled, distanceToTravel)\n\t\t\t\t)\n\t\t\t\treturn p\n\t\t\t}\n\t\t\tdistanceTraveled = newDistanceTraveled\n\t\t}\n\n\t\treturn this.isClosed ? vertices[0] : vertices[vertices.length - 1]\n\t}\n\n\t/**\n\t * Take `point`, find the closest point to it on the edge of the geometry, and return how far\n\t * along the edge it is as a fraction of the total length.\n\t */\n\tuninterpolateAlongEdge(point: VecLike, _filters?: Geometry2dFilters): number {\n\t\tconst { vertices, length } = this\n\t\tlet closestSegment = null\n\t\tlet closestDistance = Infinity\n\t\tlet distanceTraveled = 0\n\n\t\tfor (let i = 0; i < (this.isClosed ? vertices.length : vertices.length - 1); i++) {\n\t\t\tconst curr = vertices[i]\n\t\t\tconst next = vertices[(i + 1) % vertices.length]\n\n\t\t\tconst nearestPoint = Vec.NearestPointOnLineSegment(curr, next, point, true)\n\t\t\tconst distance = Vec.Dist(nearestPoint, point)\n\n\t\t\tif (distance < closestDistance) {\n\t\t\t\tclosestDistance = distance\n\t\t\t\tclosestSegment = {\n\t\t\t\t\tstart: curr,\n\t\t\t\t\tend: next,\n\t\t\t\t\tnearestPoint,\n\t\t\t\t\tdistanceToStart: distanceTraveled,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdistanceTraveled += Vec.Dist(curr, next)\n\t\t}\n\n\t\tassert(closestSegment)\n\n\t\tconst distanceAlongRoute =\n\t\t\tclosestSegment.distanceToStart + Vec.Dist(closestSegment.start, closestSegment.nearestPoint)\n\n\t\treturn distanceAlongRoute / length\n\t}\n\n\t/** @deprecated Iterate the vertices instead. */\n\tnearestPointOnLineSegment(A: VecLike, B: VecLike): Vec {\n\t\tconst { vertices } = this\n\t\tlet nearest: Vec | undefined\n\t\tlet dist = Infinity\n\t\tlet d: number, p: Vec, q: Vec\n\t\tfor (let i = 0; i < vertices.length; i++) {\n\t\t\tp = vertices[i]\n\t\t\tq = Vec.NearestPointOnLineSegment(A, B, p, true)\n\t\t\td = Vec.Dist2(p, q)\n\t\t\tif (d < dist) {\n\t\t\t\tdist = d\n\t\t\t\tnearest = q\n\t\t\t}\n\t\t}\n\t\tif (!nearest) throw Error('nearest point not found')\n\t\treturn nearest\n\t}\n\n\tisPointInBounds(point: VecLike, margin = 0) {\n\t\tconst { bounds } = this\n\t\treturn !(\n\t\t\tpoint.x < bounds.minX - margin ||\n\t\t\tpoint.y < bounds.minY - margin ||\n\t\t\tpoint.x > bounds.maxX + margin ||\n\t\t\tpoint.y > bounds.maxY + margin\n\t\t)\n\t}\n\n\ttransform(transform: MatModel, opts?: TransformedGeometry2dOptions): Geometry2d {\n\t\treturn new TransformedGeometry2d(this, transform, opts)\n\t}\n\n\tprivate _vertices: Vec[] | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget vertices(): Vec[] {\n\t\tif (!this._vertices) {\n\t\t\tthis._vertices = this.getVertices(Geometry2dFilters.EXCLUDE_LABELS)\n\t\t}\n\n\t\treturn this._vertices\n\t}\n\n\tgetBounds() {\n\t\treturn Box.FromPoints(this.vertices)\n\t}\n\n\tprivate _bounds: Box | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget bounds(): Box {\n\t\tif (!this._bounds) {\n\t\t\tthis._bounds = this.getBounds()\n\t\t}\n\t\treturn this._bounds\n\t}\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget center() {\n\t\treturn this.bounds.center\n\t}\n\n\tprivate _area: number | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget area() {\n\t\tif (!this._area) {\n\t\t\tthis._area = this.getArea()\n\t\t}\n\t\treturn this._area\n\t}\n\n\tgetArea() {\n\t\tif (!this.isClosed) {\n\t\t\treturn 0\n\t\t}\n\t\tconst { vertices } = this\n\t\tlet area = 0\n\t\tfor (let i = 0, n = vertices.length; i < n; i++) {\n\t\t\tconst curr = vertices[i]\n\t\t\tconst next = vertices[(i + 1) % n]\n\t\t\tarea += curr.x * next.y - next.x * curr.y\n\t\t}\n\t\treturn area / 2\n\t}\n\n\ttoSimpleSvgPath() {\n\t\tlet path = ''\n\n\t\tconst { vertices } = this\n\t\tconst n = vertices.length\n\n\t\tif (n === 0) return path\n\n\t\tpath += `M${vertices[0].x},${vertices[0].y}`\n\n\t\tfor (let i = 1; i < n; i++) {\n\t\t\tpath += `L${vertices[i].x},${vertices[i].y}`\n\t\t}\n\n\t\tif (this.isClosed) {\n\t\t\tpath += 'Z'\n\t\t}\n\n\t\treturn path\n\t}\n\n\tprivate _length?: number\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget length() {\n\t\tif (this._length) return this._length\n\t\tthis._length = this.getLength(Geometry2dFilters.EXCLUDE_LABELS)\n\t\treturn this._length\n\t}\n\n\tgetLength(_filters?: Geometry2dFilters) {\n\t\tconst vertices = this.getVertices(_filters ?? Geometry2dFilters.EXCLUDE_LABELS)\n\t\tif (vertices.length === 0) return 0\n\t\tlet prev = vertices[0]\n\t\tlet length = 0\n\t\tfor (let i = 1; i < vertices.length; i++) {\n\t\t\tconst next = vertices[i]\n\t\t\tlength += Vec.Dist(prev, next)\n\t\t\tprev = next\n\t\t}\n\t\tif (this.isClosed) {\n\t\t\tlength += Vec.Dist(vertices[vertices.length - 1], vertices[0])\n\t\t}\n\t\treturn length\n\t}\n\n\tabstract getSvgPathData(first: boolean): string\n}\n\n// =================================================================================================\n// Because Geometry2d.transform depends on TransformedGeometry2d, we need to define it here instead\n// of in its own files. This prevents a circular import error.\n// =================================================================================================\n\n/** @public */\nexport class TransformedGeometry2d extends Geometry2d {\n\tprivate readonly inverse: MatModel\n\tprivate readonly decomposed\n\n\tconstructor(\n\t\tprivate readonly geometry: Geometry2d,\n\t\tprivate readonly matrix: MatModel,\n\t\topts?: TransformedGeometry2dOptions\n\t) {\n\t\tsuper(geometry)\n\t\tthis.inverse = Mat.Inverse(matrix)\n\t\tthis.decomposed = Mat.Decompose(matrix)\n\n\t\tif (opts) {\n\t\t\tif (opts.isLabel != null) this.isLabel = opts.isLabel\n\t\t\tif (opts.isInternal != null) this.isInternal = opts.isInternal\n\t\t\tif (opts.debugColor != null) this.debugColor = opts.debugColor\n\t\t\tif (opts.ignore != null) this.ignore = opts.ignore\n\t\t}\n\n\t\tassert(\n\t\t\tapproximately(this.decomposed.scaleX, this.decomposed.scaleY),\n\t\t\t'non-uniform scaling is not yet supported'\n\t\t)\n\t}\n\n\tgetVertices(filters: Geometry2dFilters): Vec[] {\n\t\treturn this.geometry.getVertices(filters).map((v) => Mat.applyToPoint(this.matrix, v))\n\t}\n\n\tnearestPoint(point: VecLike, filters?: Geometry2dFilters): Vec {\n\t\treturn Mat.applyToPoint(\n\t\t\tthis.matrix,\n\t\t\tthis.geometry.nearestPoint(Mat.applyToPoint(this.inverse, point), filters)\n\t\t)\n\t}\n\n\toverride hitTestPoint(\n\t\tpoint: VecLike,\n\t\tmargin = 0,\n\t\thitInside?: boolean,\n\t\tfilters?: Geometry2dFilters\n\t): boolean {\n\t\treturn this.geometry.hitTestPoint(\n\t\t\tMat.applyToPoint(this.inverse, point),\n\t\t\tmargin / this.decomposed.scaleX,\n\t\t\thitInside,\n\t\t\tfilters\n\t\t)\n\t}\n\n\toverride distanceToPoint(point: VecLike, hitInside = false, filters?: Geometry2dFilters) {\n\t\treturn (\n\t\t\tthis.geometry.distanceToPoint(Mat.applyToPoint(this.inverse, point), hitInside, filters) *\n\t\t\tthis.decomposed.scaleX\n\t\t)\n\t}\n\n\toverride distanceToLineSegment(A: VecLike, B: VecLike, filters?: Geometry2dFilters) {\n\t\treturn (\n\t\t\tthis.geometry.distanceToLineSegment(\n\t\t\t\tMat.applyToPoint(this.inverse, A),\n\t\t\t\tMat.applyToPoint(this.inverse, B),\n\t\t\t\tfilters\n\t\t\t) * this.decomposed.scaleX\n\t\t)\n\t}\n\n\toverride hitTestLineSegment(\n\t\tA: VecLike,\n\t\tB: VecLike,\n\t\tdistance = 0,\n\t\tfilters?: Geometry2dFilters\n\t): boolean {\n\t\treturn this.geometry.hitTestLineSegment(\n\t\t\tMat.applyToPoint(this.inverse, A),\n\t\t\tMat.applyToPoint(this.inverse, B),\n\t\t\tdistance / this.decomposed.scaleX,\n\t\t\tfilters\n\t\t)\n\t}\n\n\toverride intersectLineSegment(A: VecLike, B: VecLike, filters?: Geometry2dFilters) {\n\t\treturn Mat.applyToPoints(\n\t\t\tthis.matrix,\n\t\t\tthis.geometry.intersectLineSegment(\n\t\t\t\tMat.applyToPoint(this.inverse, A),\n\t\t\t\tMat.applyToPoint(this.inverse, B),\n\t\t\t\tfilters\n\t\t\t)\n\t\t)\n\t}\n\n\toverride intersectCircle(center: VecLike, radius: number, filters?: Geometry2dFilters) {\n\t\treturn Mat.applyToPoints(\n\t\t\tthis.matrix,\n\t\t\tthis.geometry.intersectCircle(\n\t\t\t\tMat.applyToPoint(this.inverse, center),\n\t\t\t\tradius / this.decomposed.scaleX,\n\t\t\t\tfilters\n\t\t\t)\n\t\t)\n\t}\n\n\toverride intersectPolygon(polygon: VecLike[], filters?: Geometry2dFilters): VecLike[] {\n\t\treturn Mat.applyToPoints(\n\t\t\tthis.matrix,\n\t\t\tthis.geometry.intersectPolygon(Mat.applyToPoints(this.inverse, polygon), filters)\n\t\t)\n\t}\n\n\toverride intersectPolyline(polyline: VecLike[], filters?: Geometry2dFilters): VecLike[] {\n\t\treturn Mat.applyToPoints(\n\t\t\tthis.matrix,\n\t\t\tthis.geometry.intersectPolyline(Mat.applyToPoints(this.inverse, polyline), filters)\n\t\t)\n\t}\n\n\toverride transform(transform: MatModel, opts?: TransformedGeometry2dOptions): Geometry2d {\n\t\treturn new TransformedGeometry2d(this.geometry, Mat.Multiply(transform, this.matrix), {\n\t\t\tisLabel: opts?.isLabel ?? this.isLabel,\n\t\t\tisInternal: opts?.isInternal ?? this.isInternal,\n\t\t\tdebugColor: opts?.debugColor ?? this.debugColor,\n\t\t\tignore: opts?.ignore ?? this.ignore,\n\t\t})\n\t}\n\n\tgetSvgPathData(): string {\n\t\tthrow new Error('Cannot get SVG path data for transformed geometry.')\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { EMPTY_ARRAY } from "@tldraw/state";
|
|
2
|
+
import { assert, invLerp, lerp } from "@tldraw/utils";
|
|
2
3
|
import { Box } from "../Box.mjs";
|
|
3
4
|
import { Vec } from "../Vec.mjs";
|
|
4
5
|
import { Geometry2d, Geometry2dFilters } from "./Geometry2d.mjs";
|
|
@@ -82,6 +83,53 @@ class Group2d extends Geometry2d {
|
|
|
82
83
|
return child.intersectPolyline(polyline, filters);
|
|
83
84
|
});
|
|
84
85
|
}
|
|
86
|
+
interpolateAlongEdge(t, filters) {
|
|
87
|
+
const totalLength = this.getLength(filters);
|
|
88
|
+
const distanceToTravel = t * totalLength;
|
|
89
|
+
let distanceTraveled = 0;
|
|
90
|
+
for (const child of this.children) {
|
|
91
|
+
if (child.isExcludedByFilter(filters)) continue;
|
|
92
|
+
const childLength = child.length;
|
|
93
|
+
const newDistanceTraveled = distanceTraveled + childLength;
|
|
94
|
+
if (newDistanceTraveled >= distanceToTravel) {
|
|
95
|
+
return child.interpolateAlongEdge(
|
|
96
|
+
invLerp(distanceTraveled, newDistanceTraveled, distanceToTravel),
|
|
97
|
+
filters
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
distanceTraveled = newDistanceTraveled;
|
|
101
|
+
}
|
|
102
|
+
return this.children[this.children.length - 1].interpolateAlongEdge(1, filters);
|
|
103
|
+
}
|
|
104
|
+
uninterpolateAlongEdge(point, filters) {
|
|
105
|
+
const totalLength = this.getLength(filters);
|
|
106
|
+
let closestChild = null;
|
|
107
|
+
let closestDistance = Infinity;
|
|
108
|
+
let distanceTraveled = 0;
|
|
109
|
+
for (const child of this.children) {
|
|
110
|
+
if (child.isExcludedByFilter(filters)) continue;
|
|
111
|
+
const childLength = child.getLength(filters);
|
|
112
|
+
const newDistanceTraveled = distanceTraveled + childLength;
|
|
113
|
+
const distance = child.distanceToPoint(point, false, filters);
|
|
114
|
+
if (distance < closestDistance) {
|
|
115
|
+
closestDistance = distance;
|
|
116
|
+
closestChild = {
|
|
117
|
+
startLength: distanceTraveled,
|
|
118
|
+
endLength: newDistanceTraveled,
|
|
119
|
+
child
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
distanceTraveled = newDistanceTraveled;
|
|
123
|
+
}
|
|
124
|
+
assert(closestChild);
|
|
125
|
+
const normalizedDistanceInChild = closestChild.child.uninterpolateAlongEdge(point, filters);
|
|
126
|
+
const childTLength = lerp(
|
|
127
|
+
closestChild.startLength,
|
|
128
|
+
closestChild.endLength,
|
|
129
|
+
normalizedDistanceInChild
|
|
130
|
+
);
|
|
131
|
+
return childTLength / totalLength;
|
|
132
|
+
}
|
|
85
133
|
transform(transform) {
|
|
86
134
|
return new Group2d({
|
|
87
135
|
children: this.children.map((c) => c.transform(transform)),
|
|
@@ -112,8 +160,13 @@ class Group2d extends Geometry2d {
|
|
|
112
160
|
}
|
|
113
161
|
return path;
|
|
114
162
|
}
|
|
115
|
-
getLength() {
|
|
116
|
-
|
|
163
|
+
getLength(filters) {
|
|
164
|
+
let length = 0;
|
|
165
|
+
for (const child of this.children) {
|
|
166
|
+
if (child.isExcludedByFilter(filters)) continue;
|
|
167
|
+
length += child.length;
|
|
168
|
+
}
|
|
169
|
+
return length;
|
|
117
170
|
}
|
|
118
171
|
getSvgPathData() {
|
|
119
172
|
return this.children.map((c, i) => c.isLabel ? "" : c.getSvgPathData(i === 0)).join(" ");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/primitives/geometry/Group2d.ts"],
|
|
4
|
-
"sourcesContent": ["import { EMPTY_ARRAY } from '@tldraw/state'\nimport { Box } from '../Box'\nimport { Mat } from '../Mat'\nimport { Vec, VecLike } from '../Vec'\nimport { Geometry2d, Geometry2dFilters, Geometry2dOptions } from './Geometry2d'\n\n/** @public */\nexport class Group2d extends Geometry2d {\n\tchildren: Geometry2d[] = []\n\tignoredChildren: Geometry2d[] = []\n\n\tconstructor(\n\t\tconfig: Omit<Geometry2dOptions, 'isClosed' | 'isFilled'> & {\n\t\t\tchildren: Geometry2d[]\n\t\t}\n\t) {\n\t\tsuper({ ...config, isClosed: true, isFilled: false })\n\n\t\tfor (const child of config.children) {\n\t\t\tif (child.ignore) {\n\t\t\t\tthis.ignoredChildren.push(child)\n\t\t\t} else {\n\t\t\t\tthis.children.push(child)\n\t\t\t}\n\t\t}\n\n\t\tif (this.children.length === 0) throw Error('Group2d must have at least one child')\n\t}\n\n\toverride getVertices(filters: Geometry2dFilters): Vec[] {\n\t\tif (this.isExcludedByFilter(filters)) return []\n\t\treturn this.children\n\t\t\t.filter((c) => !c.isExcludedByFilter(filters))\n\t\t\t.flatMap((c) => c.getVertices(filters))\n\t}\n\n\toverride nearestPoint(point:
|
|
5
|
-
"mappings": "AAAA,SAAS,mBAAmB;AAC5B,SAAS,WAAW;AAEpB,SAAS,WAAoB;AAC7B,SAAS,YAAY,yBAA4C;AAG1D,MAAM,gBAAgB,WAAW;AAAA,EACvC,WAAyB,CAAC;AAAA,EAC1B,kBAAgC,CAAC;AAAA,EAEjC,YACC,QAGC;AACD,UAAM,EAAE,GAAG,QAAQ,UAAU,MAAM,UAAU,MAAM,CAAC;AAEpD,eAAW,SAAS,OAAO,UAAU;AACpC,UAAI,MAAM,QAAQ;AACjB,aAAK,gBAAgB,KAAK,KAAK;AAAA,MAChC,OAAO;AACN,aAAK,SAAS,KAAK,KAAK;AAAA,MACzB;AAAA,IACD;AAEA,QAAI,KAAK,SAAS,WAAW,EAAG,OAAM,MAAM,sCAAsC;AAAA,EACnF;AAAA,EAES,YAAY,SAAmC;AACvD,QAAI,KAAK,mBAAmB,OAAO,EAAG,QAAO,CAAC;AAC9C,WAAO,KAAK,SACV,OAAO,CAAC,MAAM,CAAC,EAAE,mBAAmB,OAAO,CAAC,EAC5C,QAAQ,CAAC,MAAM,EAAE,YAAY,OAAO,CAAC;AAAA,EACxC;AAAA,EAES,aAAa,
|
|
4
|
+
"sourcesContent": ["import { EMPTY_ARRAY } from '@tldraw/state'\nimport { assert, invLerp, lerp } from '@tldraw/utils'\nimport { Box } from '../Box'\nimport { Mat } from '../Mat'\nimport { Vec, VecLike } from '../Vec'\nimport { Geometry2d, Geometry2dFilters, Geometry2dOptions } from './Geometry2d'\n\n/** @public */\nexport class Group2d extends Geometry2d {\n\tchildren: Geometry2d[] = []\n\tignoredChildren: Geometry2d[] = []\n\n\tconstructor(\n\t\tconfig: Omit<Geometry2dOptions, 'isClosed' | 'isFilled'> & {\n\t\t\tchildren: Geometry2d[]\n\t\t}\n\t) {\n\t\tsuper({ ...config, isClosed: true, isFilled: false })\n\n\t\tfor (const child of config.children) {\n\t\t\tif (child.ignore) {\n\t\t\t\tthis.ignoredChildren.push(child)\n\t\t\t} else {\n\t\t\t\tthis.children.push(child)\n\t\t\t}\n\t\t}\n\n\t\tif (this.children.length === 0) throw Error('Group2d must have at least one child')\n\t}\n\n\toverride getVertices(filters: Geometry2dFilters): Vec[] {\n\t\tif (this.isExcludedByFilter(filters)) return []\n\t\treturn this.children\n\t\t\t.filter((c) => !c.isExcludedByFilter(filters))\n\t\t\t.flatMap((c) => c.getVertices(filters))\n\t}\n\n\toverride nearestPoint(point: VecLike, filters?: Geometry2dFilters): Vec {\n\t\tlet dist = Infinity\n\t\tlet nearest: Vec | undefined\n\n\t\tconst { children } = this\n\n\t\tif (children.length === 0) {\n\t\t\tthrow Error('no children')\n\t\t}\n\n\t\tlet p: Vec\n\t\tlet d: number\n\t\tfor (const child of children) {\n\t\t\tif (child.isExcludedByFilter(filters)) continue\n\t\t\tp = child.nearestPoint(point, filters)\n\t\t\td = Vec.Dist2(p, point)\n\t\t\tif (d < dist) {\n\t\t\t\tdist = d\n\t\t\t\tnearest = p\n\t\t\t}\n\t\t}\n\t\tif (!nearest) throw Error('nearest point not found')\n\t\treturn nearest\n\t}\n\n\toverride distanceToPoint(point: VecLike, hitInside = false, filters?: Geometry2dFilters) {\n\t\tlet smallestDistance = Infinity\n\t\tfor (const child of this.children) {\n\t\t\tif (child.isExcludedByFilter(filters)) continue\n\t\t\tconst distance = child.distanceToPoint(point, hitInside, filters)\n\t\t\tif (distance < smallestDistance) {\n\t\t\t\tsmallestDistance = distance\n\t\t\t}\n\t\t}\n\t\treturn smallestDistance\n\t}\n\n\toverride hitTestPoint(\n\t\tpoint: VecLike,\n\t\tmargin: number,\n\t\thitInside: boolean,\n\t\tfilters = Geometry2dFilters.EXCLUDE_LABELS\n\t): boolean {\n\t\treturn !!this.children\n\t\t\t.filter((c) => !c.isExcludedByFilter(filters))\n\t\t\t.find((c) => c.hitTestPoint(point, margin, hitInside))\n\t}\n\n\toverride hitTestLineSegment(\n\t\tA: VecLike,\n\t\tB: VecLike,\n\t\tzoom: number,\n\t\tfilters = Geometry2dFilters.EXCLUDE_LABELS\n\t): boolean {\n\t\treturn !!this.children\n\t\t\t.filter((c) => !c.isExcludedByFilter(filters))\n\t\t\t.find((c) => c.hitTestLineSegment(A, B, zoom))\n\t}\n\n\toverride intersectLineSegment(A: VecLike, B: VecLike, filters?: Geometry2dFilters) {\n\t\treturn this.children.flatMap((child) => {\n\t\t\tif (child.isExcludedByFilter(filters)) return EMPTY_ARRAY\n\t\t\treturn child.intersectLineSegment(A, B, filters)\n\t\t})\n\t}\n\n\toverride intersectCircle(center: VecLike, radius: number, filters?: Geometry2dFilters) {\n\t\treturn this.children.flatMap((child) => {\n\t\t\tif (child.isExcludedByFilter(filters)) return EMPTY_ARRAY\n\t\t\treturn child.intersectCircle(center, radius, filters)\n\t\t})\n\t}\n\n\toverride intersectPolygon(polygon: VecLike[], filters?: Geometry2dFilters) {\n\t\treturn this.children.flatMap((child) => {\n\t\t\tif (child.isExcludedByFilter(filters)) return EMPTY_ARRAY\n\t\t\treturn child.intersectPolygon(polygon, filters)\n\t\t})\n\t}\n\n\toverride intersectPolyline(polyline: VecLike[], filters?: Geometry2dFilters) {\n\t\treturn this.children.flatMap((child) => {\n\t\t\tif (child.isExcludedByFilter(filters)) return EMPTY_ARRAY\n\t\t\treturn child.intersectPolyline(polyline, filters)\n\t\t})\n\t}\n\n\toverride interpolateAlongEdge(t: number, filters?: Geometry2dFilters): Vec {\n\t\tconst totalLength = this.getLength(filters)\n\n\t\tconst distanceToTravel = t * totalLength\n\t\tlet distanceTraveled = 0\n\t\tfor (const child of this.children) {\n\t\t\tif (child.isExcludedByFilter(filters)) continue\n\t\t\tconst childLength = child.length\n\t\t\tconst newDistanceTraveled = distanceTraveled + childLength\n\t\t\tif (newDistanceTraveled >= distanceToTravel) {\n\t\t\t\treturn child.interpolateAlongEdge(\n\t\t\t\t\tinvLerp(distanceTraveled, newDistanceTraveled, distanceToTravel),\n\t\t\t\t\tfilters\n\t\t\t\t)\n\t\t\t}\n\t\t\tdistanceTraveled = newDistanceTraveled\n\t\t}\n\n\t\treturn this.children[this.children.length - 1].interpolateAlongEdge(1, filters)\n\t}\n\n\toverride uninterpolateAlongEdge(point: VecLike, filters?: Geometry2dFilters): number {\n\t\tconst totalLength = this.getLength(filters)\n\n\t\tlet closestChild = null\n\t\tlet closestDistance = Infinity\n\t\tlet distanceTraveled = 0\n\n\t\tfor (const child of this.children) {\n\t\t\tif (child.isExcludedByFilter(filters)) continue\n\t\t\tconst childLength = child.getLength(filters)\n\t\t\tconst newDistanceTraveled = distanceTraveled + childLength\n\n\t\t\tconst distance = child.distanceToPoint(point, false, filters)\n\t\t\tif (distance < closestDistance) {\n\t\t\t\tclosestDistance = distance\n\t\t\t\tclosestChild = {\n\t\t\t\t\tstartLength: distanceTraveled,\n\t\t\t\t\tendLength: newDistanceTraveled,\n\t\t\t\t\tchild,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdistanceTraveled = newDistanceTraveled\n\t\t}\n\n\t\tassert(closestChild)\n\n\t\tconst normalizedDistanceInChild = closestChild.child.uninterpolateAlongEdge(point, filters)\n\t\tconst childTLength = lerp(\n\t\t\tclosestChild.startLength,\n\t\t\tclosestChild.endLength,\n\t\t\tnormalizedDistanceInChild\n\t\t)\n\t\treturn childTLength / totalLength\n\t}\n\n\toverride transform(transform: Mat): Geometry2d {\n\t\treturn new Group2d({\n\t\t\tchildren: this.children.map((c) => c.transform(transform)),\n\t\t\tisLabel: this.isLabel,\n\t\t\tdebugColor: this.debugColor,\n\t\t\tignore: this.ignore,\n\t\t})\n\t}\n\n\tgetArea() {\n\t\t// todo: this is a temporary solution, assuming that the first child defines the group size; we would want to flatten the group and then find the area of the hull polygon\n\t\treturn this.children[0].area\n\t}\n\n\ttoSimpleSvgPath() {\n\t\tlet path = ''\n\t\tfor (const child of this.children) {\n\t\t\tpath += child.toSimpleSvgPath()\n\t\t}\n\n\t\tconst corners = Box.FromPoints(this.vertices).corners\n\t\t// draw just a few pixels around each corner, e.g. an L shape for the bottom left\n\n\t\tfor (let i = 0, n = corners.length; i < n; i++) {\n\t\t\tconst corner = corners[i]\n\t\t\tconst prevCorner = corners[(i - 1 + n) % n]\n\t\t\tconst prevDist = corner.dist(prevCorner)\n\t\t\tconst nextCorner = corners[(i + 1) % n]\n\t\t\tconst nextDist = corner.dist(nextCorner)\n\n\t\t\tconst A = corner.clone().lrp(prevCorner, 4 / prevDist)\n\t\t\tconst B = corner\n\t\t\tconst C = corner.clone().lrp(nextCorner, 4 / nextDist)\n\n\t\t\tpath += `M${A.x},${A.y} L${B.x},${B.y} L${C.x},${C.y} `\n\t\t}\n\t\treturn path\n\t}\n\n\tgetLength(filters?: Geometry2dFilters): number {\n\t\tlet length = 0\n\t\tfor (const child of this.children) {\n\t\t\tif (child.isExcludedByFilter(filters)) continue\n\t\t\tlength += child.length\n\t\t}\n\t\treturn length\n\t}\n\n\tgetSvgPathData(): string {\n\t\treturn this.children.map((c, i) => (c.isLabel ? '' : c.getSvgPathData(i === 0))).join(' ')\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/primitives/geometry/Point2d.ts"],
|
|
4
|
-
"sourcesContent": ["import { Vec } from '../Vec'\nimport { Geometry2d, Geometry2dOptions } from './Geometry2d'\n\n/** @public */\nexport class Point2d extends Geometry2d {\n\tpoint: Vec\n\n\tconstructor(\n\t\tconfig: Omit<Geometry2dOptions, 'isClosed' | 'isFilled'> & { margin: number; point: Vec }\n\t) {\n\t\tsuper({ ...config, isClosed: true, isFilled: true })\n\t\tconst { point } = config\n\n\t\tthis.point = point\n\t}\n\n\tgetVertices() {\n\t\treturn [this.point]\n\t}\n\n\tnearestPoint(): Vec {\n\t\treturn this.point\n\t}\n\n\thitTestLineSegment(A:
|
|
5
|
-
"mappings": "AAAA,SAAS,
|
|
4
|
+
"sourcesContent": ["import { Vec, VecLike } from '../Vec'\nimport { Geometry2d, Geometry2dOptions } from './Geometry2d'\n\n/** @public */\nexport class Point2d extends Geometry2d {\n\tpoint: Vec\n\n\tconstructor(\n\t\tconfig: Omit<Geometry2dOptions, 'isClosed' | 'isFilled'> & { margin: number; point: Vec }\n\t) {\n\t\tsuper({ ...config, isClosed: true, isFilled: true })\n\t\tconst { point } = config\n\n\t\tthis.point = point\n\t}\n\n\tgetVertices() {\n\t\treturn [this.point]\n\t}\n\n\tnearestPoint(): Vec {\n\t\treturn this.point\n\t}\n\n\thitTestLineSegment(A: VecLike, B: VecLike, margin: number): boolean {\n\t\treturn Vec.DistanceToLineSegment(A, B, this.point) < margin\n\t}\n\n\tgetSvgPathData() {\n\t\tconst { point } = this\n\t\treturn `M${point.toFixed()}`\n\t}\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,WAAoB;AAC7B,SAAS,kBAAqC;AAGvC,MAAM,gBAAgB,WAAW;AAAA,EACvC;AAAA,EAEA,YACC,QACC;AACD,UAAM,EAAE,GAAG,QAAQ,UAAU,MAAM,UAAU,KAAK,CAAC;AACnD,UAAM,EAAE,MAAM,IAAI;AAElB,SAAK,QAAQ;AAAA,EACd;AAAA,EAEA,cAAc;AACb,WAAO,CAAC,KAAK,KAAK;AAAA,EACnB;AAAA,EAEA,eAAoB;AACnB,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,mBAAmB,GAAY,GAAY,QAAyB;AACnE,WAAO,IAAI,sBAAsB,GAAG,GAAG,KAAK,KAAK,IAAI;AAAA,EACtD;AAAA,EAEA,iBAAiB;AAChB,UAAM,EAAE,MAAM,IAAI;AAClB,WAAO,IAAI,MAAM,QAAQ,CAAC;AAAA,EAC3B;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/primitives/geometry/Polyline2d.ts"],
|
|
4
|
-
"sourcesContent": ["import { Vec } from '../Vec'\nimport { Edge2d } from './Edge2d'\nimport { Geometry2d, Geometry2dOptions } from './Geometry2d'\n\n/** @public */\nexport class Polyline2d extends Geometry2d {\n\tpoints: Vec[]\n\n\tconstructor(config: Omit<Geometry2dOptions, 'isFilled' | 'isClosed'> & { points: Vec[] }) {\n\t\tsuper({ isClosed: false, isFilled: false, ...config })\n\t\tconst { points } = config\n\t\tthis.points = points\n\t}\n\n\t_segments?: Edge2d[]\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget segments() {\n\t\tif (!this._segments) {\n\t\t\tthis._segments = []\n\t\t\tconst { vertices } = this\n\t\t\tfor (let i = 0, n = vertices.length - 1; i < n; i++) {\n\t\t\t\tconst start = vertices[i]\n\t\t\t\tconst end = vertices[i + 1]\n\t\t\t\tthis._segments.push(new Edge2d({ start, end }))\n\t\t\t}\n\n\t\t\tif (this.isClosed) {\n\t\t\t\tthis._segments.push(new Edge2d({ start: vertices[vertices.length - 1], end: vertices[0] }))\n\t\t\t}\n\t\t}\n\n\t\treturn this._segments\n\t}\n\n\toverride getLength() {\n\t\treturn this.segments.reduce((acc, segment) => acc + segment.length, 0)\n\t}\n\n\tgetVertices() {\n\t\treturn this.points\n\t}\n\n\tnearestPoint(A:
|
|
5
|
-
"mappings": "AAAA,SAAS,
|
|
4
|
+
"sourcesContent": ["import { Vec, VecLike } from '../Vec'\nimport { Edge2d } from './Edge2d'\nimport { Geometry2d, Geometry2dOptions } from './Geometry2d'\n\n/** @public */\nexport class Polyline2d extends Geometry2d {\n\tpoints: Vec[]\n\n\tconstructor(config: Omit<Geometry2dOptions, 'isFilled' | 'isClosed'> & { points: Vec[] }) {\n\t\tsuper({ isClosed: false, isFilled: false, ...config })\n\t\tconst { points } = config\n\t\tthis.points = points\n\t}\n\n\t_segments?: Edge2d[]\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget segments() {\n\t\tif (!this._segments) {\n\t\t\tthis._segments = []\n\t\t\tconst { vertices } = this\n\t\t\tfor (let i = 0, n = vertices.length - 1; i < n; i++) {\n\t\t\t\tconst start = vertices[i]\n\t\t\t\tconst end = vertices[i + 1]\n\t\t\t\tthis._segments.push(new Edge2d({ start, end }))\n\t\t\t}\n\n\t\t\tif (this.isClosed) {\n\t\t\t\tthis._segments.push(new Edge2d({ start: vertices[vertices.length - 1], end: vertices[0] }))\n\t\t\t}\n\t\t}\n\n\t\treturn this._segments\n\t}\n\n\toverride getLength() {\n\t\treturn this.segments.reduce((acc, segment) => acc + segment.length, 0)\n\t}\n\n\tgetVertices() {\n\t\treturn this.points\n\t}\n\n\tnearestPoint(A: VecLike): Vec {\n\t\tconst { segments } = this\n\t\tlet nearest = this.points[0]\n\t\tlet dist = Infinity\n\t\tlet p: Vec // current point on segment\n\t\tlet d: number // distance from A to p\n\t\tfor (let i = 0; i < segments.length; i++) {\n\t\t\tp = segments[i].nearestPoint(A)\n\t\t\td = Vec.Dist2(p, A)\n\t\t\tif (d < dist) {\n\t\t\t\tnearest = p\n\t\t\t\tdist = d\n\t\t\t}\n\t\t}\n\t\tif (!nearest) throw Error('nearest point not found')\n\t\treturn nearest\n\t}\n\n\thitTestLineSegment(A: VecLike, B: VecLike, distance = 0): boolean {\n\t\tconst { segments } = this\n\t\tfor (let i = 0, n = segments.length; i < n; i++) {\n\t\t\tif (segments[i].hitTestLineSegment(A, B, distance)) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\treturn false\n\t}\n\n\tgetSvgPathData(): string {\n\t\tconst { vertices } = this\n\t\tif (vertices.length < 2) return ''\n\t\treturn vertices.reduce((acc, vertex, i) => {\n\t\t\tif (i === 0) return `M ${vertex.x} ${vertex.y}`\n\t\t\treturn `${acc} L ${vertex.x} ${vertex.y}`\n\t\t}, '')\n\t}\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,WAAoB;AAC7B,SAAS,cAAc;AACvB,SAAS,kBAAqC;AAGvC,MAAM,mBAAmB,WAAW;AAAA,EAC1C;AAAA,EAEA,YAAY,QAA8E;AACzF,UAAM,EAAE,UAAU,OAAO,UAAU,OAAO,GAAG,OAAO,CAAC;AACrD,UAAM,EAAE,OAAO,IAAI;AACnB,SAAK,SAAS;AAAA,EACf;AAAA,EAEA;AAAA;AAAA,EAGA,IAAI,WAAW;AACd,QAAI,CAAC,KAAK,WAAW;AACpB,WAAK,YAAY,CAAC;AAClB,YAAM,EAAE,SAAS,IAAI;AACrB,eAAS,IAAI,GAAG,IAAI,SAAS,SAAS,GAAG,IAAI,GAAG,KAAK;AACpD,cAAM,QAAQ,SAAS,CAAC;AACxB,cAAM,MAAM,SAAS,IAAI,CAAC;AAC1B,aAAK,UAAU,KAAK,IAAI,OAAO,EAAE,OAAO,IAAI,CAAC,CAAC;AAAA,MAC/C;AAEA,UAAI,KAAK,UAAU;AAClB,aAAK,UAAU,KAAK,IAAI,OAAO,EAAE,OAAO,SAAS,SAAS,SAAS,CAAC,GAAG,KAAK,SAAS,CAAC,EAAE,CAAC,CAAC;AAAA,MAC3F;AAAA,IACD;AAEA,WAAO,KAAK;AAAA,EACb;AAAA,EAES,YAAY;AACpB,WAAO,KAAK,SAAS,OAAO,CAAC,KAAK,YAAY,MAAM,QAAQ,QAAQ,CAAC;AAAA,EACtE;AAAA,EAEA,cAAc;AACb,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,aAAa,GAAiB;AAC7B,UAAM,EAAE,SAAS,IAAI;AACrB,QAAI,UAAU,KAAK,OAAO,CAAC;AAC3B,QAAI,OAAO;AACX,QAAI;AACJ,QAAI;AACJ,aAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACzC,UAAI,SAAS,CAAC,EAAE,aAAa,CAAC;AAC9B,UAAI,IAAI,MAAM,GAAG,CAAC;AAClB,UAAI,IAAI,MAAM;AACb,kBAAU;AACV,eAAO;AAAA,MACR;AAAA,IACD;AACA,QAAI,CAAC,QAAS,OAAM,MAAM,yBAAyB;AACnD,WAAO;AAAA,EACR;AAAA,EAEA,mBAAmB,GAAY,GAAY,WAAW,GAAY;AACjE,UAAM,EAAE,SAAS,IAAI;AACrB,aAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,IAAI,GAAG,KAAK;AAChD,UAAI,SAAS,CAAC,EAAE,mBAAmB,GAAG,GAAG,QAAQ,GAAG;AACnD,eAAO;AAAA,MACR;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAAA,EAEA,iBAAyB;AACxB,UAAM,EAAE,SAAS,IAAI;AACrB,QAAI,SAAS,SAAS,EAAG,QAAO;AAChC,WAAO,SAAS,OAAO,CAAC,KAAK,QAAQ,MAAM;AAC1C,UAAI,MAAM,EAAG,QAAO,KAAK,OAAO,CAAC,IAAI,OAAO,CAAC;AAC7C,aAAO,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,OAAO,CAAC;AAAA,IACxC,GAAG,EAAE;AAAA,EACN;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/primitives/geometry/Stadium2d.ts"],
|
|
4
|
-
"sourcesContent": ["import { Box } from '../Box'\nimport { Vec } from '../Vec'\nimport { PI } from '../utils'\nimport { Arc2d } from './Arc2d'\nimport { Edge2d } from './Edge2d'\nimport { Geometry2d, Geometry2dOptions } from './Geometry2d'\n\n/** @public */\nexport class Stadium2d extends Geometry2d {\n\tw: number\n\th: number\n\n\ta: Arc2d\n\tb: Edge2d\n\tc: Arc2d\n\td: Edge2d\n\n\tconstructor(\n\t\tpublic config: Omit<Geometry2dOptions, 'isClosed'> & {\n\t\t\twidth: number\n\t\t\theight: number\n\t\t}\n\t) {\n\t\tsuper({ ...config, isClosed: true })\n\t\tconst { width: w, height: h } = config\n\t\tthis.w = w\n\t\tthis.h = h\n\n\t\tif (h > w) {\n\t\t\tconst r = w / 2\n\t\t\tthis.a = new Arc2d({\n\t\t\t\tstart: new Vec(0, r),\n\t\t\t\tend: new Vec(w, r),\n\t\t\t\tcenter: new Vec(w / 2, r),\n\t\t\t\tsweepFlag: 1,\n\t\t\t\tlargeArcFlag: 1,\n\t\t\t})\n\t\t\tthis.b = new Edge2d({ start: new Vec(w, r), end: new Vec(w, h - r) })\n\t\t\tthis.c = new Arc2d({\n\t\t\t\tstart: new Vec(w, h - r),\n\t\t\t\tend: new Vec(0, h - r),\n\t\t\t\tcenter: new Vec(w / 2, h - r),\n\t\t\t\tsweepFlag: 1,\n\t\t\t\tlargeArcFlag: 1,\n\t\t\t})\n\t\t\tthis.d = new Edge2d({ start: new Vec(0, h - r), end: new Vec(0, r) })\n\t\t} else {\n\t\t\tconst r = h / 2\n\t\t\tthis.a = new Arc2d({\n\t\t\t\tstart: new Vec(r, h),\n\t\t\t\tend: new Vec(r, 0),\n\t\t\t\tcenter: new Vec(r, r),\n\t\t\t\tsweepFlag: 1,\n\t\t\t\tlargeArcFlag: 1,\n\t\t\t})\n\t\t\tthis.b = new Edge2d({ start: new Vec(r, 0), end: new Vec(w - r, 0) })\n\t\t\tthis.c = new Arc2d({\n\t\t\t\tstart: new Vec(w - r, 0),\n\t\t\t\tend: new Vec(w - r, h),\n\t\t\t\tcenter: new Vec(w - r, r),\n\t\t\t\tsweepFlag: 1,\n\t\t\t\tlargeArcFlag: 1,\n\t\t\t})\n\t\t\tthis.d = new Edge2d({ start: new Vec(w - r, h), end: new Vec(r, h) })\n\t\t}\n\t}\n\n\tnearestPoint(A:
|
|
5
|
-
"mappings": "AAAA,SAAS,WAAW;AACpB,SAAS,
|
|
4
|
+
"sourcesContent": ["import { Box } from '../Box'\nimport { Vec, VecLike } from '../Vec'\nimport { PI } from '../utils'\nimport { Arc2d } from './Arc2d'\nimport { Edge2d } from './Edge2d'\nimport { Geometry2d, Geometry2dOptions } from './Geometry2d'\n\n/** @public */\nexport class Stadium2d extends Geometry2d {\n\tw: number\n\th: number\n\n\ta: Arc2d\n\tb: Edge2d\n\tc: Arc2d\n\td: Edge2d\n\n\tconstructor(\n\t\tpublic config: Omit<Geometry2dOptions, 'isClosed'> & {\n\t\t\twidth: number\n\t\t\theight: number\n\t\t}\n\t) {\n\t\tsuper({ ...config, isClosed: true })\n\t\tconst { width: w, height: h } = config\n\t\tthis.w = w\n\t\tthis.h = h\n\n\t\tif (h > w) {\n\t\t\tconst r = w / 2\n\t\t\tthis.a = new Arc2d({\n\t\t\t\tstart: new Vec(0, r),\n\t\t\t\tend: new Vec(w, r),\n\t\t\t\tcenter: new Vec(w / 2, r),\n\t\t\t\tsweepFlag: 1,\n\t\t\t\tlargeArcFlag: 1,\n\t\t\t})\n\t\t\tthis.b = new Edge2d({ start: new Vec(w, r), end: new Vec(w, h - r) })\n\t\t\tthis.c = new Arc2d({\n\t\t\t\tstart: new Vec(w, h - r),\n\t\t\t\tend: new Vec(0, h - r),\n\t\t\t\tcenter: new Vec(w / 2, h - r),\n\t\t\t\tsweepFlag: 1,\n\t\t\t\tlargeArcFlag: 1,\n\t\t\t})\n\t\t\tthis.d = new Edge2d({ start: new Vec(0, h - r), end: new Vec(0, r) })\n\t\t} else {\n\t\t\tconst r = h / 2\n\t\t\tthis.a = new Arc2d({\n\t\t\t\tstart: new Vec(r, h),\n\t\t\t\tend: new Vec(r, 0),\n\t\t\t\tcenter: new Vec(r, r),\n\t\t\t\tsweepFlag: 1,\n\t\t\t\tlargeArcFlag: 1,\n\t\t\t})\n\t\t\tthis.b = new Edge2d({ start: new Vec(r, 0), end: new Vec(w - r, 0) })\n\t\t\tthis.c = new Arc2d({\n\t\t\t\tstart: new Vec(w - r, 0),\n\t\t\t\tend: new Vec(w - r, h),\n\t\t\t\tcenter: new Vec(w - r, r),\n\t\t\t\tsweepFlag: 1,\n\t\t\t\tlargeArcFlag: 1,\n\t\t\t})\n\t\t\tthis.d = new Edge2d({ start: new Vec(w - r, h), end: new Vec(r, h) })\n\t\t}\n\t}\n\n\tnearestPoint(A: VecLike): Vec {\n\t\tlet nearest: Vec | undefined\n\t\tlet dist = Infinity\n\t\tlet _d: number\n\t\tlet p: Vec\n\n\t\tconst { a, b, c, d } = this\n\t\tfor (const part of [a, b, c, d]) {\n\t\t\tp = part.nearestPoint(A)\n\t\t\t_d = Vec.Dist2(p, A)\n\t\t\tif (_d < dist) {\n\t\t\t\tnearest = p\n\t\t\t\tdist = _d\n\t\t\t}\n\t\t}\n\t\tif (!nearest) throw Error('nearest point not found')\n\t\treturn nearest\n\t}\n\n\thitTestLineSegment(A: VecLike, B: VecLike): boolean {\n\t\tconst { a, b, c, d } = this\n\t\treturn [a, b, c, d].some((edge) => edge.hitTestLineSegment(A, B))\n\t}\n\n\tgetVertices() {\n\t\tconst { a, b, c, d } = this\n\t\treturn [a, b, c, d].reduce<Vec[]>((a, p) => {\n\t\t\ta.push(...p.vertices)\n\t\t\treturn a\n\t\t}, [])\n\t}\n\n\tgetBounds() {\n\t\treturn new Box(0, 0, this.w, this.h)\n\t}\n\n\tgetLength() {\n\t\tconst { h, w } = this\n\t\tif (h > w) return (PI * (w / 2) + (h - w)) * 2\n\t\telse return (PI * (h / 2) + (w - h)) * 2\n\t}\n\n\tgetSvgPathData() {\n\t\tconst { a, b, c, d } = this\n\t\treturn [a, b, c, d].map((p, i) => p.getSvgPathData(i === 0)).join(' ') + ' Z'\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["a"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/lib/utils/areShapesContentEqual.ts"],
|
|
4
|
+
"sourcesContent": ["import { TLShape } from '@tldraw/tlschema'\n\nexport const areShapesContentEqual = (a: TLShape, b: TLShape) =>\n\ta.props === b.props && a.meta === b.meta\n"],
|
|
5
|
+
"mappings": "AAEO,MAAM,wBAAwB,CAAC,GAAY,MACjD,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -41,7 +41,8 @@ const debugFlags = {
|
|
|
41
41
|
debugGeometry: createDebugValue("debugGeometry", { defaults: { all: false } }),
|
|
42
42
|
hideShapes: createDebugValue("hideShapes", { defaults: { all: false } }),
|
|
43
43
|
editOnType: createDebugValue("editOnType", { defaults: { all: false } }),
|
|
44
|
-
a11y: createDebugValue("a11y", { defaults: { all: false } })
|
|
44
|
+
a11y: createDebugValue("a11y", { defaults: { all: false } }),
|
|
45
|
+
debugElbowArrows: createDebugValue("debugElbowArrows", { defaults: { all: false } })
|
|
45
46
|
};
|
|
46
47
|
if (typeof Element !== "undefined") {
|
|
47
48
|
const nativeElementRemoveChild = Element.prototype.removeChild;
|
|
@@ -91,7 +92,9 @@ function createDebugValueBase(def) {
|
|
|
91
92
|
configurable: true
|
|
92
93
|
});
|
|
93
94
|
}
|
|
94
|
-
return Object.assign(valueAtom, def
|
|
95
|
+
return Object.assign(valueAtom, def, {
|
|
96
|
+
reset: () => valueAtom.set(defaultValue)
|
|
97
|
+
});
|
|
95
98
|
}
|
|
96
99
|
function getStoredInitialValue(name) {
|
|
97
100
|
try {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/utils/debug-flags.ts"],
|
|
4
|
-
"sourcesContent": ["import { Atom, atom, react } from '@tldraw/state'\nimport { deleteFromSessionStorage, getFromSessionStorage, setInSessionStorage } from '@tldraw/utils'\n\n// --- 1. DEFINE ---\n//\n// Define your debug values and feature flags here. Use `createDebugValue` to\n// create an arbitrary value with defaults for production, staging, and\n// development. Use `createFeatureFlag` to create a boolean flag which will be\n// `true` by default in development and staging, and `false` in production.\n/** @internal */\nexport const featureFlags: Record<string, DebugFlag<boolean>> = {}\n\n/** @internal */\nexport const pointerCaptureTrackingObject = createDebugValue(\n\t'pointerCaptureTrackingObject',\n\t// ideally we wouldn't store this mutable value in an atom but it's not\n\t// a big deal for debug values\n\t{\n\t\tdefaults: { all: new Map<Element, number>() },\n\t\tshouldStoreForSession: false,\n\t}\n)\n\n/** @internal */\nexport const debugFlags = {\n\t// --- DEBUG VALUES ---\n\tlogPreventDefaults: createDebugValue('logPreventDefaults', {\n\t\tdefaults: { all: false },\n\t}),\n\tlogPointerCaptures: createDebugValue('logPointerCaptures', {\n\t\tdefaults: { all: false },\n\t}),\n\tlogElementRemoves: createDebugValue('logElementRemoves', {\n\t\tdefaults: { all: false },\n\t}),\n\tdebugSvg: createDebugValue('debugSvg', {\n\t\tdefaults: { all: false },\n\t}),\n\tshowFps: createDebugValue('showFps', {\n\t\tdefaults: { all: false },\n\t}),\n\tmeasurePerformance: createDebugValue('measurePerformance', { defaults: { all: false } }),\n\tthrowToBlob: createDebugValue('throwToBlob', {\n\t\tdefaults: { all: false },\n\t}),\n\treconnectOnPing: createDebugValue('reconnectOnPing', {\n\t\tdefaults: { all: false },\n\t}),\n\tdebugCursors: createDebugValue('debugCursors', {\n\t\tdefaults: { all: false },\n\t}),\n\tforceSrgb: createDebugValue('forceSrgbColors', { defaults: { all: false } }),\n\tdebugGeometry: createDebugValue('debugGeometry', { defaults: { all: false } }),\n\thideShapes: createDebugValue('hideShapes', { defaults: { all: false } }),\n\teditOnType: createDebugValue('editOnType', { defaults: { all: false } }),\n\ta11y: createDebugValue('a11y', { defaults: { all: false } }),\n} as const\n\ndeclare global {\n\tinterface Window {\n\t\ttldrawLog(message: any): void\n\t}\n}\n\n// --- 2. USE ---\n// In normal code, read from debug flags directly by calling .value on them:\n// if (debugFlags.preventDefaultLogging.value) { ... }\n//\n// In react, wrap your reads in `useValue` (or your component in `track`)\n// so they react to changes:\n// const shouldLog = useValue(debugFlags.preventDefaultLogging)\n\n// --- 3. GET FUNKY ---\n// If you need to do fun stuff like monkey-patching in response to flag changes,\n// add that here. Make sure you wrap your code in `react` so it runs\n// automatically when values change!\n\nif (typeof Element !== 'undefined') {\n\tconst nativeElementRemoveChild = Element.prototype.removeChild\n\treact('element removal logging', () => {\n\t\tif (debugFlags.logElementRemoves.get()) {\n\t\t\tElement.prototype.removeChild = function <T extends Node>(this: any, child: Node): T {\n\t\t\t\tconsole.warn('[tldraw] removing child:', child)\n\t\t\t\treturn nativeElementRemoveChild.call(this, child) as T\n\t\t\t}\n\t\t} else {\n\t\t\tElement.prototype.removeChild = nativeElementRemoveChild\n\t\t}\n\t})\n}\n\n// --- IMPLEMENTATION ---\n// you probably don't need to read this if you're just using the debug values system\nfunction createDebugValue<T>(\n\tname: string,\n\t{\n\t\tdefaults,\n\t\tshouldStoreForSession = true,\n\t}: { defaults: DebugFlagDefaults<T>; shouldStoreForSession?: boolean }\n) {\n\treturn createDebugValueBase({\n\t\tname,\n\t\tdefaults,\n\t\tshouldStoreForSession,\n\t})\n}\n\n// function createFeatureFlag<T>(\n// \tname: string,\n// \t{\n// \t\tdefaults,\n// \t\tshouldStoreForSession = true,\n// \t}: { defaults: DebugFlagDefaults<T>; shouldStoreForSession?: boolean }\n// ) {\n// \treturn createDebugValueBase({\n// \t\tname,\n// \t\tdefaults,\n// \t\tshouldStoreForSession,\n// \t})\n// }\n\nfunction createDebugValueBase<T>(def: DebugFlagDef<T>): DebugFlag<T> {\n\tconst defaultValue = getDefaultValue(def)\n\tconst storedValue = def.shouldStoreForSession\n\t\t? (getStoredInitialValue(def.name) as T | null)\n\t\t: null\n\tconst valueAtom = atom(`debug:${def.name}`, storedValue ?? defaultValue)\n\n\tif (typeof window !== 'undefined') {\n\t\tif (def.shouldStoreForSession) {\n\t\t\treact(`debug:${def.name}`, () => {\n\t\t\t\tconst currentValue = valueAtom.get()\n\t\t\t\tif (currentValue === defaultValue) {\n\t\t\t\t\tdeleteFromSessionStorage(`tldraw_debug:${def.name}`)\n\t\t\t\t} else {\n\t\t\t\t\tsetInSessionStorage(`tldraw_debug:${def.name}`, JSON.stringify(currentValue))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\tObject.defineProperty(window, `tldraw${def.name.replace(/^[a-z]/, (l) => l.toUpperCase())}`, {\n\t\t\tget() {\n\t\t\t\treturn valueAtom.get()\n\t\t\t},\n\t\t\tset(newValue) {\n\t\t\t\tvalueAtom.set(newValue)\n\t\t\t},\n\t\t\tconfigurable: true,\n\t\t})\n\t}\n\n\treturn Object.assign(valueAtom, def)\n}\n\nfunction getStoredInitialValue(name: string) {\n\ttry {\n\t\treturn JSON.parse(getFromSessionStorage(`tldraw_debug:${name}`) ?? 'null')\n\t} catch {\n\t\treturn null\n\t}\n}\n\n// process.env might not be defined, but we can't access it using optional\n// chaining because some bundlers search for `process.env.SOMETHING` as a string\n// and replace it with its value.\nfunction readEnv(fn: () => string | undefined) {\n\ttry {\n\t\treturn fn()\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction getDefaultValue<T>(def: DebugFlagDef<T>): T {\n\tconst env =\n\t\treadEnv(() => process.env.TLDRAW_ENV) ??\n\t\treadEnv(() => process.env.VERCEL_PUBLIC_TLDRAW_ENV) ??\n\t\treadEnv(() => process.env.NEXT_PUBLIC_TLDRAW_ENV) ??\n\t\t// default to production because if we don't have one of these, this is probably a library use\n\t\t'production'\n\n\tswitch (env) {\n\t\tcase 'production':\n\t\t\treturn def.defaults.production ?? def.defaults.all\n\t\tcase 'preview':\n\t\tcase 'staging':\n\t\t\treturn def.defaults.staging ?? def.defaults.all\n\t\tdefault:\n\t\t\treturn def.defaults.development ?? def.defaults.all\n\t}\n}\n\n/** @internal */\nexport interface DebugFlagDefaults<T> {\n\tdevelopment?: T\n\tstaging?: T\n\tproduction?: T\n\tall: T\n}\n\n/** @internal */\nexport interface DebugFlagDef<T> {\n\tname: string\n\tdefaults: DebugFlagDefaults<T>\n\tshouldStoreForSession: boolean\n}\n\n/** @internal */\nexport
|
|
5
|
-
"mappings": "AAAA,SAAe,MAAM,aAAa;AAClC,SAAS,0BAA0B,uBAAuB,2BAA2B;AAS9E,MAAM,eAAmD,CAAC;AAG1D,MAAM,+BAA+B;AAAA,EAC3C;AAAA;AAAA;AAAA,EAGA;AAAA,IACC,UAAU,EAAE,KAAK,oBAAI,IAAqB,EAAE;AAAA,IAC5C,uBAAuB;AAAA,EACxB;AACD;AAGO,MAAM,aAAa;AAAA;AAAA,EAEzB,oBAAoB,iBAAiB,sBAAsB;AAAA,IAC1D,UAAU,EAAE,KAAK,MAAM;AAAA,EACxB,CAAC;AAAA,EACD,oBAAoB,iBAAiB,sBAAsB;AAAA,IAC1D,UAAU,EAAE,KAAK,MAAM;AAAA,EACxB,CAAC;AAAA,EACD,mBAAmB,iBAAiB,qBAAqB;AAAA,IACxD,UAAU,EAAE,KAAK,MAAM;AAAA,EACxB,CAAC;AAAA,EACD,UAAU,iBAAiB,YAAY;AAAA,IACtC,UAAU,EAAE,KAAK,MAAM;AAAA,EACxB,CAAC;AAAA,EACD,SAAS,iBAAiB,WAAW;AAAA,IACpC,UAAU,EAAE,KAAK,MAAM;AAAA,EACxB,CAAC;AAAA,EACD,oBAAoB,iBAAiB,sBAAsB,EAAE,UAAU,EAAE,KAAK,MAAM,EAAE,CAAC;AAAA,EACvF,aAAa,iBAAiB,eAAe;AAAA,IAC5C,UAAU,EAAE,KAAK,MAAM;AAAA,EACxB,CAAC;AAAA,EACD,iBAAiB,iBAAiB,mBAAmB;AAAA,IACpD,UAAU,EAAE,KAAK,MAAM;AAAA,EACxB,CAAC;AAAA,EACD,cAAc,iBAAiB,gBAAgB;AAAA,IAC9C,UAAU,EAAE,KAAK,MAAM;AAAA,EACxB,CAAC;AAAA,EACD,WAAW,iBAAiB,mBAAmB,EAAE,UAAU,EAAE,KAAK,MAAM,EAAE,CAAC;AAAA,EAC3E,eAAe,iBAAiB,iBAAiB,EAAE,UAAU,EAAE,KAAK,MAAM,EAAE,CAAC;AAAA,EAC7E,YAAY,iBAAiB,cAAc,EAAE,UAAU,EAAE,KAAK,MAAM,EAAE,CAAC;AAAA,EACvE,YAAY,iBAAiB,cAAc,EAAE,UAAU,EAAE,KAAK,MAAM,EAAE,CAAC;AAAA,EACvE,MAAM,iBAAiB,QAAQ,EAAE,UAAU,EAAE,KAAK,MAAM,EAAE,CAAC;
|
|
4
|
+
"sourcesContent": ["import { Atom, atom, react } from '@tldraw/state'\nimport { deleteFromSessionStorage, getFromSessionStorage, setInSessionStorage } from '@tldraw/utils'\n\n// --- 1. DEFINE ---\n//\n// Define your debug values and feature flags here. Use `createDebugValue` to\n// create an arbitrary value with defaults for production, staging, and\n// development. Use `createFeatureFlag` to create a boolean flag which will be\n// `true` by default in development and staging, and `false` in production.\n/** @internal */\nexport const featureFlags: Record<string, DebugFlag<boolean>> = {}\n\n/** @internal */\nexport const pointerCaptureTrackingObject = createDebugValue(\n\t'pointerCaptureTrackingObject',\n\t// ideally we wouldn't store this mutable value in an atom but it's not\n\t// a big deal for debug values\n\t{\n\t\tdefaults: { all: new Map<Element, number>() },\n\t\tshouldStoreForSession: false,\n\t}\n)\n\n/** @internal */\nexport const debugFlags = {\n\t// --- DEBUG VALUES ---\n\tlogPreventDefaults: createDebugValue('logPreventDefaults', {\n\t\tdefaults: { all: false },\n\t}),\n\tlogPointerCaptures: createDebugValue('logPointerCaptures', {\n\t\tdefaults: { all: false },\n\t}),\n\tlogElementRemoves: createDebugValue('logElementRemoves', {\n\t\tdefaults: { all: false },\n\t}),\n\tdebugSvg: createDebugValue('debugSvg', {\n\t\tdefaults: { all: false },\n\t}),\n\tshowFps: createDebugValue('showFps', {\n\t\tdefaults: { all: false },\n\t}),\n\tmeasurePerformance: createDebugValue('measurePerformance', { defaults: { all: false } }),\n\tthrowToBlob: createDebugValue('throwToBlob', {\n\t\tdefaults: { all: false },\n\t}),\n\treconnectOnPing: createDebugValue('reconnectOnPing', {\n\t\tdefaults: { all: false },\n\t}),\n\tdebugCursors: createDebugValue('debugCursors', {\n\t\tdefaults: { all: false },\n\t}),\n\tforceSrgb: createDebugValue('forceSrgbColors', { defaults: { all: false } }),\n\tdebugGeometry: createDebugValue('debugGeometry', { defaults: { all: false } }),\n\thideShapes: createDebugValue('hideShapes', { defaults: { all: false } }),\n\teditOnType: createDebugValue('editOnType', { defaults: { all: false } }),\n\ta11y: createDebugValue('a11y', { defaults: { all: false } }),\n\tdebugElbowArrows: createDebugValue('debugElbowArrows', { defaults: { all: false } }),\n} as const\n\ndeclare global {\n\tinterface Window {\n\t\ttldrawLog(message: any): void\n\t}\n}\n\n// --- 2. USE ---\n// In normal code, read from debug flags directly by calling .value on them:\n// if (debugFlags.preventDefaultLogging.value) { ... }\n//\n// In react, wrap your reads in `useValue` (or your component in `track`)\n// so they react to changes:\n// const shouldLog = useValue(debugFlags.preventDefaultLogging)\n\n// --- 3. GET FUNKY ---\n// If you need to do fun stuff like monkey-patching in response to flag changes,\n// add that here. Make sure you wrap your code in `react` so it runs\n// automatically when values change!\n\nif (typeof Element !== 'undefined') {\n\tconst nativeElementRemoveChild = Element.prototype.removeChild\n\treact('element removal logging', () => {\n\t\tif (debugFlags.logElementRemoves.get()) {\n\t\t\tElement.prototype.removeChild = function <T extends Node>(this: any, child: Node): T {\n\t\t\t\tconsole.warn('[tldraw] removing child:', child)\n\t\t\t\treturn nativeElementRemoveChild.call(this, child) as T\n\t\t\t}\n\t\t} else {\n\t\t\tElement.prototype.removeChild = nativeElementRemoveChild\n\t\t}\n\t})\n}\n\n// --- IMPLEMENTATION ---\n// you probably don't need to read this if you're just using the debug values system\nfunction createDebugValue<T>(\n\tname: string,\n\t{\n\t\tdefaults,\n\t\tshouldStoreForSession = true,\n\t}: { defaults: DebugFlagDefaults<T>; shouldStoreForSession?: boolean }\n) {\n\treturn createDebugValueBase({\n\t\tname,\n\t\tdefaults,\n\t\tshouldStoreForSession,\n\t})\n}\n\n// function createFeatureFlag<T>(\n// \tname: string,\n// \t{\n// \t\tdefaults,\n// \t\tshouldStoreForSession = true,\n// \t}: { defaults: DebugFlagDefaults<T>; shouldStoreForSession?: boolean }\n// ) {\n// \treturn createDebugValueBase({\n// \t\tname,\n// \t\tdefaults,\n// \t\tshouldStoreForSession,\n// \t})\n// }\n\nfunction createDebugValueBase<T>(def: DebugFlagDef<T>): DebugFlag<T> {\n\tconst defaultValue = getDefaultValue(def)\n\tconst storedValue = def.shouldStoreForSession\n\t\t? (getStoredInitialValue(def.name) as T | null)\n\t\t: null\n\tconst valueAtom = atom(`debug:${def.name}`, storedValue ?? defaultValue)\n\n\tif (typeof window !== 'undefined') {\n\t\tif (def.shouldStoreForSession) {\n\t\t\treact(`debug:${def.name}`, () => {\n\t\t\t\tconst currentValue = valueAtom.get()\n\t\t\t\tif (currentValue === defaultValue) {\n\t\t\t\t\tdeleteFromSessionStorage(`tldraw_debug:${def.name}`)\n\t\t\t\t} else {\n\t\t\t\t\tsetInSessionStorage(`tldraw_debug:${def.name}`, JSON.stringify(currentValue))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\tObject.defineProperty(window, `tldraw${def.name.replace(/^[a-z]/, (l) => l.toUpperCase())}`, {\n\t\t\tget() {\n\t\t\t\treturn valueAtom.get()\n\t\t\t},\n\t\t\tset(newValue) {\n\t\t\t\tvalueAtom.set(newValue)\n\t\t\t},\n\t\t\tconfigurable: true,\n\t\t})\n\t}\n\n\treturn Object.assign(valueAtom, def, {\n\t\treset: () => valueAtom.set(defaultValue),\n\t})\n}\n\nfunction getStoredInitialValue(name: string) {\n\ttry {\n\t\treturn JSON.parse(getFromSessionStorage(`tldraw_debug:${name}`) ?? 'null')\n\t} catch {\n\t\treturn null\n\t}\n}\n\n// process.env might not be defined, but we can't access it using optional\n// chaining because some bundlers search for `process.env.SOMETHING` as a string\n// and replace it with its value.\nfunction readEnv(fn: () => string | undefined) {\n\ttry {\n\t\treturn fn()\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction getDefaultValue<T>(def: DebugFlagDef<T>): T {\n\tconst env =\n\t\treadEnv(() => process.env.TLDRAW_ENV) ??\n\t\treadEnv(() => process.env.VERCEL_PUBLIC_TLDRAW_ENV) ??\n\t\treadEnv(() => process.env.NEXT_PUBLIC_TLDRAW_ENV) ??\n\t\t// default to production because if we don't have one of these, this is probably a library use\n\t\t'production'\n\n\tswitch (env) {\n\t\tcase 'production':\n\t\t\treturn def.defaults.production ?? def.defaults.all\n\t\tcase 'preview':\n\t\tcase 'staging':\n\t\t\treturn def.defaults.staging ?? def.defaults.all\n\t\tdefault:\n\t\t\treturn def.defaults.development ?? def.defaults.all\n\t}\n}\n\n/** @internal */\nexport interface DebugFlagDefaults<T> {\n\tdevelopment?: T\n\tstaging?: T\n\tproduction?: T\n\tall: T\n}\n\n/** @internal */\nexport interface DebugFlagDef<T> {\n\tname: string\n\tdefaults: DebugFlagDefaults<T>\n\tshouldStoreForSession: boolean\n}\n\n/** @internal */\nexport interface DebugFlag<T> extends DebugFlagDef<T>, Atom<T> {\n\treset(): void\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -40,10 +40,10 @@ const setStyleProperty = (elm, property, value) => {
|
|
|
40
40
|
if (!elm) return;
|
|
41
41
|
elm.style.setProperty(property, value);
|
|
42
42
|
};
|
|
43
|
-
|
|
44
|
-
function activeElementShouldCaptureKeys() {
|
|
43
|
+
function activeElementShouldCaptureKeys(allowButtons = false) {
|
|
45
44
|
const { activeElement } = document;
|
|
46
|
-
|
|
45
|
+
const elements = allowButtons ? ["input", "textarea"] : ["input", "select", "button", "textarea"];
|
|
46
|
+
return !!(activeElement && (activeElement.isContentEditable || elements.indexOf(activeElement.tagName.toLowerCase()) > -1 || activeElement.classList.contains("tlui-slider__thumb")));
|
|
47
47
|
}
|
|
48
48
|
export {
|
|
49
49
|
activeElementShouldCaptureKeys,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/utils/dom.ts"],
|
|
4
|
-
"sourcesContent": ["/*\nThis is used to facilitate double clicking and pointer capture on elements.\n\nThe events in this file are possibly set on individual SVG elements, \nsuch as handles or corner handles, rather than on HTML elements or \nSVGSVGElements. Raw SVG elemnets do not support pointerCapture in \nmost cases, meaning that in order for pointer capture to work, we \nneed to crawl up the DOM tree to find the nearest HTML element. Then,\nin order for that element to also call the `onPointerUp` event from\nthis file, we need to manually set that event on that element and\nlater remove it when the pointerup occurs. This is a potential leak\nif the user clicks on a handle but the pointerup does not fire for\nwhatever reason.\n*/\n\nimport React from 'react'\nimport { debugFlags, pointerCaptureTrackingObject } from './debug-flags'\n\n/** @public */\nexport function loopToHtmlElement(elm: Element): HTMLElement {\n\tif (elm instanceof HTMLElement) return elm\n\tif (elm.parentElement) return loopToHtmlElement(elm.parentElement)\n\telse throw Error('Could not find a parent element of an HTML type!')\n}\n\n/**\n * This function calls `event.preventDefault()` for you. Why is that useful?\n *\n * Beacuase if you enable `window.preventDefaultLogging = true` it'll log out a message when it\n * happens. Because we use console.warn rather than (log) you'll get a stack trace in the inspector\n * telling you exactly where it happened. This is important because `e.preventDefault()` is the\n * source of many bugs, but unfortuantly it can't be avoided because it also stops a lot of default\n * behaviour which doesn't make sense in our UI\n *\n * @param event - To prevent default on\n * @public\n */\nexport function preventDefault(event: React.BaseSyntheticEvent | Event) {\n\tevent.preventDefault()\n\tif (debugFlags.logPreventDefaults.get()) {\n\t\tconsole.warn('preventDefault called on event:', event)\n\t}\n}\n\n/** @public */\nexport function setPointerCapture(\n\telement: Element,\n\tevent: React.PointerEvent<Element> | PointerEvent\n) {\n\telement.setPointerCapture(event.pointerId)\n\tif (debugFlags.logPointerCaptures.get()) {\n\t\tconst trackingObj = pointerCaptureTrackingObject.get()\n\t\ttrackingObj.set(element, (trackingObj.get(element) ?? 0) + 1)\n\t\tconsole.warn('setPointerCapture called on element:', element, event)\n\t}\n}\n\n/** @public */\nexport function releasePointerCapture(\n\telement: Element,\n\tevent: React.PointerEvent<Element> | PointerEvent\n) {\n\tif (!element.hasPointerCapture(event.pointerId)) {\n\t\treturn\n\t}\n\n\telement.releasePointerCapture(event.pointerId)\n\tif (debugFlags.logPointerCaptures.get()) {\n\t\tconst trackingObj = pointerCaptureTrackingObject.get()\n\t\tif (trackingObj.get(element) === 1) {\n\t\t\ttrackingObj.delete(element)\n\t\t} else if (trackingObj.has(element)) {\n\t\t\ttrackingObj.set(element, trackingObj.get(element)! - 1)\n\t\t} else {\n\t\t\tconsole.warn('Release without capture')\n\t\t}\n\t\tconsole.warn('releasePointerCapture called on element:', element, event)\n\t}\n}\n\n/** @public */\nexport const stopEventPropagation = (e: any) => e.stopPropagation()\n\n/** @internal */\nexport const setStyleProperty = (\n\telm: HTMLElement | null,\n\tproperty: string,\n\tvalue: string | number\n) => {\n\tif (!elm) return\n\telm.style.setProperty(property, value as string)\n}\n\
|
|
5
|
-
"mappings": "AAgBA,SAAS,YAAY,oCAAoC;AAGlD,SAAS,kBAAkB,KAA2B;AAC5D,MAAI,eAAe,YAAa,QAAO;AACvC,MAAI,IAAI,cAAe,QAAO,kBAAkB,IAAI,aAAa;AAAA,MAC5D,OAAM,MAAM,kDAAkD;AACpE;AAcO,SAAS,eAAe,OAAyC;AACvE,QAAM,eAAe;AACrB,MAAI,WAAW,mBAAmB,IAAI,GAAG;AACxC,YAAQ,KAAK,mCAAmC,KAAK;AAAA,EACtD;AACD;AAGO,SAAS,kBACf,SACA,OACC;AACD,UAAQ,kBAAkB,MAAM,SAAS;AACzC,MAAI,WAAW,mBAAmB,IAAI,GAAG;AACxC,UAAM,cAAc,6BAA6B,IAAI;AACrD,gBAAY,IAAI,UAAU,YAAY,IAAI,OAAO,KAAK,KAAK,CAAC;AAC5D,YAAQ,KAAK,wCAAwC,SAAS,KAAK;AAAA,EACpE;AACD;AAGO,SAAS,sBACf,SACA,OACC;AACD,MAAI,CAAC,QAAQ,kBAAkB,MAAM,SAAS,GAAG;AAChD;AAAA,EACD;AAEA,UAAQ,sBAAsB,MAAM,SAAS;AAC7C,MAAI,WAAW,mBAAmB,IAAI,GAAG;AACxC,UAAM,cAAc,6BAA6B,IAAI;AACrD,QAAI,YAAY,IAAI,OAAO,MAAM,GAAG;AACnC,kBAAY,OAAO,OAAO;AAAA,IAC3B,WAAW,YAAY,IAAI,OAAO,GAAG;AACpC,kBAAY,IAAI,SAAS,YAAY,IAAI,OAAO,IAAK,CAAC;AAAA,IACvD,OAAO;AACN,cAAQ,KAAK,yBAAyB;AAAA,IACvC;AACA,YAAQ,KAAK,4CAA4C,SAAS,KAAK;AAAA,EACxE;AACD;AAGO,MAAM,uBAAuB,CAAC,MAAW,EAAE,gBAAgB;AAG3D,MAAM,mBAAmB,CAC/B,KACA,UACA,UACI;AACJ,MAAI,CAAC,IAAK;AACV,MAAI,MAAM,YAAY,UAAU,KAAe;AAChD;
|
|
4
|
+
"sourcesContent": ["/*\nThis is used to facilitate double clicking and pointer capture on elements.\n\nThe events in this file are possibly set on individual SVG elements, \nsuch as handles or corner handles, rather than on HTML elements or \nSVGSVGElements. Raw SVG elemnets do not support pointerCapture in \nmost cases, meaning that in order for pointer capture to work, we \nneed to crawl up the DOM tree to find the nearest HTML element. Then,\nin order for that element to also call the `onPointerUp` event from\nthis file, we need to manually set that event on that element and\nlater remove it when the pointerup occurs. This is a potential leak\nif the user clicks on a handle but the pointerup does not fire for\nwhatever reason.\n*/\n\nimport React from 'react'\nimport { debugFlags, pointerCaptureTrackingObject } from './debug-flags'\n\n/** @public */\nexport function loopToHtmlElement(elm: Element): HTMLElement {\n\tif (elm instanceof HTMLElement) return elm\n\tif (elm.parentElement) return loopToHtmlElement(elm.parentElement)\n\telse throw Error('Could not find a parent element of an HTML type!')\n}\n\n/**\n * This function calls `event.preventDefault()` for you. Why is that useful?\n *\n * Beacuase if you enable `window.preventDefaultLogging = true` it'll log out a message when it\n * happens. Because we use console.warn rather than (log) you'll get a stack trace in the inspector\n * telling you exactly where it happened. This is important because `e.preventDefault()` is the\n * source of many bugs, but unfortuantly it can't be avoided because it also stops a lot of default\n * behaviour which doesn't make sense in our UI\n *\n * @param event - To prevent default on\n * @public\n */\nexport function preventDefault(event: React.BaseSyntheticEvent | Event) {\n\tevent.preventDefault()\n\tif (debugFlags.logPreventDefaults.get()) {\n\t\tconsole.warn('preventDefault called on event:', event)\n\t}\n}\n\n/** @public */\nexport function setPointerCapture(\n\telement: Element,\n\tevent: React.PointerEvent<Element> | PointerEvent\n) {\n\telement.setPointerCapture(event.pointerId)\n\tif (debugFlags.logPointerCaptures.get()) {\n\t\tconst trackingObj = pointerCaptureTrackingObject.get()\n\t\ttrackingObj.set(element, (trackingObj.get(element) ?? 0) + 1)\n\t\tconsole.warn('setPointerCapture called on element:', element, event)\n\t}\n}\n\n/** @public */\nexport function releasePointerCapture(\n\telement: Element,\n\tevent: React.PointerEvent<Element> | PointerEvent\n) {\n\tif (!element.hasPointerCapture(event.pointerId)) {\n\t\treturn\n\t}\n\n\telement.releasePointerCapture(event.pointerId)\n\tif (debugFlags.logPointerCaptures.get()) {\n\t\tconst trackingObj = pointerCaptureTrackingObject.get()\n\t\tif (trackingObj.get(element) === 1) {\n\t\t\ttrackingObj.delete(element)\n\t\t} else if (trackingObj.has(element)) {\n\t\t\ttrackingObj.set(element, trackingObj.get(element)! - 1)\n\t\t} else {\n\t\t\tconsole.warn('Release without capture')\n\t\t}\n\t\tconsole.warn('releasePointerCapture called on element:', element, event)\n\t}\n}\n\n/** @public */\nexport const stopEventPropagation = (e: any) => e.stopPropagation()\n\n/** @internal */\nexport const setStyleProperty = (\n\telm: HTMLElement | null,\n\tproperty: string,\n\tvalue: string | number\n) => {\n\tif (!elm) return\n\telm.style.setProperty(property, value as string)\n}\n\n/** @internal */\nexport function activeElementShouldCaptureKeys(allowButtons = false) {\n\tconst { activeElement } = document\n\tconst elements = allowButtons ? ['input', 'textarea'] : ['input', 'select', 'button', 'textarea']\n\treturn !!(\n\t\tactiveElement &&\n\t\t((activeElement as HTMLElement).isContentEditable ||\n\t\t\telements.indexOf(activeElement.tagName.toLowerCase()) > -1 ||\n\t\t\tactiveElement.classList.contains('tlui-slider__thumb'))\n\t)\n}\n"],
|
|
5
|
+
"mappings": "AAgBA,SAAS,YAAY,oCAAoC;AAGlD,SAAS,kBAAkB,KAA2B;AAC5D,MAAI,eAAe,YAAa,QAAO;AACvC,MAAI,IAAI,cAAe,QAAO,kBAAkB,IAAI,aAAa;AAAA,MAC5D,OAAM,MAAM,kDAAkD;AACpE;AAcO,SAAS,eAAe,OAAyC;AACvE,QAAM,eAAe;AACrB,MAAI,WAAW,mBAAmB,IAAI,GAAG;AACxC,YAAQ,KAAK,mCAAmC,KAAK;AAAA,EACtD;AACD;AAGO,SAAS,kBACf,SACA,OACC;AACD,UAAQ,kBAAkB,MAAM,SAAS;AACzC,MAAI,WAAW,mBAAmB,IAAI,GAAG;AACxC,UAAM,cAAc,6BAA6B,IAAI;AACrD,gBAAY,IAAI,UAAU,YAAY,IAAI,OAAO,KAAK,KAAK,CAAC;AAC5D,YAAQ,KAAK,wCAAwC,SAAS,KAAK;AAAA,EACpE;AACD;AAGO,SAAS,sBACf,SACA,OACC;AACD,MAAI,CAAC,QAAQ,kBAAkB,MAAM,SAAS,GAAG;AAChD;AAAA,EACD;AAEA,UAAQ,sBAAsB,MAAM,SAAS;AAC7C,MAAI,WAAW,mBAAmB,IAAI,GAAG;AACxC,UAAM,cAAc,6BAA6B,IAAI;AACrD,QAAI,YAAY,IAAI,OAAO,MAAM,GAAG;AACnC,kBAAY,OAAO,OAAO;AAAA,IAC3B,WAAW,YAAY,IAAI,OAAO,GAAG;AACpC,kBAAY,IAAI,SAAS,YAAY,IAAI,OAAO,IAAK,CAAC;AAAA,IACvD,OAAO;AACN,cAAQ,KAAK,yBAAyB;AAAA,IACvC;AACA,YAAQ,KAAK,4CAA4C,SAAS,KAAK;AAAA,EACxE;AACD;AAGO,MAAM,uBAAuB,CAAC,MAAW,EAAE,gBAAgB;AAG3D,MAAM,mBAAmB,CAC/B,KACA,UACA,UACI;AACJ,MAAI,CAAC,IAAK;AACV,MAAI,MAAM,YAAY,UAAU,KAAe;AAChD;AAGO,SAAS,+BAA+B,eAAe,OAAO;AACpE,QAAM,EAAE,cAAc,IAAI;AAC1B,QAAM,WAAW,eAAe,CAAC,SAAS,UAAU,IAAI,CAAC,SAAS,UAAU,UAAU,UAAU;AAChG,SAAO,CAAC,EACP,kBACE,cAA8B,qBAC/B,SAAS,QAAQ,cAAc,QAAQ,YAAY,CAAC,IAAI,MACxD,cAAc,UAAU,SAAS,oBAAoB;AAExD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
function gcd(a, b) {
|
|
2
|
+
return b === 0 ? a : gcd(b, a % b);
|
|
3
|
+
}
|
|
4
|
+
function nearestMultiple(float) {
|
|
5
|
+
const decimal = float.toString().split(".")[1];
|
|
6
|
+
if (!decimal) return 1;
|
|
7
|
+
const denominator = Math.pow(10, decimal.length);
|
|
8
|
+
const numerator = parseInt(decimal, 10);
|
|
9
|
+
return denominator / gcd(numerator, denominator);
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
nearestMultiple
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=nearestMultiple.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/lib/utils/nearestMultiple.ts"],
|
|
4
|
+
"sourcesContent": ["// Euclidean algorithm to find the GCD\nfunction gcd(a: number, b: number): number {\n\treturn b === 0 ? a : gcd(b, a % b)\n}\n\n// Returns the lowest value that the given number can be multiplied by to reach an integer\nexport function nearestMultiple(float: number) {\n\tconst decimal = float.toString().split('.')[1]\n\tif (!decimal) return 1\n\tconst denominator = Math.pow(10, decimal.length)\n\tconst numerator = parseInt(decimal, 10)\n\treturn denominator / gcd(numerator, denominator)\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,IAAI,GAAW,GAAmB;AAC1C,SAAO,MAAM,IAAI,IAAI,IAAI,GAAG,IAAI,CAAC;AAClC;AAGO,SAAS,gBAAgB,OAAe;AAC9C,QAAM,UAAU,MAAM,SAAS,EAAE,MAAM,GAAG,EAAE,CAAC;AAC7C,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,cAAc,KAAK,IAAI,IAAI,QAAQ,MAAM;AAC/C,QAAM,YAAY,SAAS,SAAS,EAAE;AACtC,SAAO,cAAc,IAAI,WAAW,WAAW;AAChD;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -13,10 +13,10 @@ function getRotationSnapshot({
|
|
|
13
13
|
if (!rotatedPageBounds) {
|
|
14
14
|
return null;
|
|
15
15
|
}
|
|
16
|
-
const
|
|
16
|
+
const initialPageCenter = rotatedPageBounds.center.clone().rotWith(rotatedPageBounds.point, rotation);
|
|
17
17
|
return {
|
|
18
|
-
|
|
19
|
-
initialCursorAngle:
|
|
18
|
+
initialPageCenter,
|
|
19
|
+
initialCursorAngle: initialPageCenter.angle(editor.inputs.originPagePoint),
|
|
20
20
|
initialShapesRotation: rotation,
|
|
21
21
|
shapeSnapshots: shapes.map((shape) => ({
|
|
22
22
|
shape,
|
|
@@ -31,11 +31,11 @@ function applyRotationToSnapshotShapes({
|
|
|
31
31
|
stage,
|
|
32
32
|
centerOverride
|
|
33
33
|
}) {
|
|
34
|
-
const {
|
|
34
|
+
const { initialPageCenter, shapeSnapshots } = snapshot;
|
|
35
35
|
editor.updateShapes(
|
|
36
36
|
shapeSnapshots.map(({ shape, initialPagePoint }) => {
|
|
37
37
|
const parentTransform = isShapeId(shape.parentId) ? editor.getShapePageTransform(shape.parentId) : Mat.Identity();
|
|
38
|
-
const newPagePoint = Vec.RotWith(initialPagePoint, centerOverride ??
|
|
38
|
+
const newPagePoint = Vec.RotWith(initialPagePoint, centerOverride ?? initialPageCenter, delta);
|
|
39
39
|
const newLocalPoint = Mat.applyToPoint(
|
|
40
40
|
// use the current parent transform in case it has moved/resized since the start
|
|
41
41
|
// (e.g. if rotating a shape at the edge of a group)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/utils/rotation.ts"],
|
|
4
|
-
"sourcesContent": ["import { isShapeId, TLShape, TLShapeId, TLShapePartial } from '@tldraw/tlschema'\nimport { compact } from '@tldraw/utils'\nimport { Editor } from '../editor/Editor'\nimport { Mat } from '../primitives/Mat'\nimport { canonicalizeRotation } from '../primitives/utils'\nimport { Vec, VecLike } from '../primitives/Vec'\n\n/** @internal */\nexport function getRotationSnapshot({\n\teditor,\n\tids,\n}: {\n\teditor: Editor\n\tids: TLShapeId[]\n}): TLRotationSnapshot | null {\n\tconst shapes = compact(ids.map((id) => editor.getShape(id)))\n\tconst rotation = editor.getShapesSharedRotation(ids)\n\tconst rotatedPageBounds = editor.getShapesRotatedPageBounds(ids)\n\n\t// todo: this assumes we're rotating the selected shapes\n\t// if we try to rotate shapes that aren't selected, this\n\t// will produce the wrong results\n\n\t// Return null if there are no selected shapes\n\tif (!rotatedPageBounds) {\n\t\treturn null\n\t}\n\n\tconst
|
|
5
|
-
"mappings": "AAAA,SAAS,iBAAqD;AAC9D,SAAS,eAAe;AAExB,SAAS,WAAW;AACpB,SAAS,4BAA4B;AACrC,SAAS,WAAoB;AAGtB,SAAS,oBAAoB;AAAA,EACnC;AAAA,EACA;AACD,GAG8B;AAC7B,QAAM,SAAS,QAAQ,IAAI,IAAI,CAAC,OAAO,OAAO,SAAS,EAAE,CAAC,CAAC;AAC3D,QAAM,WAAW,OAAO,wBAAwB,GAAG;AACnD,QAAM,oBAAoB,OAAO,2BAA2B,GAAG;AAO/D,MAAI,CAAC,mBAAmB;AACvB,WAAO;AAAA,EACR;AAEA,QAAM,
|
|
4
|
+
"sourcesContent": ["import { isShapeId, TLShape, TLShapeId, TLShapePartial } from '@tldraw/tlschema'\nimport { compact } from '@tldraw/utils'\nimport { Editor } from '../editor/Editor'\nimport { Mat } from '../primitives/Mat'\nimport { canonicalizeRotation } from '../primitives/utils'\nimport { Vec, VecLike } from '../primitives/Vec'\n\n/** @internal */\nexport function getRotationSnapshot({\n\teditor,\n\tids,\n}: {\n\teditor: Editor\n\tids: TLShapeId[]\n}): TLRotationSnapshot | null {\n\tconst shapes = compact(ids.map((id) => editor.getShape(id)))\n\tconst rotation = editor.getShapesSharedRotation(ids)\n\tconst rotatedPageBounds = editor.getShapesRotatedPageBounds(ids)\n\n\t// todo: this assumes we're rotating the selected shapes\n\t// if we try to rotate shapes that aren't selected, this\n\t// will produce the wrong results\n\n\t// Return null if there are no selected shapes\n\tif (!rotatedPageBounds) {\n\t\treturn null\n\t}\n\n\tconst initialPageCenter = rotatedPageBounds.center\n\t\t.clone()\n\t\t.rotWith(rotatedPageBounds.point, rotation)\n\n\treturn {\n\t\tinitialPageCenter,\n\t\tinitialCursorAngle: initialPageCenter.angle(editor.inputs.originPagePoint),\n\t\tinitialShapesRotation: rotation,\n\t\tshapeSnapshots: shapes.map((shape) => ({\n\t\t\tshape,\n\t\t\tinitialPagePoint: editor.getShapePageTransform(shape.id)!.point(),\n\t\t})),\n\t}\n}\n\n/**\n * @internal\n **/\nexport interface TLRotationSnapshot {\n\tinitialPageCenter: Vec\n\tinitialCursorAngle: number\n\tinitialShapesRotation: number\n\tshapeSnapshots: {\n\t\tshape: TLShape\n\t\tinitialPagePoint: Vec\n\t}[]\n}\n\n/** @internal */\nexport function applyRotationToSnapshotShapes({\n\tdelta,\n\teditor,\n\tsnapshot,\n\tstage,\n\tcenterOverride,\n}: {\n\tdelta: number\n\tsnapshot: TLRotationSnapshot\n\teditor: Editor\n\tstage: 'start' | 'update' | 'end' | 'one-off'\n\tcenterOverride?: VecLike\n}) {\n\tconst { initialPageCenter, shapeSnapshots } = snapshot\n\n\teditor.updateShapes(\n\t\tshapeSnapshots.map(({ shape, initialPagePoint }) => {\n\t\t\t// We need to both rotate each shape individually and rotate the shapes\n\t\t\t// around the pivot point (the average center of all rotating shapes.)\n\n\t\t\tconst parentTransform = isShapeId(shape.parentId)\n\t\t\t\t? editor.getShapePageTransform(shape.parentId)!\n\t\t\t\t: Mat.Identity()\n\n\t\t\tconst newPagePoint = Vec.RotWith(initialPagePoint, centerOverride ?? initialPageCenter, delta)\n\n\t\t\tconst newLocalPoint = Mat.applyToPoint(\n\t\t\t\t// use the current parent transform in case it has moved/resized since the start\n\t\t\t\t// (e.g. if rotating a shape at the edge of a group)\n\t\t\t\tMat.Inverse(parentTransform),\n\t\t\t\tnewPagePoint\n\t\t\t)\n\t\t\tconst newRotation = canonicalizeRotation(shape.rotation + delta)\n\n\t\t\treturn {\n\t\t\t\tid: shape.id,\n\t\t\t\ttype: shape.type,\n\t\t\t\tx: newLocalPoint.x,\n\t\t\t\ty: newLocalPoint.y,\n\t\t\t\trotation: newRotation,\n\t\t\t}\n\t\t})\n\t)\n\n\t// Handle change\n\n\tconst changes: TLShapePartial[] = []\n\n\tshapeSnapshots.forEach(({ shape }) => {\n\t\tconst current = editor.getShape(shape.id)\n\t\tif (!current) return\n\t\tconst util = editor.getShapeUtil(shape)\n\n\t\tif (stage === 'start' || stage === 'one-off') {\n\t\t\tconst changeStart = util.onRotateStart?.(shape)\n\t\t\tif (changeStart) changes.push(changeStart)\n\t\t}\n\n\t\tconst changeUpdate = util.onRotate?.(shape, current)\n\t\tif (changeUpdate) changes.push(changeUpdate)\n\n\t\tif (stage === 'end' || stage === 'one-off') {\n\t\t\tconst changeEnd = util.onRotateEnd?.(shape, current)\n\t\t\tif (changeEnd) changes.push(changeEnd)\n\t\t}\n\t})\n\n\tif (changes.length > 0) {\n\t\teditor.updateShapes(changes)\n\t}\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAqD;AAC9D,SAAS,eAAe;AAExB,SAAS,WAAW;AACpB,SAAS,4BAA4B;AACrC,SAAS,WAAoB;AAGtB,SAAS,oBAAoB;AAAA,EACnC;AAAA,EACA;AACD,GAG8B;AAC7B,QAAM,SAAS,QAAQ,IAAI,IAAI,CAAC,OAAO,OAAO,SAAS,EAAE,CAAC,CAAC;AAC3D,QAAM,WAAW,OAAO,wBAAwB,GAAG;AACnD,QAAM,oBAAoB,OAAO,2BAA2B,GAAG;AAO/D,MAAI,CAAC,mBAAmB;AACvB,WAAO;AAAA,EACR;AAEA,QAAM,oBAAoB,kBAAkB,OAC1C,MAAM,EACN,QAAQ,kBAAkB,OAAO,QAAQ;AAE3C,SAAO;AAAA,IACN;AAAA,IACA,oBAAoB,kBAAkB,MAAM,OAAO,OAAO,eAAe;AAAA,IACzE,uBAAuB;AAAA,IACvB,gBAAgB,OAAO,IAAI,CAAC,WAAW;AAAA,MACtC;AAAA,MACA,kBAAkB,OAAO,sBAAsB,MAAM,EAAE,EAAG,MAAM;AAAA,IACjE,EAAE;AAAA,EACH;AACD;AAgBO,SAAS,8BAA8B;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAMG;AACF,QAAM,EAAE,mBAAmB,eAAe,IAAI;AAE9C,SAAO;AAAA,IACN,eAAe,IAAI,CAAC,EAAE,OAAO,iBAAiB,MAAM;AAInD,YAAM,kBAAkB,UAAU,MAAM,QAAQ,IAC7C,OAAO,sBAAsB,MAAM,QAAQ,IAC3C,IAAI,SAAS;AAEhB,YAAM,eAAe,IAAI,QAAQ,kBAAkB,kBAAkB,mBAAmB,KAAK;AAE7F,YAAM,gBAAgB,IAAI;AAAA;AAAA;AAAA,QAGzB,IAAI,QAAQ,eAAe;AAAA,QAC3B;AAAA,MACD;AACA,YAAM,cAAc,qBAAqB,MAAM,WAAW,KAAK;AAE/D,aAAO;AAAA,QACN,IAAI,MAAM;AAAA,QACV,MAAM,MAAM;AAAA,QACZ,GAAG,cAAc;AAAA,QACjB,GAAG,cAAc;AAAA,QACjB,UAAU;AAAA,MACX;AAAA,IACD,CAAC;AAAA,EACF;AAIA,QAAM,UAA4B,CAAC;AAEnC,iBAAe,QAAQ,CAAC,EAAE,MAAM,MAAM;AACrC,UAAM,UAAU,OAAO,SAAS,MAAM,EAAE;AACxC,QAAI,CAAC,QAAS;AACd,UAAM,OAAO,OAAO,aAAa,KAAK;AAEtC,QAAI,UAAU,WAAW,UAAU,WAAW;AAC7C,YAAM,cAAc,KAAK,gBAAgB,KAAK;AAC9C,UAAI,YAAa,SAAQ,KAAK,WAAW;AAAA,IAC1C;AAEA,UAAM,eAAe,KAAK,WAAW,OAAO,OAAO;AACnD,QAAI,aAAc,SAAQ,KAAK,YAAY;AAE3C,QAAI,UAAU,SAAS,UAAU,WAAW;AAC3C,YAAM,YAAY,KAAK,cAAc,OAAO,OAAO;AACnD,UAAI,UAAW,SAAQ,KAAK,SAAS;AAAA,IACtC;AAAA,EACD,CAAC;AAED,MAAI,QAAQ,SAAS,GAAG;AACvB,WAAO,aAAa,OAAO;AAAA,EAC5B;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-esm/version.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const version = "3.13.0-canary.
|
|
1
|
+
const version = "3.13.0-canary.ae38fb277ff7";
|
|
2
2
|
const publishDates = {
|
|
3
3
|
major: "2024-09-13T14:36:29.063Z",
|
|
4
|
-
minor: "2025-
|
|
5
|
-
patch: "2025-
|
|
4
|
+
minor: "2025-05-09T08:36:18.073Z",
|
|
5
|
+
patch: "2025-05-09T08:36:18.073Z"
|
|
6
6
|
};
|
|
7
7
|
export {
|
|
8
8
|
publishDates,
|
package/dist-esm/version.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/version.ts"],
|
|
4
|
-
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.13.0-canary.
|
|
4
|
+
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.13.0-canary.ae38fb277ff7'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-05-09T08:36:18.073Z',\n\tpatch: '2025-05-09T08:36:18.073Z',\n}\n"],
|
|
5
5
|
"mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|