@design-core/core 0.0.4 → 0.0.5
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/core/entities/arc.js +39 -22
- package/core/entities/arctext.js +6 -4
- package/core/entities/basePolyline.js +26 -18
- package/core/entities/circle.js +33 -15
- package/core/entities/entity.js +1 -1
- package/core/entities/hatch.js +2 -0
- package/core/entities/insert.js +9 -3
- package/core/entities/line.js +16 -11
- package/core/entities/lwpolyline.js +2 -0
- package/core/entities/point.js +3 -1
- package/core/entities/polyline.js +2 -0
- package/core/entities/rectangle.js +2 -0
- package/core/entities/solid.js +2 -0
- package/core/entities/text.js +5 -8
- package/core/lib/input.js +8 -4
- package/core/lib/inputManager.js +2 -3
- package/core/lib/selectionManager.js +4 -0
- package/core/lib/settings.js +9 -5
- package/core/lib/snapping.js +112 -17
- package/core/tables/block.js +2 -0
- package/core/tools/chamfer.js +2 -0
- package/core/tools/chamferFilletBase.js +2 -0
- package/core/tools/copy.js +2 -0
- package/core/tools/copybase.js +2 -0
- package/core/tools/copyclip.js +2 -0
- package/core/tools/cutclip.js +2 -0
- package/core/tools/distance.js +2 -0
- package/core/tools/erase.js +2 -0
- package/core/tools/explode.js +2 -0
- package/core/tools/extend.js +2 -0
- package/core/tools/fillet.js +2 -0
- package/core/tools/identify.js +2 -0
- package/core/tools/matchProp.js +2 -0
- package/core/tools/mirror.js +2 -0
- package/core/tools/move.js +2 -0
- package/core/tools/offset.js +2 -0
- package/core/tools/pan.js +2 -0
- package/core/tools/pasteclip.js +2 -0
- package/core/tools/purge.js +2 -0
- package/core/tools/rotate.js +2 -0
- package/core/tools/scale.js +2 -0
- package/core/tools/tool.js +1 -1
- package/core/tools/trim.js +2 -0
- package/core/tools/zoom.js +2 -0
- package/package.json +1 -1
- package/test/entities/arc.test.js +60 -11
- package/test/entities/arctext.test.js +18 -2
- package/test/entities/circle.test.js +48 -22
- package/test/entities/insert.test.js +14 -4
- package/test/entities/line.test.js +53 -0
- package/test/entities/text.test.js +10 -1
- package/test/lib/input.test.js +117 -0
- package/test/lib/settings.test.js +5 -7
- package/test/lib/snapping.test.js +218 -12
package/core/lib/snapping.js
CHANGED
|
@@ -6,13 +6,27 @@ import { Utils } from './utils.js';
|
|
|
6
6
|
import { DesignCore } from '../designCore.js';
|
|
7
7
|
|
|
8
8
|
/** SnapPoint Class */
|
|
9
|
-
class SnapPoint {
|
|
9
|
+
export class SnapPoint {
|
|
10
|
+
static Type = Object.freeze({
|
|
11
|
+
NONE: 'none',
|
|
12
|
+
END: 'end',
|
|
13
|
+
MID: 'mid',
|
|
14
|
+
CENTRE: 'centre',
|
|
15
|
+
QUADRANT: 'quadrant',
|
|
16
|
+
NEAREST: 'nearest',
|
|
17
|
+
TANGENT: 'tangent',
|
|
18
|
+
NODE: 'node',
|
|
19
|
+
PERPENDICULAR: 'perpendicular',
|
|
20
|
+
});
|
|
21
|
+
|
|
10
22
|
/**
|
|
11
23
|
* Create SnapPoint
|
|
12
24
|
* @param {Point} snapPoint
|
|
25
|
+
* @param {string} type - snap type from SnapPoint.Type
|
|
13
26
|
*/
|
|
14
|
-
constructor(snapPoint) {
|
|
27
|
+
constructor(snapPoint, type = SnapPoint.Type.END) {
|
|
15
28
|
this.snapPoint = snapPoint;
|
|
29
|
+
this.type = type;
|
|
16
30
|
}
|
|
17
31
|
|
|
18
32
|
/**
|
|
@@ -21,19 +35,74 @@ class SnapPoint {
|
|
|
21
35
|
* @param {number} scale
|
|
22
36
|
*/
|
|
23
37
|
draw(ctx, scale) {
|
|
24
|
-
const snapColour = DesignCore.Settings.
|
|
25
|
-
const
|
|
38
|
+
const snapColour = DesignCore.Settings.snaptrackingcolour;
|
|
39
|
+
const size = 6 / scale;
|
|
40
|
+
const x = this.snapPoint.x;
|
|
41
|
+
const y = this.snapPoint.y;
|
|
42
|
+
const lineWidth = 2.5 / scale;
|
|
26
43
|
|
|
27
44
|
try { // HTML Canvas
|
|
28
|
-
ctx.
|
|
45
|
+
ctx.strokeStyle = Colours.rgbToString(snapColour);
|
|
46
|
+
ctx.lineWidth = lineWidth;
|
|
47
|
+
ctx.setLineDash([]);
|
|
29
48
|
ctx.beginPath();
|
|
30
49
|
} catch { // Cairo
|
|
31
50
|
const rgbColour = Colours.rgbToScaledRGB(snapColour);
|
|
32
51
|
ctx.setSourceRGB(rgbColour.r, rgbColour.g, rgbColour.b);
|
|
52
|
+
ctx.setLineWidth(lineWidth);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
switch (this.type) {
|
|
56
|
+
case SnapPoint.Type.END: // square
|
|
57
|
+
ctx.moveTo(x - size, y - size);
|
|
58
|
+
ctx.lineTo(x + size, y - size);
|
|
59
|
+
ctx.lineTo(x + size, y + size);
|
|
60
|
+
ctx.lineTo(x - size, y + size);
|
|
61
|
+
ctx.closePath();
|
|
62
|
+
break;
|
|
63
|
+
case SnapPoint.Type.MID: // triangle
|
|
64
|
+
ctx.moveTo(x, y + size);
|
|
65
|
+
ctx.lineTo(x - size, y - size);
|
|
66
|
+
ctx.lineTo(x + size, y - size);
|
|
67
|
+
ctx.closePath();
|
|
68
|
+
break;
|
|
69
|
+
case SnapPoint.Type.QUADRANT: // diamond
|
|
70
|
+
ctx.moveTo(x, y - size);
|
|
71
|
+
ctx.lineTo(x + size, y);
|
|
72
|
+
ctx.lineTo(x, y + size);
|
|
73
|
+
ctx.lineTo(x - size, y);
|
|
74
|
+
ctx.closePath();
|
|
75
|
+
break;
|
|
76
|
+
case SnapPoint.Type.NEAREST: // hourglass (X with horizontal lines at top and bottom)
|
|
77
|
+
ctx.moveTo(x - size, y - size);
|
|
78
|
+
ctx.lineTo(x + size, y - size);
|
|
79
|
+
ctx.lineTo(x - size, y + size);
|
|
80
|
+
ctx.lineTo(x + size, y + size);
|
|
81
|
+
ctx.closePath();
|
|
82
|
+
break;
|
|
83
|
+
case SnapPoint.Type.TANGENT: // circle with a horizontal line over the top
|
|
84
|
+
ctx.arc(x, y, size, 0, 6.283);
|
|
85
|
+
ctx.moveTo(x - size, y + size * 1.5);
|
|
86
|
+
ctx.lineTo(x + size, y + size * 1.5);
|
|
87
|
+
break;
|
|
88
|
+
case SnapPoint.Type.NODE: // circle with an X inside
|
|
89
|
+
ctx.arc(x, y, size, 0, 6.283);
|
|
90
|
+
ctx.moveTo(x - size * 0.7, y - size * 0.7);
|
|
91
|
+
ctx.lineTo(x + size * 0.7, y + size * 0.7);
|
|
92
|
+
ctx.moveTo(x + size * 0.7, y - size * 0.7);
|
|
93
|
+
ctx.lineTo(x - size * 0.7, y + size * 0.7);
|
|
94
|
+
break;
|
|
95
|
+
case SnapPoint.Type.PERPENDICULAR: // right-angle corner (L-shape)
|
|
96
|
+
ctx.moveTo(x - size, y + size);
|
|
97
|
+
ctx.lineTo(x - size, y - size);
|
|
98
|
+
ctx.lineTo(x + size, y - size);
|
|
99
|
+
break;
|
|
100
|
+
default: // CENTRE - circle
|
|
101
|
+
ctx.arc(x, y, size, 0, 6.283);
|
|
102
|
+
break;
|
|
33
103
|
}
|
|
34
104
|
|
|
35
|
-
ctx.
|
|
36
|
-
ctx.fill();
|
|
105
|
+
ctx.stroke();
|
|
37
106
|
}
|
|
38
107
|
}
|
|
39
108
|
|
|
@@ -57,6 +126,7 @@ class TrackingLine {
|
|
|
57
126
|
draw(ctx, scale) {
|
|
58
127
|
const from = this.inputPoint;
|
|
59
128
|
const dir = this.snapPoint.subtract(from);
|
|
129
|
+
const lineWidth = 2 / scale;
|
|
60
130
|
|
|
61
131
|
if (dir.x === 0 && dir.y === 0) {
|
|
62
132
|
return;
|
|
@@ -99,7 +169,7 @@ class TrackingLine {
|
|
|
99
169
|
const start = from.add(dir.scale(tMin));
|
|
100
170
|
const end = from.add(dir.scale(tMax));
|
|
101
171
|
|
|
102
|
-
const lineColour = DesignCore.Settings.
|
|
172
|
+
const lineColour = DesignCore.Settings.snaptrackingcolour;
|
|
103
173
|
const dashSize = 4 / scale;
|
|
104
174
|
|
|
105
175
|
ctx.save();
|
|
@@ -107,12 +177,12 @@ class TrackingLine {
|
|
|
107
177
|
try { // HTML Canvas
|
|
108
178
|
ctx.beginPath();
|
|
109
179
|
ctx.strokeStyle = Colours.rgbToString(lineColour);
|
|
110
|
-
ctx.lineWidth =
|
|
180
|
+
ctx.lineWidth = lineWidth;
|
|
111
181
|
ctx.setLineDash([dashSize, dashSize]);
|
|
112
182
|
} catch { // Cairo
|
|
113
183
|
const rgbColour = Colours.rgbToScaledRGB(lineColour);
|
|
114
184
|
ctx.setSourceRGB(rgbColour.r, rgbColour.g, rgbColour.b);
|
|
115
|
-
ctx.setLineWidth(
|
|
185
|
+
ctx.setLineWidth(lineWidth);
|
|
116
186
|
ctx.setDash([dashSize, dashSize], 0);
|
|
117
187
|
}
|
|
118
188
|
|
|
@@ -128,9 +198,32 @@ class TrackingLine {
|
|
|
128
198
|
export class Snapping {
|
|
129
199
|
/** Create snapping */
|
|
130
200
|
constructor() {
|
|
201
|
+
// active is true when snapping is active (e.g. during a command)
|
|
202
|
+
this.active = false;
|
|
203
|
+
// snapOverride: null = use settings; SnapPoint.Type.NONE = suppress all snaps; any other type = snap only to that type
|
|
204
|
+
this.snapOverride = null;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Reset snapping state
|
|
209
|
+
*/
|
|
210
|
+
reset() {
|
|
131
211
|
this.active = false;
|
|
212
|
+
this.snapOverride = null;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Set the snap override type
|
|
217
|
+
* @param {string|null} type - a SnapPoint.Type value, or null to clear the override
|
|
218
|
+
*/
|
|
219
|
+
setSnapOverride(type) {
|
|
220
|
+
if (type !== null && !Object.values(SnapPoint.Type).includes(type)) {
|
|
221
|
+
throw new Error(`Invalid snap override type: ${type}`);
|
|
222
|
+
}
|
|
223
|
+
this.snapOverride = type;
|
|
132
224
|
}
|
|
133
225
|
|
|
226
|
+
|
|
134
227
|
/**
|
|
135
228
|
* Get snap point and draw to the scene
|
|
136
229
|
* @return {Point} or undefined
|
|
@@ -149,14 +242,14 @@ export class Snapping {
|
|
|
149
242
|
|
|
150
243
|
/**
|
|
151
244
|
* Draw the snap point
|
|
152
|
-
* @param {
|
|
245
|
+
* @param {SnapPoint} snapPoint
|
|
153
246
|
*/
|
|
154
247
|
addSnapPoint(snapPoint) {
|
|
155
248
|
// show the snap point
|
|
156
|
-
DesignCore.Scene.auxiliaryEntities.add(
|
|
249
|
+
DesignCore.Scene.auxiliaryEntities.add(snapPoint);
|
|
157
250
|
|
|
158
251
|
// Move the mouse to the closest snap point so if the mouse if clicked the snap point is used.
|
|
159
|
-
DesignCore.Mouse.setPosFromScenePoint(snapPoint);
|
|
252
|
+
DesignCore.Mouse.setPosFromScenePoint(snapPoint.snapPoint);
|
|
160
253
|
}
|
|
161
254
|
|
|
162
255
|
/**
|
|
@@ -174,7 +267,8 @@ export class Snapping {
|
|
|
174
267
|
*/
|
|
175
268
|
getSnapPoint() {
|
|
176
269
|
let snapPoint;
|
|
177
|
-
|
|
270
|
+
const snapAperture = 25; // capture radius in pixels (screen space)
|
|
271
|
+
let delta = snapAperture / DesignCore.Canvas.getScale(); // convert to scene space
|
|
178
272
|
|
|
179
273
|
for (let i = 0; i < DesignCore.Scene.entities.count(); i++) {
|
|
180
274
|
const layer = DesignCore.LayerManager.getItemByName(DesignCore.Scene.entities.get(i).layer);
|
|
@@ -185,11 +279,12 @@ export class Snapping {
|
|
|
185
279
|
|
|
186
280
|
const itemSnaps = DesignCore.Scene.entities.get(i).snaps(DesignCore.Mouse.pointOnScene(), delta); // get an array of snap point from the item
|
|
187
281
|
if (itemSnaps) {
|
|
188
|
-
|
|
189
|
-
|
|
282
|
+
const filteredSnaps = this.snapOverride !== null ? itemSnaps.filter((s) => s.type === this.snapOverride) : itemSnaps.filter((s) => DesignCore.Settings[`${s.type}snap`]);
|
|
283
|
+
for (let j = 0; j < filteredSnaps.length; j++) {
|
|
284
|
+
const length = filteredSnaps[j].snapPoint.distance(DesignCore.Mouse.pointOnScene());
|
|
190
285
|
if (length < delta) {
|
|
191
286
|
delta = length;
|
|
192
|
-
snapPoint =
|
|
287
|
+
snapPoint = filteredSnaps[j];
|
|
193
288
|
}
|
|
194
289
|
}
|
|
195
290
|
}
|
package/core/tables/block.js
CHANGED
package/core/tools/chamfer.js
CHANGED
package/core/tools/copy.js
CHANGED
package/core/tools/copybase.js
CHANGED
package/core/tools/copyclip.js
CHANGED
package/core/tools/cutclip.js
CHANGED
package/core/tools/distance.js
CHANGED
package/core/tools/erase.js
CHANGED
package/core/tools/explode.js
CHANGED
package/core/tools/extend.js
CHANGED
package/core/tools/fillet.js
CHANGED
package/core/tools/identify.js
CHANGED
package/core/tools/matchProp.js
CHANGED
package/core/tools/mirror.js
CHANGED
package/core/tools/move.js
CHANGED
package/core/tools/offset.js
CHANGED
package/core/tools/pan.js
CHANGED
package/core/tools/pasteclip.js
CHANGED
package/core/tools/purge.js
CHANGED
package/core/tools/rotate.js
CHANGED
package/core/tools/scale.js
CHANGED
package/core/tools/tool.js
CHANGED
package/core/tools/trim.js
CHANGED
package/core/tools/zoom.js
CHANGED
package/package.json
CHANGED
|
@@ -434,22 +434,16 @@ test('Arc.draw does not throw (ccw and cw)', () => {
|
|
|
434
434
|
expect(() => arcCw.draw(ctx2, 1)).not.toThrow();
|
|
435
435
|
});
|
|
436
436
|
|
|
437
|
-
test('Arc.snaps returns end
|
|
437
|
+
test('Arc.snaps returns end and centre snap points', () => {
|
|
438
438
|
const arc = new Arc({ points: [new Point(0, 0), new Point(10, 0), new Point(0, 10)], direction: 1 });
|
|
439
439
|
|
|
440
|
-
DesignCore.Settings.endsnap = true;
|
|
441
|
-
DesignCore.Settings.centresnap = true;
|
|
442
|
-
DesignCore.Settings.nearestsnap = false;
|
|
443
440
|
const snaps = arc.snaps(new Point(5, 5), 10);
|
|
444
|
-
expect(snaps.length).toBe(
|
|
441
|
+
expect(snaps.filter((s) => s.type === 'end').length).toBe(2);
|
|
442
|
+
expect(snaps.filter((s) => s.type === 'centre').length).toBe(1);
|
|
445
443
|
|
|
446
|
-
//
|
|
447
|
-
// so closest[2] === true is never satisfied and no snap is pushed
|
|
448
|
-
DesignCore.Settings.endsnap = false;
|
|
449
|
-
DesignCore.Settings.centresnap = false;
|
|
450
|
-
DesignCore.Settings.nearestsnap = true;
|
|
444
|
+
// Arc.snaps nearest fires when mouse is on the arc surface
|
|
451
445
|
const nearSnaps = arc.snaps(new Point(10, 0), 100);
|
|
452
|
-
expect(nearSnaps.length).toBe(
|
|
446
|
+
expect(nearSnaps.filter((s) => s.type === 'nearest').length).toBe(1);
|
|
453
447
|
});
|
|
454
448
|
|
|
455
449
|
test('Arc.execute handles negative angle (clockwise)', async () => {
|
|
@@ -505,3 +499,58 @@ test('Arc.fromPolylinePoints precision drift is negligible', () => {
|
|
|
505
499
|
expect(Math.abs(rebuilt.radius - arc.radius)).toBeLessThan(1e-10);
|
|
506
500
|
});
|
|
507
501
|
|
|
502
|
+
test('Arc.snaps nearest does not fire when mouse is too far from arc', () => {
|
|
503
|
+
const arc = new Arc({ points: [new Point(0, 0), new Point(10, 0), new Point(0, 10)], direction: 1 });
|
|
504
|
+
// Mouse far from arc surface; delta=1 so delta/10=0.1 — distance >> threshold
|
|
505
|
+
const snaps = arc.snaps(new Point(100, 100), 1);
|
|
506
|
+
expect(snaps.filter((s) => s.type === 'nearest').length).toBe(0);
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
test('Arc.snaps returns tangent snap when fromPoint is outside the arc', () => {
|
|
510
|
+
const arc = new Arc({ points: [new Point(0, 0), new Point(10, 0), new Point(0, 10)], direction: 1 });
|
|
511
|
+
const savedInputPoint = DesignCore.Scene.inputManager.inputPoint;
|
|
512
|
+
// fromPoint=(20,0): distanceToCenter=20 > radius=10
|
|
513
|
+
// tangentHalfAngle = acos(10/20) = π/3 (60°)
|
|
514
|
+
// tangentPoint at angle 0+60°=(5, 8.66) IS on CCW arc from 0° to 90°
|
|
515
|
+
// tangentPoint at angle 0-60°=(5,-8.66) is NOT on the arc
|
|
516
|
+
DesignCore.Scene.inputManager.inputPoint = new Point(20, 0);
|
|
517
|
+
const snaps = arc.snaps(new Point(5, 5), 100);
|
|
518
|
+
const tangentSnaps = snaps.filter((s) => s.type === 'tangent');
|
|
519
|
+
expect(tangentSnaps.length).toBe(1);
|
|
520
|
+
expect(tangentSnaps[0].snapPoint.x).toBeCloseTo(5);
|
|
521
|
+
expect(tangentSnaps[0].snapPoint.y).toBeCloseTo(8.6603, 3);
|
|
522
|
+
DesignCore.Scene.inputManager.inputPoint = savedInputPoint;
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
test('Arc.snaps returns no tangent when fromPoint is inside the arc radius', () => {
|
|
526
|
+
const arc = new Arc({ points: [new Point(0, 0), new Point(10, 0), new Point(0, 10)], direction: 1 });
|
|
527
|
+
const savedInputPoint = DesignCore.Scene.inputManager.inputPoint;
|
|
528
|
+
DesignCore.Scene.inputManager.inputPoint = new Point(1, 1); // distanceToCenter ≈ 1.41 < radius 10
|
|
529
|
+
const snaps = arc.snaps(new Point(5, 5), 100);
|
|
530
|
+
expect(snaps.filter((s) => s.type === 'tangent').length).toBe(0);
|
|
531
|
+
DesignCore.Scene.inputManager.inputPoint = savedInputPoint;
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
test('Arc.snaps returns perpendicular snap when radial point is on the arc', () => {
|
|
535
|
+
const arc = new Arc({ points: [new Point(0, 0), new Point(10, 0), new Point(0, 10)], direction: 1 });
|
|
536
|
+
const savedInputPoint = DesignCore.Scene.inputManager.inputPoint;
|
|
537
|
+
// fromPoint=(20,0): angleFromCentreToInput=0; perpendicularPoint=(10,0) IS on CCW arc
|
|
538
|
+
DesignCore.Scene.inputManager.inputPoint = new Point(20, 0);
|
|
539
|
+
const snaps = arc.snaps(new Point(5, 5), 100);
|
|
540
|
+
const perpSnaps = snaps.filter((s) => s.type === 'perpendicular');
|
|
541
|
+
expect(perpSnaps.length).toBe(1);
|
|
542
|
+
expect(perpSnaps[0].snapPoint.x).toBeCloseTo(10);
|
|
543
|
+
expect(perpSnaps[0].snapPoint.y).toBeCloseTo(0);
|
|
544
|
+
DesignCore.Scene.inputManager.inputPoint = savedInputPoint;
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
test('Arc.snaps returns no perpendicular when radial point is not on the arc', () => {
|
|
548
|
+
const arc = new Arc({ points: [new Point(0, 0), new Point(10, 0), new Point(0, 10)], direction: 1 });
|
|
549
|
+
const savedInputPoint = DesignCore.Scene.inputManager.inputPoint;
|
|
550
|
+
// fromPoint=(0,-20): angleFromCentreToInput=-π/2; perpendicularPoint=(0,-10) NOT on CCW arc from 0° to 90°
|
|
551
|
+
DesignCore.Scene.inputManager.inputPoint = new Point(0, -20);
|
|
552
|
+
const snaps = arc.snaps(new Point(5, 5), 100);
|
|
553
|
+
expect(snaps.filter((s) => s.type === 'perpendicular').length).toBe(0);
|
|
554
|
+
DesignCore.Scene.inputManager.inputPoint = savedInputPoint;
|
|
555
|
+
});
|
|
556
|
+
|
|
@@ -300,8 +300,9 @@ test('Test ArcText.snaps', () => {
|
|
|
300
300
|
const arcText = new ArcAlignedText({ points: [new Point(0, 0)], string: 'Test', radius: 100 });
|
|
301
301
|
const point = new Point(100, 100);
|
|
302
302
|
const snaps = arcText.snaps(point, 1);
|
|
303
|
-
|
|
304
|
-
expect(
|
|
303
|
+
const nodeSnaps = snaps.filter((s) => s.type === 'node');
|
|
304
|
+
expect(nodeSnaps[0].snapPoint.x).toBeCloseTo(-2.39222);
|
|
305
|
+
expect(nodeSnaps[0].snapPoint.y).toBeCloseTo(101.22173);
|
|
305
306
|
});
|
|
306
307
|
|
|
307
308
|
test('Test ArcText.closestPoint', () => {
|
|
@@ -327,3 +328,18 @@ test('Test ArcText.toPolylinePoints - returns correct points array', () => {
|
|
|
327
328
|
expect(result[0].x).toBeCloseTo(-2.39222);
|
|
328
329
|
expect(result[0].y).toBeCloseTo(101.22173);
|
|
329
330
|
});
|
|
331
|
+
|
|
332
|
+
test('ArcText.snaps returns a centre snap at points[0]', () => {
|
|
333
|
+
const arcText = new ArcAlignedText({ points: [new Point(3, 7)], string: 'Hi', radius: 50 });
|
|
334
|
+
const centreSnaps = arcText.snaps(new Point(0, 0), 100).filter((s) => s.type === 'centre');
|
|
335
|
+
expect(centreSnaps.length).toBe(1);
|
|
336
|
+
expect(centreSnaps[0].snapPoint.x).toBe(3);
|
|
337
|
+
expect(centreSnaps[0].snapPoint.y).toBe(7);
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
test('ArcText.snaps returns node snaps only for non-space characters', () => {
|
|
341
|
+
// 'A B' has 3 characters: 'A', ' ', 'B' — only 'A' and 'B' produce node snaps
|
|
342
|
+
const arcText = new ArcAlignedText({ points: [new Point(0, 0)], string: 'A B', radius: 100 });
|
|
343
|
+
const nodeSnaps = arcText.snaps(new Point(0, 0), 100).filter((s) => s.type === 'node');
|
|
344
|
+
expect(nodeSnaps.length).toBe(2);
|
|
345
|
+
});
|