@design-core/core 0.0.6 → 0.0.7
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/.eslintrc.json +4 -0
- package/TODO.md +49 -6
- package/core/core/core.js +0 -3
- package/core/dimensions/alignedDimension.js +5 -4
- package/core/dimensions/angularDimension.js +6 -5
- package/core/dimensions/baseCircularDimension.js +3 -2
- package/core/dimensions/baseDimension.js +59 -93
- package/core/dimensions/baseLinearDimension.js +6 -5
- package/core/dimensions/diametricDimension.js +4 -3
- package/core/dimensions/dimension.js +21 -14
- package/core/dimensions/radialDimension.js +4 -3
- package/core/dimensions/rotatedDimension.js +12 -11
- package/core/entities/arc.js +112 -145
- package/core/entities/arctext.js +212 -174
- package/core/entities/basePolyline.js +30 -282
- package/core/entities/circle.js +77 -99
- package/core/entities/entity.js +114 -93
- package/core/entities/hatch.js +322 -249
- package/core/entities/insert.js +66 -81
- package/core/entities/line.js +21 -142
- package/core/entities/lwpolyline.js +16 -11
- package/core/entities/polyline.js +4 -4
- package/core/entities/rectangle.js +3 -1
- package/core/entities/solid.js +6 -15
- package/core/entities/text.js +188 -199
- package/core/lib/auxiliary/rubberBand.js +32 -0
- package/core/lib/auxiliary/selectionWindow.js +63 -0
- package/core/lib/auxiliary/snapPoint.js +113 -0
- package/core/lib/auxiliary/trackingLine.js +76 -0
- package/core/lib/canvas.js +228 -166
- package/core/lib/clipboard.js +7 -1
- package/core/lib/colour.js +16 -0
- package/core/lib/commandLine.js +1 -6
- package/core/lib/commandManager.js +18 -8
- package/core/lib/constants.js +28 -0
- package/core/lib/dxf/dxf.js +4 -3
- package/core/lib/entityManager.js +18 -11
- package/core/lib/inputManager.js +35 -11
- package/core/lib/intersect.js +25 -0
- package/core/lib/patterns.js +8 -1
- package/core/lib/plotOptions.js +67 -0
- package/core/lib/polylineUtils.js +75 -0
- package/core/lib/renderers/cairoRenderer.js +371 -0
- package/core/lib/renderers/canvasRenderer.js +315 -0
- package/core/lib/renderers/pdfRenderer.js +366 -0
- package/core/lib/renderers/rendererBase.js +284 -0
- package/core/lib/renderers/svgRenderer.js +343 -0
- package/core/lib/scene.js +27 -5
- package/core/lib/selectionManager.js +2 -2
- package/core/lib/settings.js +4 -2
- package/core/lib/snapping.js +4 -191
- package/core/lib/stateManager.js +30 -1
- package/core/lib/utils.js +21 -2
- package/core/properties/entityProperties.js +104 -0
- package/core/properties/property.js +106 -2
- package/core/properties/propertyManager.js +29 -13
- package/core/tables/block.js +4 -37
- package/core/tables/endblk.js +1 -1
- package/core/tables/layer.js +8 -0
- package/core/tables/styleManagerBase.js +3 -2
- package/core/tables/tableManagerBase.js +8 -3
- package/core/tools/chamfer.js +111 -137
- package/core/tools/chamferFilletBase.js +135 -34
- package/core/tools/copy.js +3 -3
- package/core/tools/explode.js +2 -2
- package/core/tools/extend.js +132 -19
- package/core/tools/fillet.js +86 -183
- package/core/tools/matchProp.js +2 -11
- package/core/tools/mirror.js +7 -6
- package/core/tools/move.js +3 -3
- package/core/tools/offset.js +3 -5
- package/core/tools/pasteclip.js +1 -1
- package/core/tools/rotate.js +6 -3
- package/core/tools/scale.js +1 -1
- package/core/tools/trim.js +265 -23
- package/core/tools/zoom.js +1 -1
- package/jest.config.js +6 -0
- package/package.json +5 -3
- package/test/dimensions/alignedDimension.test.js +14 -7
- package/test/dimensions/angularDimension.test.js +6 -6
- package/test/dimensions/baseDimension.test.js +69 -8
- package/test/dimensions/baseLinearDimension.test.js +62 -0
- package/test/dimensions/diametricDimension.test.js +6 -6
- package/test/dimensions/radialDimension.test.js +6 -6
- package/test/dimensions/rotatedDimension.test.js +14 -7
- package/test/entities/arc.test.js +80 -83
- package/test/entities/arctext.test.js +180 -53
- package/test/entities/basePolyline.test.js +68 -2
- package/test/entities/circle.test.js +57 -85
- package/test/entities/entity.test.js +42 -8
- package/test/entities/hatch.test.js +543 -70
- package/test/entities/insert.test.js +96 -1
- package/test/entities/line.test.js +15 -41
- package/test/entities/lwpolyline.test.js +104 -0
- package/test/entities/polyline.test.js +11 -0
- package/test/entities/rectangle.test.js +11 -0
- package/test/entities/solid.test.js +1 -1
- package/test/entities/text.test.js +294 -69
- package/test/integration/exportIntegration.reference.dxf +9 -9
- package/test/integration/exportIntegration.test.js +2 -2
- package/test/integration/intersectionIntegration.test.js +4 -5
- package/test/integration/pdfRendererIntegration.reference.pdf +17709 -0
- package/test/integration/pdfRendererIntegration.test.js +61 -0
- package/test/integration/svgRendererIntegration.reference.svg +3343 -0
- package/test/integration/svgRendererIntegration.test.js +61 -0
- package/test/integration/userInputIntegration.reference.dxf +1165 -105
- package/test/integration/userInputIntegration.test.js +239 -132
- package/test/lib/canvas.test.js +742 -123
- package/test/lib/constants.test.js +27 -0
- package/test/lib/entityManager.test.js +4 -4
- package/test/lib/inputManager.test.js +80 -19
- package/test/lib/intersect.test.js +83 -0
- package/test/lib/plotOptions.test.js +179 -0
- package/test/lib/rubberBand.test.js +84 -0
- package/test/lib/settings.test.js +5 -6
- package/test/lib/snapping.test.js +71 -129
- package/test/lib/stateManager.test.js +7 -7
- package/test/lib/utils.test.js +36 -2
- package/test/properties/entityProperties.test.js +132 -0
- package/test/properties/property.test.js +53 -0
- package/test/properties/propertyManager.test.js +3 -3
- package/test/renderers/canvasRenderer.test.js +317 -0
- package/test/renderers/pdfRenderer.test.js +271 -0
- package/test/renderers/rendererBase.test.js +213 -0
- package/test/renderers/svgRenderer.test.js +326 -0
- package/test/tables/block.test.js +31 -1
- package/test/tables/endblk.test.js +2 -2
- package/test/tables/layer.test.js +30 -0
- package/test/test-helpers/hatchGridRenderer.js +180 -0
- package/test/test-helpers/test-helpers.js +152 -0
- package/test/tools/chamfer.test.js +227 -5
- package/test/tools/chamferFilletBase.test.js +98 -9
- package/test/tools/copy.test.js +2 -2
- package/test/tools/explode.test.js +3 -3
- package/test/tools/extend.test.js +331 -0
- package/test/tools/fillet.test.js +181 -0
- package/test/tools/matchProp.test.js +5 -5
- package/test/tools/mirror.test.js +13 -13
- package/test/tools/offset.test.js +170 -3
- package/test/tools/pasteclip.test.js +5 -5
- package/test/tools/rotate.test.js +32 -2
- package/test/tools/scale.test.js +5 -5
- package/test/tools/trim.test.js +526 -0
- package/test/tools/zoom.test.js +7 -7
- package/core/lib/selectionWindow.js +0 -83
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jest } from '@jest/globals';
|
|
2
2
|
import { Core } from '../../core/core/core.js';
|
|
3
|
-
import { Snapping
|
|
3
|
+
import { Snapping } from '../../core/lib/snapping.js';
|
|
4
|
+
import { SnapPoint } from '../../core/lib/auxiliary/snapPoint.js';
|
|
4
5
|
import { Point } from '../../core/entities/point.js';
|
|
5
6
|
import { DesignCore } from '../../core/designCore.js';
|
|
6
7
|
|
|
@@ -69,21 +70,10 @@ test('Test SnapPoint.draw', () => {
|
|
|
69
70
|
DesignCore.Scene.auxiliaryEntities.clear();
|
|
70
71
|
snapping.addSnapPoint(new SnapPoint(new Point(0.5, 0.5), SnapPoint.Type.CENTRE));
|
|
71
72
|
const snapPointEntity = DesignCore.Scene.auxiliaryEntities.get(0);
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
beginPath: jest.fn(),
|
|
77
|
-
moveTo: jest.fn(),
|
|
78
|
-
lineTo: jest.fn(),
|
|
79
|
-
closePath: jest.fn(),
|
|
80
|
-
arc: jest.fn(),
|
|
81
|
-
stroke: jest.fn(),
|
|
82
|
-
};
|
|
83
|
-
snapPointEntity.draw(ctx, 1);
|
|
84
|
-
expect(ctx.beginPath).toHaveBeenCalled();
|
|
85
|
-
expect(ctx.arc).toHaveBeenCalledWith(0.5, 0.5, expect.any(Number), 0, 6.283);
|
|
86
|
-
expect(ctx.stroke).toHaveBeenCalled();
|
|
73
|
+
const renderer = makeSnapRenderer();
|
|
74
|
+
snapPointEntity.draw(renderer, 1);
|
|
75
|
+
expect(renderer.setColour).toHaveBeenCalled();
|
|
76
|
+
expect(renderer.drawShape).toHaveBeenCalled();
|
|
87
77
|
});
|
|
88
78
|
|
|
89
79
|
test('Test Snapping.addTrackingLine', () => {
|
|
@@ -98,23 +88,9 @@ test('Test TrackingLine.draw', () => {
|
|
|
98
88
|
// note: the default matrix has d=-1, so scene y is in [-1, 0] for a 1x1 canvas
|
|
99
89
|
snapping.addTrackingLine(new Point(0.2, -0.5), new Point(0.8, -0.5));
|
|
100
90
|
const trackingLine = DesignCore.Scene.auxiliaryEntities.get(0);
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
beginPath: jest.fn(),
|
|
105
|
-
strokeStyle: '',
|
|
106
|
-
lineWidth: 0,
|
|
107
|
-
setLineDash: jest.fn(),
|
|
108
|
-
moveTo: jest.fn(),
|
|
109
|
-
lineTo: jest.fn(),
|
|
110
|
-
stroke: jest.fn(),
|
|
111
|
-
};
|
|
112
|
-
trackingLine.draw(ctx, 1);
|
|
113
|
-
expect(ctx.save).toHaveBeenCalled();
|
|
114
|
-
expect(ctx.moveTo).toHaveBeenCalled();
|
|
115
|
-
expect(ctx.lineTo).toHaveBeenCalled();
|
|
116
|
-
expect(ctx.stroke).toHaveBeenCalled();
|
|
117
|
-
expect(ctx.restore).toHaveBeenCalled();
|
|
91
|
+
const renderer = makeTrackingRenderer();
|
|
92
|
+
trackingLine.draw(renderer, 1);
|
|
93
|
+
expect(renderer.drawShape).toHaveBeenCalled();
|
|
118
94
|
});
|
|
119
95
|
|
|
120
96
|
test('Test TrackingLine.draw degenerate zero direction', () => {
|
|
@@ -122,20 +98,10 @@ test('Test TrackingLine.draw degenerate zero direction', () => {
|
|
|
122
98
|
// inputPoint equals snapPoint → direction is zero vector → draw returns early
|
|
123
99
|
snapping.addTrackingLine(new Point(0.5, 0.5), new Point(0.5, 0.5));
|
|
124
100
|
const trackingLine = DesignCore.Scene.auxiliaryEntities.get(0);
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
strokeStyle: '',
|
|
130
|
-
lineWidth: 0,
|
|
131
|
-
setLineDash: jest.fn(),
|
|
132
|
-
moveTo: jest.fn(),
|
|
133
|
-
lineTo: jest.fn(),
|
|
134
|
-
stroke: jest.fn(),
|
|
135
|
-
};
|
|
136
|
-
trackingLine.draw(ctx, 1);
|
|
137
|
-
expect(ctx.moveTo).not.toHaveBeenCalled();
|
|
138
|
-
expect(ctx.stroke).not.toHaveBeenCalled();
|
|
101
|
+
const renderer = makeTrackingRenderer();
|
|
102
|
+
trackingLine.draw(renderer, 1);
|
|
103
|
+
expect(renderer.drawShape).not.toHaveBeenCalled();
|
|
104
|
+
expect(renderer.restore).not.toHaveBeenCalled();
|
|
139
105
|
});
|
|
140
106
|
|
|
141
107
|
test('Test Snapping.polarSnap', () => {
|
|
@@ -199,35 +165,27 @@ test('Test Snapping.orthoSnap', () => {
|
|
|
199
165
|
expect(snapping.orthoSnap(new Point(0, 0))).toBeUndefined();
|
|
200
166
|
});
|
|
201
167
|
|
|
202
|
-
// ───
|
|
168
|
+
// ─── Renderer mock helpers ──────────────────────────────────────────────────
|
|
203
169
|
|
|
204
|
-
/** @return {object} mock
|
|
205
|
-
function
|
|
170
|
+
/** @return {object} mock renderer for SnapPoint.draw tests */
|
|
171
|
+
function makeSnapRenderer() {
|
|
206
172
|
return {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
moveTo: jest.fn(),
|
|
212
|
-
lineTo: jest.fn(),
|
|
213
|
-
closePath: jest.fn(),
|
|
214
|
-
arc: jest.fn(),
|
|
215
|
-
stroke: jest.fn(),
|
|
173
|
+
setColour: jest.fn(),
|
|
174
|
+
setLineWidth: jest.fn(),
|
|
175
|
+
setDash: jest.fn(),
|
|
176
|
+
drawShape: jest.fn(),
|
|
216
177
|
};
|
|
217
178
|
}
|
|
218
179
|
|
|
219
|
-
/** @return {object} mock
|
|
220
|
-
function
|
|
180
|
+
/** @return {object} mock renderer for TrackingLine.draw tests */
|
|
181
|
+
function makeTrackingRenderer() {
|
|
221
182
|
return {
|
|
222
183
|
save: jest.fn(),
|
|
223
184
|
restore: jest.fn(),
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
moveTo: jest.fn(),
|
|
229
|
-
lineTo: jest.fn(),
|
|
230
|
-
stroke: jest.fn(),
|
|
185
|
+
setColour: jest.fn(),
|
|
186
|
+
setLineWidth: jest.fn(),
|
|
187
|
+
setDash: jest.fn(),
|
|
188
|
+
drawShape: jest.fn(),
|
|
231
189
|
};
|
|
232
190
|
}
|
|
233
191
|
|
|
@@ -294,74 +252,58 @@ test('Test Snapping.getSnapPoint with non-matching override returns undefined',
|
|
|
294
252
|
|
|
295
253
|
// ─── SnapPoint.draw – all snap types ────────────────────────────────────────
|
|
296
254
|
|
|
297
|
-
test('Test SnapPoint.draw END type draws closed polygon
|
|
255
|
+
test('Test SnapPoint.draw END type draws closed polygon', () => {
|
|
298
256
|
const sp = new SnapPoint(new Point(5, 5), SnapPoint.Type.END);
|
|
299
|
-
const
|
|
300
|
-
sp.draw(
|
|
301
|
-
expect(
|
|
302
|
-
expect(
|
|
303
|
-
expect(ctx.stroke).toHaveBeenCalled();
|
|
304
|
-
expect(ctx.arc).not.toHaveBeenCalled();
|
|
257
|
+
const renderer = makeSnapRenderer();
|
|
258
|
+
sp.draw(renderer, 1);
|
|
259
|
+
expect(renderer.drawShape).toHaveBeenCalledTimes(1);
|
|
260
|
+
expect(renderer.drawShape).toHaveBeenCalledWith(expect.any(Array), expect.objectContaining({ closed: true }));
|
|
305
261
|
});
|
|
306
262
|
|
|
307
|
-
test('Test SnapPoint.draw MID type draws closed polygon
|
|
263
|
+
test('Test SnapPoint.draw MID type draws closed polygon', () => {
|
|
308
264
|
const sp = new SnapPoint(new Point(5, 5), SnapPoint.Type.MID);
|
|
309
|
-
const
|
|
310
|
-
sp.draw(
|
|
311
|
-
expect(
|
|
312
|
-
expect(
|
|
313
|
-
expect(ctx.stroke).toHaveBeenCalled();
|
|
314
|
-
expect(ctx.arc).not.toHaveBeenCalled();
|
|
265
|
+
const renderer = makeSnapRenderer();
|
|
266
|
+
sp.draw(renderer, 1);
|
|
267
|
+
expect(renderer.drawShape).toHaveBeenCalledTimes(1);
|
|
268
|
+
expect(renderer.drawShape).toHaveBeenCalledWith(expect.any(Array), expect.objectContaining({ closed: true }));
|
|
315
269
|
});
|
|
316
270
|
|
|
317
|
-
test('Test SnapPoint.draw QUADRANT type draws closed polygon
|
|
271
|
+
test('Test SnapPoint.draw QUADRANT type draws closed polygon', () => {
|
|
318
272
|
const sp = new SnapPoint(new Point(5, 5), SnapPoint.Type.QUADRANT);
|
|
319
|
-
const
|
|
320
|
-
sp.draw(
|
|
321
|
-
expect(
|
|
322
|
-
expect(
|
|
323
|
-
expect(ctx.stroke).toHaveBeenCalled();
|
|
324
|
-
expect(ctx.arc).not.toHaveBeenCalled();
|
|
273
|
+
const renderer = makeSnapRenderer();
|
|
274
|
+
sp.draw(renderer, 1);
|
|
275
|
+
expect(renderer.drawShape).toHaveBeenCalledTimes(1);
|
|
276
|
+
expect(renderer.drawShape).toHaveBeenCalledWith(expect.any(Array), expect.objectContaining({ closed: true }));
|
|
325
277
|
});
|
|
326
278
|
|
|
327
|
-
test('Test SnapPoint.draw NEAREST type draws closed polygon
|
|
279
|
+
test('Test SnapPoint.draw NEAREST type draws closed polygon', () => {
|
|
328
280
|
const sp = new SnapPoint(new Point(5, 5), SnapPoint.Type.NEAREST);
|
|
329
|
-
const
|
|
330
|
-
sp.draw(
|
|
331
|
-
expect(
|
|
332
|
-
expect(
|
|
333
|
-
expect(ctx.stroke).toHaveBeenCalled();
|
|
334
|
-
expect(ctx.arc).not.toHaveBeenCalled();
|
|
281
|
+
const renderer = makeSnapRenderer();
|
|
282
|
+
sp.draw(renderer, 1);
|
|
283
|
+
expect(renderer.drawShape).toHaveBeenCalledTimes(1);
|
|
284
|
+
expect(renderer.drawShape).toHaveBeenCalledWith(expect.any(Array), expect.objectContaining({ closed: true }));
|
|
335
285
|
});
|
|
336
286
|
|
|
337
|
-
test('Test SnapPoint.draw TANGENT type draws
|
|
287
|
+
test('Test SnapPoint.draw TANGENT type draws circle and tangent line', () => {
|
|
338
288
|
const sp = new SnapPoint(new Point(5, 5), SnapPoint.Type.TANGENT);
|
|
339
|
-
const
|
|
340
|
-
sp.draw(
|
|
341
|
-
expect(
|
|
342
|
-
expect(ctx.arc).toHaveBeenCalledWith(5, 5, expect.any(Number), 0, 6.283);
|
|
343
|
-
expect(ctx.stroke).toHaveBeenCalled();
|
|
344
|
-
expect(ctx.closePath).not.toHaveBeenCalled();
|
|
289
|
+
const renderer = makeSnapRenderer();
|
|
290
|
+
sp.draw(renderer, 1);
|
|
291
|
+
expect(renderer.drawShape).toHaveBeenCalledTimes(2);
|
|
345
292
|
});
|
|
346
293
|
|
|
347
|
-
test('Test SnapPoint.draw NODE type draws
|
|
294
|
+
test('Test SnapPoint.draw NODE type draws circle and X lines', () => {
|
|
348
295
|
const sp = new SnapPoint(new Point(5, 5), SnapPoint.Type.NODE);
|
|
349
|
-
const
|
|
350
|
-
sp.draw(
|
|
351
|
-
expect(
|
|
352
|
-
expect(ctx.arc).toHaveBeenCalledWith(5, 5, expect.any(Number), 0, 6.283);
|
|
353
|
-
expect(ctx.stroke).toHaveBeenCalled();
|
|
354
|
-
expect(ctx.closePath).not.toHaveBeenCalled();
|
|
296
|
+
const renderer = makeSnapRenderer();
|
|
297
|
+
sp.draw(renderer, 1);
|
|
298
|
+
expect(renderer.drawShape).toHaveBeenCalledTimes(3);
|
|
355
299
|
});
|
|
356
300
|
|
|
357
|
-
test('Test SnapPoint.draw PERPENDICULAR type draws L-shape
|
|
301
|
+
test('Test SnapPoint.draw PERPENDICULAR type draws L-shape', () => {
|
|
358
302
|
const sp = new SnapPoint(new Point(5, 5), SnapPoint.Type.PERPENDICULAR);
|
|
359
|
-
const
|
|
360
|
-
sp.draw(
|
|
361
|
-
expect(
|
|
362
|
-
expect(
|
|
363
|
-
expect(ctx.closePath).not.toHaveBeenCalled();
|
|
364
|
-
expect(ctx.arc).not.toHaveBeenCalled();
|
|
303
|
+
const renderer = makeSnapRenderer();
|
|
304
|
+
sp.draw(renderer, 1);
|
|
305
|
+
expect(renderer.drawShape).toHaveBeenCalledTimes(1);
|
|
306
|
+
expect(renderer.drawShape).not.toHaveBeenCalledWith(expect.any(Array), expect.objectContaining({ closed: true }));
|
|
365
307
|
});
|
|
366
308
|
|
|
367
309
|
// ─── TrackingLine.draw – out-of-bounds cases ─────────────────────────────────
|
|
@@ -371,10 +313,10 @@ test('Test TrackingLine.draw vertical line outside x bounds', () => {
|
|
|
371
313
|
// dir.x === 0 and from.x = 2 > boundsMax.x = 1 → draw returns early
|
|
372
314
|
snapping.addTrackingLine(new Point(2, -0.5), new Point(2, 0.5));
|
|
373
315
|
const trackingLine = DesignCore.Scene.auxiliaryEntities.get(0);
|
|
374
|
-
const
|
|
375
|
-
trackingLine.draw(
|
|
376
|
-
expect(
|
|
377
|
-
expect(
|
|
316
|
+
const renderer = makeTrackingRenderer();
|
|
317
|
+
trackingLine.draw(renderer, 1);
|
|
318
|
+
expect(renderer.drawShape).not.toHaveBeenCalled();
|
|
319
|
+
expect(renderer.restore).not.toHaveBeenCalled();
|
|
378
320
|
});
|
|
379
321
|
|
|
380
322
|
test('Test TrackingLine.draw horizontal line outside y bounds', () => {
|
|
@@ -382,10 +324,10 @@ test('Test TrackingLine.draw horizontal line outside y bounds', () => {
|
|
|
382
324
|
// dir.y === 0 and from.y = -5 < boundsMin.y = -1 → draw returns early
|
|
383
325
|
snapping.addTrackingLine(new Point(0.5, -5), new Point(0.8, -5));
|
|
384
326
|
const trackingLine = DesignCore.Scene.auxiliaryEntities.get(0);
|
|
385
|
-
const
|
|
386
|
-
trackingLine.draw(
|
|
387
|
-
expect(
|
|
388
|
-
expect(
|
|
327
|
+
const renderer = makeTrackingRenderer();
|
|
328
|
+
trackingLine.draw(renderer, 1);
|
|
329
|
+
expect(renderer.drawShape).not.toHaveBeenCalled();
|
|
330
|
+
expect(renderer.restore).not.toHaveBeenCalled();
|
|
389
331
|
});
|
|
390
332
|
|
|
391
333
|
test('Test TrackingLine.draw line does not intersect canvas bounds', () => {
|
|
@@ -394,8 +336,8 @@ test('Test TrackingLine.draw line does not intersect canvas bounds', () => {
|
|
|
394
336
|
// tMax (-1) < tMin (-0.5) → draw returns early
|
|
395
337
|
snapping.addTrackingLine(new Point(2, -0.5), new Point(3, 0.5));
|
|
396
338
|
const trackingLine = DesignCore.Scene.auxiliaryEntities.get(0);
|
|
397
|
-
const
|
|
398
|
-
trackingLine.draw(
|
|
399
|
-
expect(
|
|
400
|
-
expect(
|
|
339
|
+
const renderer = makeTrackingRenderer();
|
|
340
|
+
trackingLine.draw(renderer, 1);
|
|
341
|
+
expect(renderer.drawShape).not.toHaveBeenCalled();
|
|
342
|
+
expect(renderer.restore).not.toHaveBeenCalled();
|
|
401
343
|
});
|
|
@@ -58,24 +58,24 @@ describe('StateManager', () => {
|
|
|
58
58
|
}
|
|
59
59
|
const target = em.get(2);
|
|
60
60
|
sm.commit(em, [new UpdateState(target, { layer: 'newLayer' })]);
|
|
61
|
-
expect(em.get(2).layer).toBe('newLayer');
|
|
61
|
+
expect(em.get(2).getProperty('layer')).toBe('newLayer');
|
|
62
62
|
sm.undo();
|
|
63
|
-
expect(em.get(2).layer).toBe('testLayer');
|
|
63
|
+
expect(em.get(2).getProperty('layer')).toBe('testLayer');
|
|
64
64
|
sm.redo();
|
|
65
|
-
expect(em.get(2).layer).toBe('newLayer');
|
|
65
|
+
expect(em.get(2).getProperty('layer')).toBe('newLayer');
|
|
66
66
|
});
|
|
67
67
|
|
|
68
68
|
test('addState removed future states', () => {
|
|
69
69
|
const em = new EntityManager();
|
|
70
70
|
const line = new Line({ layer: 'testLayer', points: [new Point(), new Point(10, 11)] });
|
|
71
71
|
sm.commit(em, [new AddState(line)]);
|
|
72
|
-
expect(em.get(0).layer).toBe('testLayer');
|
|
72
|
+
expect(em.get(0).getProperty('layer')).toBe('testLayer');
|
|
73
73
|
sm.commit(em, [new UpdateState(line, { layer: 'differentLayer', points: [new Point(1, 2), new Point(101, 110)] })]);
|
|
74
|
-
expect(em.get(0).layer).toBe('differentLayer');
|
|
74
|
+
expect(em.get(0).getProperty('layer')).toBe('differentLayer');
|
|
75
75
|
sm.undo();
|
|
76
|
-
expect(em.get(0).layer).toBe('testLayer');
|
|
76
|
+
expect(em.get(0).getProperty('layer')).toBe('testLayer');
|
|
77
77
|
sm.redo();
|
|
78
|
-
expect(em.get(0).layer).toBe('differentLayer');
|
|
78
|
+
expect(em.get(0).getProperty('layer')).toBe('differentLayer');
|
|
79
79
|
});
|
|
80
80
|
|
|
81
81
|
test('clearHistory resets history and indices', () => {
|
package/test/lib/utils.test.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Arc } from '../../core/entities/arc.js';
|
|
2
|
+
import { Hatch } from '../../core/entities/hatch.js';
|
|
2
3
|
import { Utils } from '../../core/lib/utils.js';
|
|
3
4
|
import { Point } from '../../core/entities/point.js';
|
|
4
5
|
|
|
@@ -74,7 +75,7 @@ test('Test Utils.sortPointsOnArc mutates array ordered by angular position', ()
|
|
|
74
75
|
];
|
|
75
76
|
|
|
76
77
|
const arc = new Arc({ points: [new Point(0, 0), new Point(10, 0), new Point(-10, 0)], direction: 1 });
|
|
77
|
-
Utils.sortPointsOnArc(pts, arc.points[1], arc.points[2], arc.points[0], arc.direction);
|
|
78
|
+
Utils.sortPointsOnArc(pts, arc.points[1], arc.points[2], arc.points[0], arc.getProperty('direction'));
|
|
78
79
|
// Expect order: (10,0), (7.1, 7.1), (10,10), (-7.1, 7.1), (-10,0)
|
|
79
80
|
expect(pts[0].x).toBe(10);
|
|
80
81
|
expect(pts[0].y).toBe(0);
|
|
@@ -92,7 +93,7 @@ test('Test Utils.sortPointsOnArc mutates array ordered by angular position', ()
|
|
|
92
93
|
expect(pts[4].y).toBe(0);
|
|
93
94
|
|
|
94
95
|
const cwArc = new Arc({ points: [new Point(0, 0), new Point(-10, 0), new Point(10, 0)], direction: -1 });
|
|
95
|
-
Utils.sortPointsOnArc(pts, cwArc.points[1], cwArc.points[2], cwArc.points[0], cwArc.direction);
|
|
96
|
+
Utils.sortPointsOnArc(pts, cwArc.points[1], cwArc.points[2], cwArc.points[0], cwArc.getProperty('direction'));
|
|
96
97
|
// Expect order: (-10,0), (-7.1, 7.1), (10,10), (7.1, 7.1), (10,0)
|
|
97
98
|
expect(pts[0].x).toBe(-10);
|
|
98
99
|
expect(pts[0].y).toBe(0);
|
|
@@ -110,6 +111,39 @@ test('Test Utils.sortPointsOnArc mutates array ordered by angular position', ()
|
|
|
110
111
|
expect(pts[4].y).toBe(0);
|
|
111
112
|
});
|
|
112
113
|
|
|
114
|
+
test('Test Utils.cloneProperties copies default properties from entity', () => {
|
|
115
|
+
const arc = new Arc({ layer: 'walls', lineWidth: 5, lineType: 'DASHED' });
|
|
116
|
+
const props = Utils.cloneProperties(arc);
|
|
117
|
+
expect(props.layer).toBe('walls');
|
|
118
|
+
expect(props.lineWidth).toBe(5);
|
|
119
|
+
expect(props.lineType).toBe('DASHED');
|
|
120
|
+
expect(Object.keys(props)).toEqual(expect.arrayContaining(['layer', 'colour', 'lineWidth', 'lineType']));
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('Test Utils.cloneProperties respects custom properties list', () => {
|
|
124
|
+
const arc = new Arc({ layer: 'walls', lineWidth: 5, lineType: 'DASHED' });
|
|
125
|
+
const props = Utils.cloneProperties(arc, ['layer', 'lineWidth']);
|
|
126
|
+
expect(props.layer).toBe('walls');
|
|
127
|
+
expect(props.lineWidth).toBe(5);
|
|
128
|
+
expect(props.lineType).toBeUndefined();
|
|
129
|
+
expect(props.colour).toBeUndefined();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test('Test Utils.cloneProperties copies patternName from Hatch', () => {
|
|
133
|
+
const hatch = new Hatch({ patternName: 'ANSI37' });
|
|
134
|
+
const props = Utils.cloneProperties(hatch);
|
|
135
|
+
expect(props.patternName).toBe('ANSI37');
|
|
136
|
+
// lineType is hidden on Hatch
|
|
137
|
+
expect(props.lineType).toBeUndefined();
|
|
138
|
+
expect(props.lineWidth).toBeDefined();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test('Test Utils.cloneProperties does not include patternName for non-hatch entities', () => {
|
|
142
|
+
const arc = new Arc({ layer: 'walls' });
|
|
143
|
+
const props = Utils.cloneProperties(arc);
|
|
144
|
+
expect(props.patternName).toBeUndefined();
|
|
145
|
+
});
|
|
146
|
+
|
|
113
147
|
test('Test Utils.areaOfTriangle', () => {
|
|
114
148
|
expect(Utils.areaOfTriangle(new Point(0, 0), new Point(10, 0), new Point(0, 10))).toBe(50);
|
|
115
149
|
expect(Utils.areaOfTriangle(new Point(-5, -5), new Point(5, -5), new Point(0, 5))).toBe(50);
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { Core } from '../../core/core/core.js';
|
|
2
|
+
import { EntityProperties } from '../../core/properties/entityProperties.js';
|
|
3
|
+
import { Property } from '../../core/properties/property.js';
|
|
4
|
+
import { Entity } from '../../core/entities/entity.js';
|
|
5
|
+
|
|
6
|
+
// initialise core
|
|
7
|
+
new Core();
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Minimal entity-like object for isolated EntityProperties tests.
|
|
11
|
+
* @return {Object} plain object with layer and lineWidth fields
|
|
12
|
+
*/
|
|
13
|
+
function makeTarget() {
|
|
14
|
+
return { layer: '0', lineWidth: 1 };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe('EntityProperties.add / get', () => {
|
|
18
|
+
test('get returns value after add', () => {
|
|
19
|
+
const ep = new EntityProperties(makeTarget());
|
|
20
|
+
ep.add('layer', { type: Property.Type.LIST, value: '0' });
|
|
21
|
+
expect(ep.get('layer')).toBe('0');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('get returns undefined for unknown property', () => {
|
|
25
|
+
const ep = new EntityProperties(makeTarget());
|
|
26
|
+
expect(ep.get('unknown')).toBeUndefined();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('EntityProperties.set', () => {
|
|
31
|
+
test('updates value in _store, readable via get', () => {
|
|
32
|
+
const target = makeTarget();
|
|
33
|
+
const ep = new EntityProperties(target);
|
|
34
|
+
ep.add('layer', { type: Property.Type.LIST, value: target.layer });
|
|
35
|
+
ep.set('layer', 'WALLS');
|
|
36
|
+
expect(ep.get('layer')).toBe('WALLS');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('no-op for unknown property', () => {
|
|
40
|
+
const target = makeTarget();
|
|
41
|
+
const ep = new EntityProperties(target);
|
|
42
|
+
expect(() => ep.set('unknown', 'X')).not.toThrow();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('no-op when property is readOnly', () => {
|
|
46
|
+
const target = makeTarget();
|
|
47
|
+
const ep = new EntityProperties(target);
|
|
48
|
+
ep.add('type', { type: Property.Type.LABEL, value: 'Line', readOnly: true });
|
|
49
|
+
ep.set('type', 'Circle');
|
|
50
|
+
expect(ep.get('type')).toBe('Line');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('EntityProperties.has', () => {
|
|
55
|
+
test('returns true for registered property', () => {
|
|
56
|
+
const ep = new EntityProperties(makeTarget());
|
|
57
|
+
ep.add('layer', { type: Property.Type.LIST, value: '0' });
|
|
58
|
+
expect(ep.has('layer')).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('returns false for unregistered property', () => {
|
|
62
|
+
const ep = new EntityProperties(makeTarget());
|
|
63
|
+
expect(ep.has('layer')).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe('EntityProperties.remove', () => {
|
|
68
|
+
test('removes a registered property', () => {
|
|
69
|
+
const ep = new EntityProperties(makeTarget());
|
|
70
|
+
ep.add('layer', { type: Property.Type.LIST, value: '0' });
|
|
71
|
+
ep.remove('layer');
|
|
72
|
+
expect(ep.has('layer')).toBe(false);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('EntityProperties.list', () => {
|
|
77
|
+
test('returns names of visible properties in registration order', () => {
|
|
78
|
+
const ep = new EntityProperties(makeTarget());
|
|
79
|
+
ep.add('layer', { type: Property.Type.LIST, value: '0' });
|
|
80
|
+
ep.add('lineWidth', { type: Property.Type.NUMBER, value: 1 });
|
|
81
|
+
ep.add('hidden', { type: Property.Type.LABEL, value: 'x', visible: false });
|
|
82
|
+
expect(ep.list()).toEqual(['layer', 'lineWidth']);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('EntityProperties.definition', () => {
|
|
87
|
+
test('returns the Property descriptor', () => {
|
|
88
|
+
const ep = new EntityProperties(makeTarget());
|
|
89
|
+
ep.add('layer', { type: Property.Type.LIST, value: '0', dxfCode: 8 });
|
|
90
|
+
const def = ep.definition('layer');
|
|
91
|
+
expect(def).toBeInstanceOf(Property);
|
|
92
|
+
expect(def.type).toBe(Property.Type.LIST);
|
|
93
|
+
expect(def.dxfCode).toBe(8);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test('returns undefined for unknown property', () => {
|
|
97
|
+
const ep = new EntityProperties(makeTarget());
|
|
98
|
+
expect(ep.definition('unknown')).toBeUndefined();
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('Entity.properties integration', () => {
|
|
103
|
+
test('entity has properties registered for layer, lineType, lineWidth, colour', () => {
|
|
104
|
+
const e = new Entity();
|
|
105
|
+
expect(e.properties.has('layer')).toBe(true);
|
|
106
|
+
expect(e.properties.has('lineType')).toBe(true);
|
|
107
|
+
expect(e.properties.has('lineWidth')).toBe(true);
|
|
108
|
+
expect(e.properties.has('colour')).toBe(true);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test('properties values match entity fields at construction', () => {
|
|
112
|
+
const e = new Entity({ layer: 'TEST', lineWidth: 5 });
|
|
113
|
+
expect(e.properties.get('layer')).toBe('TEST');
|
|
114
|
+
expect(e.properties.get('lineWidth')).toBe(5);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('set updates _store value, readable via get', () => {
|
|
118
|
+
const e = new Entity();
|
|
119
|
+
e.properties.set('layer', 'DOORS');
|
|
120
|
+
expect(e.properties.get('layer')).toBe('DOORS');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('list returns the 4 registered property names', () => {
|
|
124
|
+
const e = new Entity();
|
|
125
|
+
expect(e.properties.list()).toEqual(['layer', 'lineType', 'lineWidth', 'colour']);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('properties is non-enumerable on entity', () => {
|
|
129
|
+
const e = new Entity();
|
|
130
|
+
expect(Object.keys(e)).not.toContain('properties');
|
|
131
|
+
});
|
|
132
|
+
});
|
|
@@ -11,3 +11,56 @@ test('Test property.loadValue', () => {
|
|
|
11
11
|
flags.setFlagValue(4);
|
|
12
12
|
expect(Property.loadValue([flags], 3)).toBe(4);
|
|
13
13
|
});
|
|
14
|
+
|
|
15
|
+
describe('Property.Type', () => {
|
|
16
|
+
test('has all expected members', () => {
|
|
17
|
+
expect(Property.Type.NUMBER).toBe('NUMBER');
|
|
18
|
+
expect(Property.Type.STRING).toBe('STRING');
|
|
19
|
+
expect(Property.Type.BOOLEAN).toBe('BOOLEAN');
|
|
20
|
+
expect(Property.Type.LIST).toBe('LIST');
|
|
21
|
+
expect(Property.Type.COLOUR).toBe('COLOUR');
|
|
22
|
+
expect(Property.Type.LABEL).toBe('LABEL');
|
|
23
|
+
expect(Property.Type.ENTITIES).toBe('ENTITIES');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('has exactly 7 members', () => {
|
|
27
|
+
expect(Object.keys(Property.Type)).toHaveLength(7);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('Property instance', () => {
|
|
32
|
+
test('stores type and value', () => {
|
|
33
|
+
const p = new Property({ type: Property.Type.NUMBER, value: 42 });
|
|
34
|
+
expect(p.type).toBe(Property.Type.NUMBER);
|
|
35
|
+
expect(p.value).toBe(42);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('defaults readOnly to false and visible to true', () => {
|
|
39
|
+
const p = new Property({ type: Property.Type.STRING, value: 'hello' });
|
|
40
|
+
expect(p.readOnly).toBe(false);
|
|
41
|
+
expect(p.visible).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('set value updates when not readOnly', () => {
|
|
45
|
+
const p = new Property({ type: Property.Type.NUMBER, value: 1 });
|
|
46
|
+
p.value = 99;
|
|
47
|
+
expect(p.value).toBe(99);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('set value is ignored when readOnly', () => {
|
|
51
|
+
const p = new Property({ type: Property.Type.LABEL, value: 'fixed', readOnly: true });
|
|
52
|
+
p.value = 'changed';
|
|
53
|
+
expect(p.value).toBe('fixed');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('stores dxfCode', () => {
|
|
57
|
+
const p = new Property({ type: Property.Type.LIST, value: '0', dxfCode: 8 });
|
|
58
|
+
expect(p.dxfCode).toBe(8);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('no-arg constructor produces undefined fields without throwing', () => {
|
|
62
|
+
const p = new Property();
|
|
63
|
+
expect(p.type).toBeUndefined();
|
|
64
|
+
expect(p.value).toBeUndefined();
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -49,7 +49,7 @@ test('Test propertyManager.setItemProperties', () => {
|
|
|
49
49
|
|
|
50
50
|
let text = DesignCore.Scene.entities.get(2);
|
|
51
51
|
expect(text.type).toBe('Text');
|
|
52
|
-
expect(text.string).toBe(string);
|
|
52
|
+
expect(text.getProperty('string')).toBe(string);
|
|
53
53
|
|
|
54
54
|
// try and set a non-existent property
|
|
55
55
|
propertiesManager.setItemProperties('faux-prop', string);
|
|
@@ -61,11 +61,11 @@ test('Test propertyManager.setItemProperties', () => {
|
|
|
61
61
|
// Select the circle element
|
|
62
62
|
DesignCore.Scene.selectionManager.selectionSet.selectionSet.push(1);
|
|
63
63
|
// get the current radius
|
|
64
|
-
const radius = DesignCore.Scene.entities.get(1).radius;
|
|
64
|
+
const radius = DesignCore.Scene.entities.get(1).getProperty('radius');
|
|
65
65
|
// try and set an incorrect value
|
|
66
66
|
propertiesManager.setItemProperties('radius', string);
|
|
67
67
|
const circle = DesignCore.Scene.entities.get(1);
|
|
68
|
-
expect(circle.radius).toBe(radius);
|
|
68
|
+
expect(circle.getProperty('radius')).toBe(radius);
|
|
69
69
|
});
|
|
70
70
|
|
|
71
71
|
test('Test propertyManager.getItemProperties', () => {
|