@tldraw/editor 3.13.0-canary.c0afd1f5aa1e → 3.13.0-canary.c4135f4903f5
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 +99 -99
- package/dist-cjs/index.js +22 -7
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +6 -10
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +16 -64
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TextManager.js +0 -10
- package/dist-cjs/lib/editor/managers/TextManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +1 -1
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +3 -0
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js.map +2 -2
- package/dist-cjs/lib/hooks/useEditorComponents.js +2 -1
- package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
- package/dist-cjs/lib/primitives/Box.js +0 -16
- 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 +0 -20
- 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 +20 -91
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Group2d.js +2 -55
- 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/debug-flags.js +2 -5
- package/dist-cjs/lib/utils/debug-flags.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 +99 -99
- package/dist-esm/index.mjs +41 -9
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +6 -10
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +16 -64
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TextManager.mjs +0 -10
- package/dist-esm/lib/editor/managers/TextManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +1 -1
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +3 -0
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs.map +2 -2
- package/dist-esm/lib/hooks/useEditorComponents.mjs +4 -1
- package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
- package/dist-esm/lib/primitives/Box.mjs +0 -16
- 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 +0 -20
- 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 +21 -92
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs +2 -55
- 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/debug-flags.mjs +2 -5
- package/dist-esm/lib/utils/debug-flags.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +4 -36
- package/package.json +7 -7
- package/src/index.ts +31 -16
- package/src/lib/components/default-components/DefaultCanvas.tsx +6 -11
- package/src/lib/editor/Editor.test.ts +1 -1
- package/src/lib/editor/Editor.ts +16 -75
- package/src/lib/editor/managers/SnapManager/HandleSnaps.ts +1 -0
- package/src/lib/editor/managers/TextManager.ts +0 -12
- package/src/lib/editor/shapes/ShapeUtil.ts +2 -10
- package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +4 -0
- package/src/lib/editor/shapes/shared/getPerfectDashProps.ts +9 -9
- package/src/lib/hooks/useEditorComponents.tsx +5 -2
- package/src/lib/primitives/Box.ts +0 -20
- package/src/lib/primitives/Mat.ts +4 -5
- package/src/lib/primitives/Vec.ts +0 -23
- 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.ts +35 -123
- package/src/lib/primitives/geometry/Group2d.ts +7 -70
- 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/debug-flags.ts +2 -7
- 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
- package/src/lib/primitives/geometry/Geometry2d.test.ts +0 -42
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Vec
|
|
1
|
+
import { Vec } from '../Vec'
|
|
2
2
|
import { intersectLineSegmentCircle } from '../intersect'
|
|
3
3
|
import { getArcMeasure, getPointInArcT, getPointOnCircle } from '../utils'
|
|
4
4
|
import { Geometry2d, Geometry2dOptions } from './Geometry2d'
|
|
@@ -44,14 +44,14 @@ export class Arc2d extends Geometry2d {
|
|
|
44
44
|
this._center = center
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
nearestPoint(point:
|
|
47
|
+
nearestPoint(point: Vec): Vec {
|
|
48
48
|
const { _center, measure, radius, angleEnd, angleStart, start: A, end: B } = this
|
|
49
49
|
const t = getPointInArcT(measure, angleStart, angleEnd, _center.angle(point))
|
|
50
50
|
if (t <= 0) return A
|
|
51
51
|
if (t >= 1) return B
|
|
52
52
|
|
|
53
53
|
// Get the point (P) on the arc, then pick the nearest of A, B, and P
|
|
54
|
-
const P =
|
|
54
|
+
const P = _center.clone().add(point.clone().sub(_center).uni().mul(radius))
|
|
55
55
|
|
|
56
56
|
let nearest: Vec | undefined
|
|
57
57
|
let dist = Infinity
|
|
@@ -67,7 +67,7 @@ export class Arc2d extends Geometry2d {
|
|
|
67
67
|
return nearest
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
hitTestLineSegment(A:
|
|
70
|
+
hitTestLineSegment(A: Vec, B: Vec): boolean {
|
|
71
71
|
const { _center, radius, measure, angleStart, angleEnd } = this
|
|
72
72
|
const intersection = intersectLineSegmentCircle(A, B, _center, radius)
|
|
73
73
|
if (intersection === null) return false
|
|
@@ -95,6 +95,6 @@ export class Arc2d extends Geometry2d {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
override getLength() {
|
|
98
|
-
return
|
|
98
|
+
return this.measure * this.radius
|
|
99
99
|
}
|
|
100
100
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Box } from '../Box'
|
|
2
|
-
import { Vec
|
|
2
|
+
import { Vec } from '../Vec'
|
|
3
3
|
import { intersectLineSegmentCircle } from '../intersect'
|
|
4
4
|
import { PI2, getPointOnCircle } from '../utils'
|
|
5
5
|
import { Geometry2d, Geometry2dOptions } from './Geometry2d'
|
|
@@ -43,13 +43,13 @@ export class Circle2d extends Geometry2d {
|
|
|
43
43
|
return vertices
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
nearestPoint(point:
|
|
46
|
+
nearestPoint(point: Vec): Vec {
|
|
47
47
|
const { _center, radius } = this
|
|
48
48
|
if (_center.equals(point)) return Vec.AddXY(_center, radius, 0)
|
|
49
|
-
return
|
|
49
|
+
return _center.clone().add(point.clone().sub(_center).uni().mul(radius))
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
hitTestLineSegment(A:
|
|
52
|
+
hitTestLineSegment(A: Vec, B: Vec, distance = 0): boolean {
|
|
53
53
|
const { _center, radius } = this
|
|
54
54
|
return intersectLineSegmentCircle(A, B, _center, radius + distance) !== null
|
|
55
55
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Vec
|
|
2
|
-
import {
|
|
1
|
+
import { Vec } from '../Vec'
|
|
2
|
+
import { Geometry2dOptions } from './Geometry2d'
|
|
3
3
|
import { Polyline2d } from './Polyline2d'
|
|
4
4
|
|
|
5
5
|
/** @public */
|
|
@@ -52,7 +52,7 @@ export class CubicBezier2d extends Polyline2d {
|
|
|
52
52
|
return CubicBezier2d.GetAtT(this, 0.5)
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
nearestPoint(A:
|
|
55
|
+
nearestPoint(A: Vec): Vec {
|
|
56
56
|
let nearest: Vec | undefined
|
|
57
57
|
let dist = Infinity
|
|
58
58
|
let d: number
|
|
@@ -89,7 +89,7 @@ export class CubicBezier2d extends Polyline2d {
|
|
|
89
89
|
)
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
override getLength(
|
|
92
|
+
override getLength(precision = 32) {
|
|
93
93
|
let n1: Vec,
|
|
94
94
|
p1 = this.a,
|
|
95
95
|
length = 0
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Vec
|
|
1
|
+
import { Vec } from '../Vec'
|
|
2
2
|
import { CubicBezier2d } from './CubicBezier2d'
|
|
3
3
|
import { Geometry2d, Geometry2dOptions } from './Geometry2d'
|
|
4
4
|
|
|
@@ -58,7 +58,7 @@ export class CubicSpline2d extends Geometry2d {
|
|
|
58
58
|
return vertices
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
nearestPoint(A:
|
|
61
|
+
nearestPoint(A: Vec): Vec {
|
|
62
62
|
let nearest: Vec | undefined
|
|
63
63
|
let dist = Infinity
|
|
64
64
|
let d: number
|
|
@@ -75,7 +75,7 @@ export class CubicSpline2d extends Geometry2d {
|
|
|
75
75
|
return nearest
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
hitTestLineSegment(A:
|
|
78
|
+
hitTestLineSegment(A: Vec, B: Vec): boolean {
|
|
79
79
|
return this.segments.some((segment) => segment.hitTestLineSegment(A, B))
|
|
80
80
|
}
|
|
81
81
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { Vec } from '../Vec'
|
|
1
2
|
import { linesIntersect } from '../intersect'
|
|
2
|
-
import { Vec, VecLike } from '../Vec'
|
|
3
3
|
import { Geometry2d } from './Geometry2d'
|
|
4
4
|
|
|
5
5
|
/** @public */
|
|
@@ -34,7 +34,7 @@ export class Edge2d extends Geometry2d {
|
|
|
34
34
|
return [this.start, this.end]
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
override nearestPoint(point:
|
|
37
|
+
override nearestPoint(point: Vec): Vec {
|
|
38
38
|
const { start, end, d, u, ul: l } = this
|
|
39
39
|
if (d.len() === 0) return start // start and end are the same
|
|
40
40
|
if (l === 0) return start // no length in the unit vector
|
|
@@ -48,7 +48,7 @@ export class Edge2d extends Geometry2d {
|
|
|
48
48
|
return new Vec(cx, cy)
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
override hitTestLineSegment(A:
|
|
51
|
+
override hitTestLineSegment(A: Vec, B: Vec, distance = 0): boolean {
|
|
52
52
|
return (
|
|
53
53
|
linesIntersect(A, B, this.start, this.end) || this.distanceToLineSegment(A, B) <= distance
|
|
54
54
|
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Box } from '../Box'
|
|
2
|
-
import { Vec
|
|
2
|
+
import { Vec } from '../Vec'
|
|
3
3
|
import { PI, PI2, perimeterOfEllipse } from '../utils'
|
|
4
4
|
import { Edge2d } from './Edge2d'
|
|
5
5
|
import { Geometry2d, Geometry2dOptions } from './Geometry2d'
|
|
@@ -73,7 +73,7 @@ export class Ellipse2d extends Geometry2d {
|
|
|
73
73
|
return vertices
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
nearestPoint(A:
|
|
76
|
+
nearestPoint(A: Vec): Vec {
|
|
77
77
|
let nearest: Vec | undefined
|
|
78
78
|
let dist = Infinity
|
|
79
79
|
let d: number
|
|
@@ -90,7 +90,7 @@ export class Ellipse2d extends Geometry2d {
|
|
|
90
90
|
return nearest
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
hitTestLineSegment(A:
|
|
93
|
+
hitTestLineSegment(A: Vec, B: Vec): boolean {
|
|
94
94
|
return this.edges.some((edge) => edge.hitTestLineSegment(A, B))
|
|
95
95
|
}
|
|
96
96
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { assert
|
|
1
|
+
import { assert } from '@tldraw/utils'
|
|
2
2
|
import { Box } from '../Box'
|
|
3
3
|
import { Mat, MatModel } from '../Mat'
|
|
4
4
|
import { Vec, VecLike } from '../Vec'
|
|
@@ -81,9 +81,9 @@ export abstract class Geometry2d {
|
|
|
81
81
|
|
|
82
82
|
abstract getVertices(filters: Geometry2dFilters): Vec[]
|
|
83
83
|
|
|
84
|
-
abstract nearestPoint(point:
|
|
84
|
+
abstract nearestPoint(point: Vec, _filters?: Geometry2dFilters): Vec
|
|
85
85
|
|
|
86
|
-
hitTestPoint(point:
|
|
86
|
+
hitTestPoint(point: Vec, margin = 0, hitInside = false, _filters?: Geometry2dFilters) {
|
|
87
87
|
// First check whether the point is inside
|
|
88
88
|
if (this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices)) {
|
|
89
89
|
return true
|
|
@@ -92,17 +92,17 @@ export abstract class Geometry2d {
|
|
|
92
92
|
return Vec.Dist2(point, this.nearestPoint(point)) <= margin * margin
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
distanceToPoint(point:
|
|
95
|
+
distanceToPoint(point: Vec, hitInside = false, filters?: Geometry2dFilters) {
|
|
96
96
|
return (
|
|
97
|
-
|
|
97
|
+
point.dist(this.nearestPoint(point, filters)) *
|
|
98
98
|
(this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices)
|
|
99
99
|
? -1
|
|
100
100
|
: 1)
|
|
101
101
|
)
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
distanceToLineSegment(A:
|
|
105
|
-
if (
|
|
104
|
+
distanceToLineSegment(A: Vec, B: Vec, filters?: Geometry2dFilters) {
|
|
105
|
+
if (A.equals(B)) return this.distanceToPoint(A, false, filters)
|
|
106
106
|
const { vertices } = this
|
|
107
107
|
let nearest: Vec | undefined
|
|
108
108
|
let dist = Infinity
|
|
@@ -120,7 +120,7 @@ export abstract class Geometry2d {
|
|
|
120
120
|
return this.isClosed && this.isFilled && pointInPolygon(nearest, this.vertices) ? -dist : dist
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
hitTestLineSegment(A:
|
|
123
|
+
hitTestLineSegment(A: Vec, B: Vec, distance = 0, filters?: Geometry2dFilters): boolean {
|
|
124
124
|
return this.distanceToLineSegment(A, B, filters) <= distance
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -148,76 +148,8 @@ export abstract class Geometry2d {
|
|
|
148
148
|
return intersectPolys(polyline, this.vertices, false, this.isClosed)
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
/**
|
|
152
|
-
* Find a point along the edge of the geometry that is a fraction `t` along the entire way round.
|
|
153
|
-
*/
|
|
154
|
-
interpolateAlongEdge(t: number, _filters?: Geometry2dFilters): Vec {
|
|
155
|
-
const { vertices } = this
|
|
156
|
-
|
|
157
|
-
if (t <= 0) return vertices[0]
|
|
158
|
-
|
|
159
|
-
const distanceToTravel = t * this.length
|
|
160
|
-
let distanceTraveled = 0
|
|
161
|
-
|
|
162
|
-
for (let i = 0; i < (this.isClosed ? vertices.length : vertices.length - 1); i++) {
|
|
163
|
-
const curr = vertices[i]
|
|
164
|
-
const next = vertices[(i + 1) % vertices.length]
|
|
165
|
-
const dist = Vec.Dist(curr, next)
|
|
166
|
-
const newDistanceTraveled = distanceTraveled + dist
|
|
167
|
-
if (newDistanceTraveled >= distanceToTravel) {
|
|
168
|
-
const p = Vec.Lrp(
|
|
169
|
-
curr,
|
|
170
|
-
next,
|
|
171
|
-
invLerp(distanceTraveled, newDistanceTraveled, distanceToTravel)
|
|
172
|
-
)
|
|
173
|
-
return p
|
|
174
|
-
}
|
|
175
|
-
distanceTraveled = newDistanceTraveled
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return this.isClosed ? vertices[0] : vertices[vertices.length - 1]
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Take `point`, find the closest point to it on the edge of the geometry, and return how far
|
|
183
|
-
* along the edge it is as a fraction of the total length.
|
|
184
|
-
*/
|
|
185
|
-
uninterpolateAlongEdge(point: VecLike, _filters?: Geometry2dFilters): number {
|
|
186
|
-
const { vertices, length } = this
|
|
187
|
-
let closestSegment = null
|
|
188
|
-
let closestDistance = Infinity
|
|
189
|
-
let distanceTraveled = 0
|
|
190
|
-
|
|
191
|
-
for (let i = 0; i < (this.isClosed ? vertices.length : vertices.length - 1); i++) {
|
|
192
|
-
const curr = vertices[i]
|
|
193
|
-
const next = vertices[(i + 1) % vertices.length]
|
|
194
|
-
|
|
195
|
-
const nearestPoint = Vec.NearestPointOnLineSegment(curr, next, point, true)
|
|
196
|
-
const distance = Vec.Dist(nearestPoint, point)
|
|
197
|
-
|
|
198
|
-
if (distance < closestDistance) {
|
|
199
|
-
closestDistance = distance
|
|
200
|
-
closestSegment = {
|
|
201
|
-
start: curr,
|
|
202
|
-
end: next,
|
|
203
|
-
nearestPoint,
|
|
204
|
-
distanceToStart: distanceTraveled,
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
distanceTraveled += Vec.Dist(curr, next)
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
assert(closestSegment)
|
|
212
|
-
|
|
213
|
-
const distanceAlongRoute =
|
|
214
|
-
closestSegment.distanceToStart + Vec.Dist(closestSegment.start, closestSegment.nearestPoint)
|
|
215
|
-
|
|
216
|
-
return distanceAlongRoute / length
|
|
217
|
-
}
|
|
218
|
-
|
|
219
151
|
/** @deprecated Iterate the vertices instead. */
|
|
220
|
-
nearestPointOnLineSegment(A:
|
|
152
|
+
nearestPointOnLineSegment(A: Vec, B: Vec): Vec {
|
|
221
153
|
const { vertices } = this
|
|
222
154
|
let nearest: Vec | undefined
|
|
223
155
|
let dist = Infinity
|
|
@@ -235,7 +167,7 @@ export abstract class Geometry2d {
|
|
|
235
167
|
return nearest
|
|
236
168
|
}
|
|
237
169
|
|
|
238
|
-
isPointInBounds(point:
|
|
170
|
+
isPointInBounds(point: Vec, margin = 0) {
|
|
239
171
|
const { bounds } = this
|
|
240
172
|
return !(
|
|
241
173
|
point.x < bounds.minX - margin ||
|
|
@@ -329,24 +261,21 @@ export abstract class Geometry2d {
|
|
|
329
261
|
// eslint-disable-next-line no-restricted-syntax
|
|
330
262
|
get length() {
|
|
331
263
|
if (this._length) return this._length
|
|
332
|
-
this._length = this.getLength(
|
|
264
|
+
this._length = this.getLength()
|
|
333
265
|
return this._length
|
|
334
266
|
}
|
|
335
267
|
|
|
336
|
-
getLength(
|
|
337
|
-
const vertices = this
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
268
|
+
getLength() {
|
|
269
|
+
const { vertices } = this
|
|
270
|
+
let n1: Vec,
|
|
271
|
+
p1 = vertices[0],
|
|
272
|
+
length = 0
|
|
341
273
|
for (let i = 1; i < vertices.length; i++) {
|
|
342
|
-
|
|
343
|
-
length += Vec.
|
|
344
|
-
|
|
345
|
-
}
|
|
346
|
-
if (this.isClosed) {
|
|
347
|
-
length += Vec.Dist(vertices[vertices.length - 1], vertices[0])
|
|
274
|
+
n1 = vertices[i]
|
|
275
|
+
length += Vec.Dist2(p1, n1)
|
|
276
|
+
p1 = n1
|
|
348
277
|
}
|
|
349
|
-
return length
|
|
278
|
+
return Math.sqrt(length)
|
|
350
279
|
}
|
|
351
280
|
|
|
352
281
|
abstract getSvgPathData(first: boolean): string
|
|
@@ -388,7 +317,7 @@ export class TransformedGeometry2d extends Geometry2d {
|
|
|
388
317
|
return this.geometry.getVertices(filters).map((v) => Mat.applyToPoint(this.matrix, v))
|
|
389
318
|
}
|
|
390
319
|
|
|
391
|
-
nearestPoint(point:
|
|
320
|
+
nearestPoint(point: Vec, filters?: Geometry2dFilters): Vec {
|
|
392
321
|
return Mat.applyToPoint(
|
|
393
322
|
this.matrix,
|
|
394
323
|
this.geometry.nearestPoint(Mat.applyToPoint(this.inverse, point), filters)
|
|
@@ -396,7 +325,7 @@ export class TransformedGeometry2d extends Geometry2d {
|
|
|
396
325
|
}
|
|
397
326
|
|
|
398
327
|
override hitTestPoint(
|
|
399
|
-
point:
|
|
328
|
+
point: Vec,
|
|
400
329
|
margin = 0,
|
|
401
330
|
hitInside?: boolean,
|
|
402
331
|
filters?: Geometry2dFilters
|
|
@@ -409,14 +338,14 @@ export class TransformedGeometry2d extends Geometry2d {
|
|
|
409
338
|
)
|
|
410
339
|
}
|
|
411
340
|
|
|
412
|
-
override distanceToPoint(point:
|
|
341
|
+
override distanceToPoint(point: Vec, hitInside = false, filters?: Geometry2dFilters) {
|
|
413
342
|
return (
|
|
414
343
|
this.geometry.distanceToPoint(Mat.applyToPoint(this.inverse, point), hitInside, filters) *
|
|
415
344
|
this.decomposed.scaleX
|
|
416
345
|
)
|
|
417
346
|
}
|
|
418
347
|
|
|
419
|
-
override distanceToLineSegment(A:
|
|
348
|
+
override distanceToLineSegment(A: Vec, B: Vec, filters?: Geometry2dFilters) {
|
|
420
349
|
return (
|
|
421
350
|
this.geometry.distanceToLineSegment(
|
|
422
351
|
Mat.applyToPoint(this.inverse, A),
|
|
@@ -426,12 +355,7 @@ export class TransformedGeometry2d extends Geometry2d {
|
|
|
426
355
|
)
|
|
427
356
|
}
|
|
428
357
|
|
|
429
|
-
override hitTestLineSegment(
|
|
430
|
-
A: VecLike,
|
|
431
|
-
B: VecLike,
|
|
432
|
-
distance = 0,
|
|
433
|
-
filters?: Geometry2dFilters
|
|
434
|
-
): boolean {
|
|
358
|
+
override hitTestLineSegment(A: Vec, B: Vec, distance = 0, filters?: Geometry2dFilters): boolean {
|
|
435
359
|
return this.geometry.hitTestLineSegment(
|
|
436
360
|
Mat.applyToPoint(this.inverse, A),
|
|
437
361
|
Mat.applyToPoint(this.inverse, B),
|
|
@@ -441,39 +365,27 @@ export class TransformedGeometry2d extends Geometry2d {
|
|
|
441
365
|
}
|
|
442
366
|
|
|
443
367
|
override intersectLineSegment(A: VecLike, B: VecLike, filters?: Geometry2dFilters) {
|
|
444
|
-
return
|
|
445
|
-
this.
|
|
446
|
-
this.
|
|
447
|
-
|
|
448
|
-
Mat.applyToPoint(this.inverse, B),
|
|
449
|
-
filters
|
|
450
|
-
)
|
|
368
|
+
return this.geometry.intersectLineSegment(
|
|
369
|
+
Mat.applyToPoint(this.inverse, A),
|
|
370
|
+
Mat.applyToPoint(this.inverse, B),
|
|
371
|
+
filters
|
|
451
372
|
)
|
|
452
373
|
}
|
|
453
374
|
|
|
454
375
|
override intersectCircle(center: VecLike, radius: number, filters?: Geometry2dFilters) {
|
|
455
|
-
return
|
|
456
|
-
this.
|
|
457
|
-
this.
|
|
458
|
-
|
|
459
|
-
radius / this.decomposed.scaleX,
|
|
460
|
-
filters
|
|
461
|
-
)
|
|
376
|
+
return this.geometry.intersectCircle(
|
|
377
|
+
Mat.applyToPoint(this.inverse, center),
|
|
378
|
+
radius / this.decomposed.scaleX,
|
|
379
|
+
filters
|
|
462
380
|
)
|
|
463
381
|
}
|
|
464
382
|
|
|
465
383
|
override intersectPolygon(polygon: VecLike[], filters?: Geometry2dFilters): VecLike[] {
|
|
466
|
-
return Mat.applyToPoints(
|
|
467
|
-
this.matrix,
|
|
468
|
-
this.geometry.intersectPolygon(Mat.applyToPoints(this.inverse, polygon), filters)
|
|
469
|
-
)
|
|
384
|
+
return this.geometry.intersectPolygon(Mat.applyToPoints(this.inverse, polygon), filters)
|
|
470
385
|
}
|
|
471
386
|
|
|
472
387
|
override intersectPolyline(polyline: VecLike[], filters?: Geometry2dFilters): VecLike[] {
|
|
473
|
-
return Mat.applyToPoints(
|
|
474
|
-
this.matrix,
|
|
475
|
-
this.geometry.intersectPolyline(Mat.applyToPoints(this.inverse, polyline), filters)
|
|
476
|
-
)
|
|
388
|
+
return this.geometry.intersectPolyline(Mat.applyToPoints(this.inverse, polyline), filters)
|
|
477
389
|
}
|
|
478
390
|
|
|
479
391
|
override transform(transform: MatModel, opts?: TransformedGeometry2dOptions): Geometry2d {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { EMPTY_ARRAY } from '@tldraw/state'
|
|
2
|
-
import { assert, invLerp, lerp } from '@tldraw/utils'
|
|
3
2
|
import { Box } from '../Box'
|
|
4
3
|
import { Mat } from '../Mat'
|
|
5
4
|
import { Vec, VecLike } from '../Vec'
|
|
@@ -35,7 +34,7 @@ export class Group2d extends Geometry2d {
|
|
|
35
34
|
.flatMap((c) => c.getVertices(filters))
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
override nearestPoint(point:
|
|
37
|
+
override nearestPoint(point: Vec, filters?: Geometry2dFilters): Vec {
|
|
39
38
|
let dist = Infinity
|
|
40
39
|
let nearest: Vec | undefined
|
|
41
40
|
|
|
@@ -60,7 +59,7 @@ export class Group2d extends Geometry2d {
|
|
|
60
59
|
return nearest
|
|
61
60
|
}
|
|
62
61
|
|
|
63
|
-
override distanceToPoint(point:
|
|
62
|
+
override distanceToPoint(point: Vec, hitInside = false, filters?: Geometry2dFilters) {
|
|
64
63
|
let smallestDistance = Infinity
|
|
65
64
|
for (const child of this.children) {
|
|
66
65
|
if (child.isExcludedByFilter(filters)) continue
|
|
@@ -73,7 +72,7 @@ export class Group2d extends Geometry2d {
|
|
|
73
72
|
}
|
|
74
73
|
|
|
75
74
|
override hitTestPoint(
|
|
76
|
-
point:
|
|
75
|
+
point: Vec,
|
|
77
76
|
margin: number,
|
|
78
77
|
hitInside: boolean,
|
|
79
78
|
filters = Geometry2dFilters.EXCLUDE_LABELS
|
|
@@ -84,8 +83,8 @@ export class Group2d extends Geometry2d {
|
|
|
84
83
|
}
|
|
85
84
|
|
|
86
85
|
override hitTestLineSegment(
|
|
87
|
-
A:
|
|
88
|
-
B:
|
|
86
|
+
A: Vec,
|
|
87
|
+
B: Vec,
|
|
89
88
|
zoom: number,
|
|
90
89
|
filters = Geometry2dFilters.EXCLUDE_LABELS
|
|
91
90
|
): boolean {
|
|
@@ -122,63 +121,6 @@ export class Group2d extends Geometry2d {
|
|
|
122
121
|
})
|
|
123
122
|
}
|
|
124
123
|
|
|
125
|
-
override interpolateAlongEdge(t: number, filters?: Geometry2dFilters): Vec {
|
|
126
|
-
const totalLength = this.getLength(filters)
|
|
127
|
-
|
|
128
|
-
const distanceToTravel = t * totalLength
|
|
129
|
-
let distanceTraveled = 0
|
|
130
|
-
for (const child of this.children) {
|
|
131
|
-
if (child.isExcludedByFilter(filters)) continue
|
|
132
|
-
const childLength = child.length
|
|
133
|
-
const newDistanceTraveled = distanceTraveled + childLength
|
|
134
|
-
if (newDistanceTraveled >= distanceToTravel) {
|
|
135
|
-
return child.interpolateAlongEdge(
|
|
136
|
-
invLerp(distanceTraveled, newDistanceTraveled, distanceToTravel),
|
|
137
|
-
filters
|
|
138
|
-
)
|
|
139
|
-
}
|
|
140
|
-
distanceTraveled = newDistanceTraveled
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return this.children[this.children.length - 1].interpolateAlongEdge(1, filters)
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
override uninterpolateAlongEdge(point: VecLike, filters?: Geometry2dFilters): number {
|
|
147
|
-
const totalLength = this.getLength(filters)
|
|
148
|
-
|
|
149
|
-
let closestChild = null
|
|
150
|
-
let closestDistance = Infinity
|
|
151
|
-
let distanceTraveled = 0
|
|
152
|
-
|
|
153
|
-
for (const child of this.children) {
|
|
154
|
-
if (child.isExcludedByFilter(filters)) continue
|
|
155
|
-
const childLength = child.getLength(filters)
|
|
156
|
-
const newDistanceTraveled = distanceTraveled + childLength
|
|
157
|
-
|
|
158
|
-
const distance = child.distanceToPoint(point, false, filters)
|
|
159
|
-
if (distance < closestDistance) {
|
|
160
|
-
closestDistance = distance
|
|
161
|
-
closestChild = {
|
|
162
|
-
startLength: distanceTraveled,
|
|
163
|
-
endLength: newDistanceTraveled,
|
|
164
|
-
child,
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
distanceTraveled = newDistanceTraveled
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
assert(closestChild)
|
|
172
|
-
|
|
173
|
-
const normalizedDistanceInChild = closestChild.child.uninterpolateAlongEdge(point, filters)
|
|
174
|
-
const childTLength = lerp(
|
|
175
|
-
closestChild.startLength,
|
|
176
|
-
closestChild.endLength,
|
|
177
|
-
normalizedDistanceInChild
|
|
178
|
-
)
|
|
179
|
-
return childTLength / totalLength
|
|
180
|
-
}
|
|
181
|
-
|
|
182
124
|
override transform(transform: Mat): Geometry2d {
|
|
183
125
|
return new Group2d({
|
|
184
126
|
children: this.children.map((c) => c.transform(transform)),
|
|
@@ -218,13 +160,8 @@ export class Group2d extends Geometry2d {
|
|
|
218
160
|
return path
|
|
219
161
|
}
|
|
220
162
|
|
|
221
|
-
getLength(
|
|
222
|
-
|
|
223
|
-
for (const child of this.children) {
|
|
224
|
-
if (child.isExcludedByFilter(filters)) continue
|
|
225
|
-
length += child.length
|
|
226
|
-
}
|
|
227
|
-
return length
|
|
163
|
+
getLength(): number {
|
|
164
|
+
return this.children.reduce((a, c) => (c.isLabel ? a : a + c.length), 0)
|
|
228
165
|
}
|
|
229
166
|
|
|
230
167
|
getSvgPathData(): string {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Vec
|
|
1
|
+
import { Vec } from '../Vec'
|
|
2
2
|
import { Geometry2d, Geometry2dOptions } from './Geometry2d'
|
|
3
3
|
|
|
4
4
|
/** @public */
|
|
@@ -22,7 +22,7 @@ export class Point2d extends Geometry2d {
|
|
|
22
22
|
return this.point
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
hitTestLineSegment(A:
|
|
25
|
+
hitTestLineSegment(A: Vec, B: Vec, margin: number): boolean {
|
|
26
26
|
return Vec.DistanceToLineSegment(A, B, this.point) < margin
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Vec
|
|
1
|
+
import { Vec } from '../Vec'
|
|
2
2
|
import { Edge2d } from './Edge2d'
|
|
3
3
|
import { Geometry2d, Geometry2dOptions } from './Geometry2d'
|
|
4
4
|
|
|
@@ -41,7 +41,7 @@ export class Polyline2d extends Geometry2d {
|
|
|
41
41
|
return this.points
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
nearestPoint(A:
|
|
44
|
+
nearestPoint(A: Vec): Vec {
|
|
45
45
|
const { segments } = this
|
|
46
46
|
let nearest = this.points[0]
|
|
47
47
|
let dist = Infinity
|
|
@@ -59,7 +59,7 @@ export class Polyline2d extends Geometry2d {
|
|
|
59
59
|
return nearest
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
hitTestLineSegment(A:
|
|
62
|
+
hitTestLineSegment(A: Vec, B: Vec, distance = 0): boolean {
|
|
63
63
|
const { segments } = this
|
|
64
64
|
for (let i = 0, n = segments.length; i < n; i++) {
|
|
65
65
|
if (segments[i].hitTestLineSegment(A, B, distance)) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Box } from '../Box'
|
|
2
|
-
import { Vec
|
|
2
|
+
import { Vec } from '../Vec'
|
|
3
3
|
import { PI } from '../utils'
|
|
4
4
|
import { Arc2d } from './Arc2d'
|
|
5
5
|
import { Edge2d } from './Edge2d'
|
|
@@ -65,7 +65,7 @@ export class Stadium2d extends Geometry2d {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
nearestPoint(A:
|
|
68
|
+
nearestPoint(A: Vec): Vec {
|
|
69
69
|
let nearest: Vec | undefined
|
|
70
70
|
let dist = Infinity
|
|
71
71
|
let _d: number
|
|
@@ -84,7 +84,7 @@ export class Stadium2d extends Geometry2d {
|
|
|
84
84
|
return nearest
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
hitTestLineSegment(A:
|
|
87
|
+
hitTestLineSegment(A: Vec, B: Vec): boolean {
|
|
88
88
|
const { a, b, c, d } = this
|
|
89
89
|
return [a, b, c, d].some((edge) => edge.hitTestLineSegment(A, B))
|
|
90
90
|
}
|
|
@@ -54,7 +54,6 @@ export const debugFlags = {
|
|
|
54
54
|
hideShapes: createDebugValue('hideShapes', { defaults: { all: false } }),
|
|
55
55
|
editOnType: createDebugValue('editOnType', { defaults: { all: false } }),
|
|
56
56
|
a11y: createDebugValue('a11y', { defaults: { all: false } }),
|
|
57
|
-
debugElbowArrows: createDebugValue('debugElbowArrows', { defaults: { all: false } }),
|
|
58
57
|
} as const
|
|
59
58
|
|
|
60
59
|
declare global {
|
|
@@ -150,9 +149,7 @@ function createDebugValueBase<T>(def: DebugFlagDef<T>): DebugFlag<T> {
|
|
|
150
149
|
})
|
|
151
150
|
}
|
|
152
151
|
|
|
153
|
-
return Object.assign(valueAtom, def
|
|
154
|
-
reset: () => valueAtom.set(defaultValue),
|
|
155
|
-
})
|
|
152
|
+
return Object.assign(valueAtom, def)
|
|
156
153
|
}
|
|
157
154
|
|
|
158
155
|
function getStoredInitialValue(name: string) {
|
|
@@ -209,6 +206,4 @@ export interface DebugFlagDef<T> {
|
|
|
209
206
|
}
|
|
210
207
|
|
|
211
208
|
/** @internal */
|
|
212
|
-
export
|
|
213
|
-
reset(): void
|
|
214
|
-
}
|
|
209
|
+
export type DebugFlag<T> = DebugFlagDef<T> & Atom<T>
|
|
@@ -3,7 +3,7 @@ import { openDB } from 'idb'
|
|
|
3
3
|
import { hardReset } from './hardReset'
|
|
4
4
|
import { getAllIndexDbNames, LocalIndexedDb } from './LocalIndexedDb'
|
|
5
5
|
|
|
6
|
-
const schema = createTLSchema({ shapes: {}
|
|
6
|
+
const schema = createTLSchema({ shapes: {} })
|
|
7
7
|
describe('LocalIndexedDb', () => {
|
|
8
8
|
beforeEach(() => {
|
|
9
9
|
jest.useRealTimers()
|