@design-core/core 0.0.1 → 0.0.3
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 +14 -7
- package/.github/workflows/DesignCoreQA.yml +3 -1
- package/README.md +11 -4
- package/TODO.md +19 -0
- package/core/core/core.js +49 -42
- package/core/designCore.js +61 -2
- package/core/dimensions/alignedDimension.js +142 -0
- package/core/dimensions/angularDimension.js +550 -0
- package/core/dimensions/baseCircularDimension.js +244 -0
- package/core/dimensions/baseDimension.js +558 -0
- package/core/dimensions/baseLinearDimension.js +371 -0
- package/core/dimensions/diametricDimension.js +82 -0
- package/core/dimensions/dimension.js +298 -0
- package/core/dimensions/linearDimension.js +29 -0
- package/core/dimensions/radialDimension.js +78 -0
- package/core/dimensions/rotatedDimension.js +167 -0
- package/core/entities/arc.js +314 -60
- package/core/entities/arctext.js +642 -0
- package/core/entities/basePolyline.js +553 -94
- package/core/entities/circle.js +181 -54
- package/core/entities/entity.js +154 -74
- package/core/entities/hatch.js +807 -0
- package/core/entities/insert.js +200 -39
- package/core/entities/line.js +196 -134
- package/core/entities/lwpolyline.js +21 -44
- package/core/entities/point.js +194 -29
- package/core/entities/polyline.js +54 -7
- package/core/entities/rectangle.js +43 -13
- package/core/entities/solid.js +43 -6
- package/core/entities/text.js +324 -181
- package/core/lib/boundingBox.js +73 -13
- package/core/lib/canvas.js +256 -65
- package/core/lib/clipboard.js +198 -0
- package/core/lib/colour.js +144 -0
- package/core/lib/colours.js +367 -301
- package/core/lib/commandLine.js +16 -28
- package/core/lib/commandManager.js +115 -58
- package/core/lib/constants.js +23 -0
- package/core/lib/dxf/dxf.js +249 -34
- package/core/lib/dxf/dxfFile.js +23 -38
- package/core/lib/dxf/dxfIterator.js +17 -5
- package/core/lib/dxf/dxfRead.js +23 -7
- package/core/lib/dxf/dxfWrite.js +39 -129
- package/core/lib/dxf/handleManager.js +97 -0
- package/core/lib/dxf/sections/blocks.js +16 -2
- package/core/lib/dxf/sections/entities.js +17 -3
- package/core/lib/dxf/sections/header.js +10 -1
- package/core/lib/dxf/sections/objects.js +36 -0
- package/core/lib/dxf/sections/section.js +43 -5
- package/core/lib/dxf/sections/tables.js +17 -3
- package/core/lib/entityManager.js +178 -0
- package/core/lib/fileio.js +14 -4
- package/core/lib/headers.js +229 -0
- package/core/lib/input.js +46 -0
- package/core/lib/inputManager.js +199 -194
- package/core/lib/intersect.js +341 -468
- package/core/lib/logging.js +25 -1
- package/core/lib/matrix.js +6 -8
- package/core/lib/mouse.js +24 -79
- package/core/lib/patterns.js +690 -0
- package/core/lib/promptOptions.js +133 -0
- package/core/lib/scene.js +71 -174
- package/core/lib/selectionManager.js +74 -48
- package/core/lib/selectionWindow.js +24 -10
- package/core/lib/settings.js +18 -11
- package/core/lib/snapping.js +129 -21
- package/core/lib/stateManager.js +288 -0
- package/core/lib/strings.js +57 -5
- package/core/lib/utils.js +95 -11
- package/core/objects/dictionary.js +43 -0
- package/core/objects/dictionaryManager.js +80 -0
- package/core/properties/dimType.js +117 -0
- package/core/properties/flags.js +66 -0
- package/core/properties/property.js +26 -0
- package/core/properties/propertyManager.js +65 -19
- package/core/tables/appId.js +31 -0
- package/core/tables/appIdManager.js +44 -0
- package/core/tables/block.js +323 -0
- package/core/tables/blockManager.js +48 -0
- package/core/tables/blockRecord.js +29 -0
- package/core/tables/blockRecordManager.js +37 -0
- package/core/tables/dimStyle.js +627 -0
- package/core/tables/dimStyleManager.js +187 -0
- package/core/tables/endblk.js +28 -0
- package/core/tables/layer.js +219 -0
- package/core/tables/layerManager.js +47 -0
- package/core/tables/ltype.js +85 -0
- package/core/tables/ltypeManager.js +65 -0
- package/core/tables/style.js +145 -0
- package/core/tables/styleManager.js +55 -0
- package/core/tables/styleManagerBase.js +110 -0
- package/core/tables/tableManagerBase.js +354 -0
- package/core/tables/ucs.js +28 -0
- package/core/tables/ucsManager.js +44 -0
- package/core/tables/view.js +28 -0
- package/core/tables/viewManager.js +44 -0
- package/core/tables/vport.js +70 -0
- package/core/tables/vportManager.js +65 -0
- package/core/tools/chamfer.js +343 -0
- package/core/tools/chamferFilletBase.js +162 -0
- package/core/tools/copy.js +68 -40
- package/core/tools/copybase.js +65 -0
- package/core/tools/copyclip.js +59 -0
- package/core/tools/cornerEntity.js +138 -0
- package/core/tools/cutclip.js +72 -0
- package/core/tools/distance.js +37 -9
- package/core/tools/erase.js +43 -13
- package/core/tools/explode.js +117 -0
- package/core/tools/extend.js +71 -32
- package/core/tools/fillet.js +336 -0
- package/core/tools/identify.js +33 -6
- package/core/tools/matchProp.js +106 -0
- package/core/tools/mirror.js +141 -0
- package/core/tools/move.js +65 -32
- package/core/tools/offset.js +321 -0
- package/core/tools/pan.js +54 -0
- package/core/tools/pasteclip.js +93 -0
- package/core/tools/purge.js +90 -0
- package/core/tools/rotate.js +105 -70
- package/core/tools/scale.js +166 -0
- package/core/tools/tool.js +14 -4
- package/core/tools/trim.js +71 -32
- package/core/tools/zoom.js +152 -0
- package/package.json +3 -305
- package/test/dimensions/alignedDimension.test.js +211 -0
- package/test/dimensions/angularDimension.test.js +243 -0
- package/test/dimensions/baseDimension.test.js +239 -0
- package/test/dimensions/diametricDimension.test.js +203 -0
- package/test/dimensions/dimension.test.js +102 -0
- package/test/dimensions/radialDimension.test.js +203 -0
- package/test/dimensions/rotatedDimension.test.js +224 -0
- package/test/entities/arc.test.js +463 -41
- package/test/entities/arctext.test.js +329 -0
- package/test/entities/basePolyline.test.js +459 -10
- package/test/entities/circle.test.js +312 -7
- package/test/entities/entity.test.js +28 -9
- package/test/entities/hatch.test.js +606 -0
- package/test/entities/insert.test.js +90 -0
- package/test/entities/line.test.js +182 -6
- package/test/entities/point.test.js +375 -37
- package/test/entities/solid.test.js +156 -0
- package/test/entities/text.test.js +533 -7
- package/test/integration/exportIntegration.reference.dxf +1706 -0
- package/test/integration/exportIntegration.test.js +186 -0
- package/test/integration/importExportIntegration.test.js +126 -0
- package/test/integration/intersectionIntegration.test.js +880 -0
- package/test/integration/userInputIntegration.reference.dxf +1410 -0
- package/test/integration/userInputIntegration.test.js +269 -0
- package/test/lib/boundingBox.test.js +26 -2
- package/test/lib/canvas.test.js +613 -5
- package/test/lib/clipboard.test.js +70 -0
- package/test/lib/colour.test.js +114 -0
- package/test/lib/colours.test.js +63 -18
- package/test/lib/commandLine.test.js +159 -22
- package/test/lib/commandManager.test.js +4 -4
- package/test/lib/constants.test.js +9 -0
- package/test/lib/dxf/dxfFile.test.js +6 -2
- package/test/lib/dxf/dxfIterator.test.js +1 -1
- package/test/lib/dxf/dxfWrite.test.js +173 -0
- package/test/lib/dxf/handleManager.test.js +137 -0
- package/test/lib/dxf/sections/blocks.test.js +5 -5
- package/test/lib/dxf/sections/entities.test.js +4 -4
- package/test/lib/dxf/sections/header.test.js +18 -4
- package/test/lib/dxf/sections/objects.test.js +132 -0
- package/test/lib/dxf/sections/section.test.js +29 -29
- package/test/lib/dxf/sections/tables.test.js +3 -3
- package/test/lib/entityManager.test.js +163 -0
- package/test/lib/headers.test.js +233 -0
- package/test/lib/inputManager.test.js +1144 -5
- package/test/lib/intersect.test.js +454 -331
- package/test/lib/logging.test.js +1 -1
- package/test/lib/matrix.test.js +1 -1
- package/test/lib/mouse.test.js +327 -4
- package/test/lib/patterns.test.js +105 -0
- package/test/lib/promptOptions.test.js +179 -0
- package/test/lib/scene.test.js +16 -52
- package/test/lib/selectionManager.test.js +17 -5
- package/test/lib/settings.test.js +111 -5
- package/test/lib/snapping.test.js +142 -4
- package/test/lib/stateManager.test.js +155 -0
- package/test/lib/utils.test.js +81 -1
- package/test/objects/dictionary.test.js +81 -0
- package/test/objects/dictionaryManager.test.js +34 -0
- package/test/properties/dimType.test.js +62 -0
- package/test/properties/flags.test.js +164 -0
- package/test/properties/property.test.js +13 -0
- package/test/properties/propertyManager.test.js +10 -11
- package/test/tables/appId.test.js +46 -0
- package/test/tables/appIdManager.test.js +72 -0
- package/test/tables/block.test.js +157 -0
- package/test/tables/blockManager.test.js +52 -0
- package/test/tables/blockRecord.test.js +39 -0
- package/test/tables/blockRecordManager.test.js +60 -0
- package/test/tables/dimstyle.test.js +72 -0
- package/test/tables/endblk.test.js +30 -0
- package/test/tables/layer.test.js +95 -0
- package/test/tables/layerManager.test.js +172 -0
- package/test/{styles → tables}/ltype.test.js +7 -7
- package/test/{styles → tables}/ltypeManager.test.js +2 -2
- package/test/tables/style.test.js +44 -0
- package/test/tables/stylemanagerbase.test.js +220 -0
- package/test/tables/tableManagerBase.test.js +194 -0
- package/test/tables/ucs.test.js +37 -0
- package/test/tables/ucsManager.test.js +48 -0
- package/test/tables/view.test.js +37 -0
- package/test/tables/viewManager.test.js +48 -0
- package/test/tables/vport.test.js +117 -0
- package/test/tables/vportManager.test.js +54 -0
- package/test/test-helpers/test-helpers.js +66 -0
- package/test/tools/chamfer.test.js +970 -0
- package/test/tools/chamferFilletBase.test.js +446 -0
- package/test/tools/copy.test.js +22 -14
- package/test/tools/copybase.test.js +93 -0
- package/test/tools/copyclip.test.js +92 -0
- package/test/tools/cornerEntity.test.js +201 -0
- package/test/tools/cutclip.test.js +94 -0
- package/test/tools/distance.test.js +140 -18
- package/test/tools/erase.test.js +12 -12
- package/test/tools/explode.test.js +45 -0
- package/test/tools/extend.test.js +326 -44
- package/test/tools/fillet.test.js +831 -0
- package/test/tools/identify.test.js +115 -16
- package/test/tools/matchProp.test.js +84 -0
- package/test/tools/mirror.test.js +475 -0
- package/test/tools/move.test.js +75 -19
- package/test/tools/offset.test.js +748 -0
- package/test/tools/pan.test.js +72 -0
- package/test/tools/pasteclip.test.js +100 -0
- package/test/tools/purge.test.js +89 -0
- package/test/tools/rotate.test.js +89 -23
- package/test/tools/scale.test.js +529 -0
- package/test/tools/trim.test.js +419 -84
- package/test/tools/zoom.test.js +504 -0
- package/core/entities/alignedDimension.js +0 -279
- package/core/entities/angularDimension.js +0 -194
- package/core/entities/baseDimension.js +0 -227
- package/core/entities/block.js +0 -247
- package/core/entities/diametricDimension.js +0 -133
- package/core/entities/dimension.js +0 -202
- package/core/entities/radialDimension.js +0 -126
- package/core/styles/dimStyle.js +0 -719
- package/core/styles/dimStyleManager.js +0 -47
- package/core/styles/layer.js +0 -133
- package/core/styles/layerManager.js +0 -40
- package/core/styles/ltype.js +0 -86
- package/core/styles/ltypeManager.js +0 -50
- package/core/styles/style.js +0 -158
- package/core/styles/styleManager.js +0 -43
- package/core/styles/styleManagerBase.js +0 -299
- package/test/entities/block.test.js +0 -22
- package/test/styles/dimstyle.test.js +0 -19
- package/test/styles/layerManager.test.js +0 -150
- package/test/styles/style.test.js +0 -33
- package/test/styles/stylemanagerbase.test.js +0 -219
|
@@ -1,20 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { DesignCore } from '../designCore.js';
|
|
2
|
+
import { Point } from '../entities/point.js';
|
|
3
|
+
import { Colours } from './colours.js';
|
|
4
4
|
|
|
5
|
+
/** SelectionWindow Class */
|
|
5
6
|
export class SelectionWindow {
|
|
7
|
+
/**
|
|
8
|
+
* Create a SelectionWindow
|
|
9
|
+
* @param {Object} data
|
|
10
|
+
*/
|
|
6
11
|
constructor(data) {
|
|
7
|
-
this.colour =
|
|
12
|
+
this.colour = DesignCore.Settings.selectionWindow;
|
|
8
13
|
this.lineWidth = 1;
|
|
9
14
|
this.dashPattern = [];
|
|
10
15
|
|
|
11
16
|
if (data) {
|
|
12
|
-
if (data.points) {
|
|
17
|
+
if (data.hasOwnProperty('points')) {
|
|
13
18
|
if (data.points[1].y > data.points[0].y) {
|
|
14
|
-
this.colour =
|
|
19
|
+
this.colour = DesignCore.Settings.selectionWindow;
|
|
15
20
|
this.dashPattern = [5];
|
|
16
21
|
} else {
|
|
17
|
-
this.colour =
|
|
22
|
+
this.colour = DesignCore.Settings.crossingWindow;
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
this.points = [];
|
|
@@ -27,7 +32,11 @@ export class SelectionWindow {
|
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
34
|
|
|
30
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Draw the entity
|
|
37
|
+
* @param {Object} ctx - context
|
|
38
|
+
* @param {number} scale
|
|
39
|
+
*/
|
|
31
40
|
draw(ctx, scale) {
|
|
32
41
|
const colour = this.colour;
|
|
33
42
|
ctx.fillStyle = colour;
|
|
@@ -35,7 +44,8 @@ export class SelectionWindow {
|
|
|
35
44
|
const scaledPattern = this.dashPattern.map((x) => x / scale);
|
|
36
45
|
|
|
37
46
|
try { // HTML Canvas
|
|
38
|
-
ctx.strokeStyle = colour;
|
|
47
|
+
ctx.strokeStyle = Colours.rgbToString(colour);
|
|
48
|
+
ctx.fillStyle = Colours.rgbToString(colour);
|
|
39
49
|
ctx.lineWidth = this.lineWidth / scale;
|
|
40
50
|
ctx.beginPath();
|
|
41
51
|
ctx.globalAlpha = 0.2;
|
|
@@ -48,7 +58,7 @@ export class SelectionWindow {
|
|
|
48
58
|
ctx.stroke();
|
|
49
59
|
} catch { // Cairo
|
|
50
60
|
ctx.setLineWidth(this.lineWidth / scale);
|
|
51
|
-
const rgbColour = Colours.
|
|
61
|
+
const rgbColour = Colours.rgbToScaledRGB(colour);
|
|
52
62
|
ctx.setSourceRGBA(rgbColour.r, rgbColour.g, rgbColour.b, 0.2);
|
|
53
63
|
this.drawRect(ctx);
|
|
54
64
|
ctx.fillPreserve();
|
|
@@ -59,6 +69,10 @@ export class SelectionWindow {
|
|
|
59
69
|
}
|
|
60
70
|
}
|
|
61
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Draw a rectangle
|
|
74
|
+
* @param {Object} ctx
|
|
75
|
+
*/
|
|
62
76
|
drawRect(ctx) {
|
|
63
77
|
ctx.moveTo(this.points[0].x, this.points[0].y);
|
|
64
78
|
ctx.lineTo(this.points[1].x, this.points[0].y);
|
package/core/lib/settings.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import {DesignCore} from '../designCore.js';
|
|
1
|
+
import { DesignCore } from '../designCore.js';
|
|
2
2
|
|
|
3
|
+
/** Settings Class */
|
|
3
4
|
export class Settings {
|
|
4
|
-
/**
|
|
5
|
-
* Settings Constructor
|
|
6
|
-
*/
|
|
5
|
+
/** Create Setting */
|
|
7
6
|
constructor() {
|
|
8
|
-
this.canvasbackgroundcolour =
|
|
9
|
-
this.selecteditemscolour =
|
|
10
|
-
this.snapcolour =
|
|
11
|
-
this.gridcolour =
|
|
12
|
-
this.helpergeometrycolour =
|
|
13
|
-
this.polarsnapcolour =
|
|
7
|
+
this.canvasbackgroundcolour = { r: 30, g: 30, b: 30 };
|
|
8
|
+
this.selecteditemscolour = { r: 0, g: 255, b: 0 };
|
|
9
|
+
this.snapcolour = { r: 255, g: 0, b: 0 };
|
|
10
|
+
this.gridcolour = { r: 119, g: 118, b: 123 };
|
|
11
|
+
this.helpergeometrycolour = { r: 0, g: 195, b: 255 };
|
|
12
|
+
this.polarsnapcolour = { r: 55, g: 180, b: 75 };
|
|
13
|
+
this.selectionWindow = { r: 0, g: 255, b: 0 };
|
|
14
|
+
this.crossingWindow = { r: 0, g: 0, b: 255 };
|
|
14
15
|
// fontSettings
|
|
15
16
|
this.font = 'Arial';
|
|
16
17
|
this.fontupsidedown = false;
|
|
@@ -36,6 +37,12 @@ export class Settings {
|
|
|
36
37
|
// TODO: Check setting is valid
|
|
37
38
|
this[setting] = value;
|
|
38
39
|
|
|
40
|
+
// polar and ortho are mutually exclusive — enabling one disables the other
|
|
41
|
+
if (value === true) {
|
|
42
|
+
if (setting === 'polar') this.ortho = false;
|
|
43
|
+
else if (setting === 'ortho') this.polar = false;
|
|
44
|
+
}
|
|
45
|
+
|
|
39
46
|
if (DesignCore.instance) {
|
|
40
47
|
DesignCore.Canvas.requestPaint();
|
|
41
48
|
}
|
|
@@ -44,7 +51,7 @@ export class Settings {
|
|
|
44
51
|
/**
|
|
45
52
|
* Returns the value of the setting
|
|
46
53
|
* @param {string} setting
|
|
47
|
-
* @
|
|
54
|
+
* @return {string}
|
|
48
55
|
*/
|
|
49
56
|
getSetting(setting) {
|
|
50
57
|
// TODO: Validate setting exists
|
package/core/lib/snapping.js
CHANGED
|
@@ -1,24 +1,34 @@
|
|
|
1
1
|
|
|
2
|
-
import {Point} from '../entities/point.js';
|
|
3
|
-
import {Colours} from './colours.js';
|
|
4
|
-
import {Utils} from './utils.js';
|
|
2
|
+
import { Point } from '../entities/point.js';
|
|
3
|
+
import { Colours } from './colours.js';
|
|
4
|
+
import { Utils } from './utils.js';
|
|
5
5
|
|
|
6
|
-
import {DesignCore} from '../designCore.js';
|
|
6
|
+
import { DesignCore } from '../designCore.js';
|
|
7
7
|
|
|
8
|
+
/** SnapPoint Class */
|
|
8
9
|
class SnapPoint {
|
|
10
|
+
/**
|
|
11
|
+
* Create SnapPoint
|
|
12
|
+
* @param {Point} snapPoint
|
|
13
|
+
*/
|
|
9
14
|
constructor(snapPoint) {
|
|
10
15
|
this.snapPoint = snapPoint;
|
|
11
16
|
}
|
|
12
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Draw the entity
|
|
20
|
+
* @param {Object} ctx - context
|
|
21
|
+
* @param {number} scale
|
|
22
|
+
*/
|
|
13
23
|
draw(ctx, scale) {
|
|
14
|
-
const snapColour = DesignCore.Settings.snapcolour
|
|
24
|
+
const snapColour = DesignCore.Settings.snapcolour;
|
|
15
25
|
const radius = 4;
|
|
16
26
|
|
|
17
27
|
try { // HTML Canvas
|
|
18
|
-
ctx.
|
|
28
|
+
ctx.fillStyle = Colours.rgbToString(snapColour);
|
|
19
29
|
ctx.beginPath();
|
|
20
30
|
} catch { // Cairo
|
|
21
|
-
const rgbColour = Colours.
|
|
31
|
+
const rgbColour = Colours.rgbToScaledRGB(snapColour);
|
|
22
32
|
ctx.setSourceRGB(rgbColour.r, rgbColour.g, rgbColour.b);
|
|
23
33
|
}
|
|
24
34
|
|
|
@@ -27,14 +37,103 @@ class SnapPoint {
|
|
|
27
37
|
}
|
|
28
38
|
}
|
|
29
39
|
|
|
40
|
+
/** TrackingLine Class - dotted tracking line for polar/ortho snap */
|
|
41
|
+
class TrackingLine {
|
|
42
|
+
/**
|
|
43
|
+
* Create TrackingLine
|
|
44
|
+
* @param {Point} inputPoint - the previous input point (line passes through this)
|
|
45
|
+
* @param {Point} snapPoint - the current snapped mouse point (direction reference)
|
|
46
|
+
*/
|
|
47
|
+
constructor(inputPoint, snapPoint) {
|
|
48
|
+
this.inputPoint = inputPoint;
|
|
49
|
+
this.snapPoint = snapPoint;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Draw the tracking line, extended to the visible canvas edges
|
|
54
|
+
* @param {Object} ctx - context
|
|
55
|
+
* @param {number} scale
|
|
56
|
+
*/
|
|
57
|
+
draw(ctx, scale) {
|
|
58
|
+
const from = this.inputPoint;
|
|
59
|
+
const dir = this.snapPoint.subtract(from);
|
|
60
|
+
|
|
61
|
+
if (dir.x === 0 && dir.y === 0) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Compute visible canvas bounds in scene space
|
|
66
|
+
const w = DesignCore.Canvas.width;
|
|
67
|
+
const h = DesignCore.Canvas.height;
|
|
68
|
+
const corner0 = DesignCore.Mouse.transformToScene(new Point(0, 0));
|
|
69
|
+
const corner1 = DesignCore.Mouse.transformToScene(new Point(w, h));
|
|
70
|
+
const boundsMin = corner0.min(corner1);
|
|
71
|
+
const boundsMax = corner0.max(corner1);
|
|
72
|
+
|
|
73
|
+
// Clip the infinite line (through 'from' in direction dir) to canvas bounds
|
|
74
|
+
let tMin = -Infinity;
|
|
75
|
+
let tMax = Infinity;
|
|
76
|
+
|
|
77
|
+
if (dir.x !== 0) {
|
|
78
|
+
const tx1 = (boundsMin.x - from.x) / dir.x;
|
|
79
|
+
const tx2 = (boundsMax.x - from.x) / dir.x;
|
|
80
|
+
tMin = Math.max(tMin, Math.min(tx1, tx2));
|
|
81
|
+
tMax = Math.min(tMax, Math.max(tx1, tx2));
|
|
82
|
+
} else if (from.x < boundsMin.x || from.x > boundsMax.x) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (dir.y !== 0) {
|
|
87
|
+
const ty1 = (boundsMin.y - from.y) / dir.y;
|
|
88
|
+
const ty2 = (boundsMax.y - from.y) / dir.y;
|
|
89
|
+
tMin = Math.max(tMin, Math.min(ty1, ty2));
|
|
90
|
+
tMax = Math.min(tMax, Math.max(ty1, ty2));
|
|
91
|
+
} else if (from.y < boundsMin.y || from.y > boundsMax.y) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (tMax < tMin) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const start = from.add(dir.scale(tMin));
|
|
100
|
+
const end = from.add(dir.scale(tMax));
|
|
101
|
+
|
|
102
|
+
const lineColour = DesignCore.Settings.polarsnapcolour;
|
|
103
|
+
const dashSize = 4 / scale;
|
|
104
|
+
|
|
105
|
+
ctx.save();
|
|
106
|
+
|
|
107
|
+
try { // HTML Canvas
|
|
108
|
+
ctx.beginPath();
|
|
109
|
+
ctx.strokeStyle = Colours.rgbToString(lineColour);
|
|
110
|
+
ctx.lineWidth = 1 / scale;
|
|
111
|
+
ctx.setLineDash([dashSize, dashSize]);
|
|
112
|
+
} catch { // Cairo
|
|
113
|
+
const rgbColour = Colours.rgbToScaledRGB(lineColour);
|
|
114
|
+
ctx.setSourceRGB(rgbColour.r, rgbColour.g, rgbColour.b);
|
|
115
|
+
ctx.setLineWidth(1 / scale);
|
|
116
|
+
ctx.setDash([dashSize, dashSize], 0);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
ctx.moveTo(start.x, start.y);
|
|
120
|
+
ctx.lineTo(end.x, end.y);
|
|
121
|
+
ctx.stroke();
|
|
122
|
+
|
|
123
|
+
ctx.restore();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Snapping Class */
|
|
30
128
|
export class Snapping {
|
|
129
|
+
/** Create snapping */
|
|
31
130
|
constructor() {
|
|
32
131
|
this.active = false;
|
|
33
132
|
}
|
|
34
133
|
|
|
35
134
|
/**
|
|
36
135
|
* Get snap point and draw to the scene
|
|
37
|
-
* @
|
|
136
|
+
* @return {Point} or undefined
|
|
38
137
|
*/
|
|
39
138
|
snap() {
|
|
40
139
|
if (this.active) {
|
|
@@ -54,28 +153,37 @@ export class Snapping {
|
|
|
54
153
|
*/
|
|
55
154
|
addSnapPoint(snapPoint) {
|
|
56
155
|
// show the snap point
|
|
57
|
-
DesignCore.Scene.
|
|
156
|
+
DesignCore.Scene.auxiliaryEntities.add(new SnapPoint(snapPoint));
|
|
58
157
|
|
|
59
158
|
// Move the mouse to the closest snap point so if the mouse if clicked the snap point is used.
|
|
60
159
|
DesignCore.Mouse.setPosFromScenePoint(snapPoint);
|
|
61
160
|
}
|
|
62
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Add a tracking line for polar/ortho snap to the scene
|
|
164
|
+
* @param {Point} inputPoint - previous input point the line passes through
|
|
165
|
+
* @param {Point} snapPoint - current snapped mouse position (defines direction)
|
|
166
|
+
*/
|
|
167
|
+
addTrackingLine(inputPoint, snapPoint) {
|
|
168
|
+
DesignCore.Scene.auxiliaryEntities.add(new TrackingLine(inputPoint, snapPoint));
|
|
169
|
+
}
|
|
170
|
+
|
|
63
171
|
/**
|
|
64
172
|
* Get the closest snap point
|
|
65
|
-
* @
|
|
173
|
+
* @return {Point} or undefined
|
|
66
174
|
*/
|
|
67
175
|
getSnapPoint() {
|
|
68
176
|
let snapPoint;
|
|
69
177
|
let delta = 25 / DesignCore.Canvas.getScale(); // find a more suitable starting value
|
|
70
178
|
|
|
71
|
-
for (let i = 0; i <DesignCore.Scene.
|
|
72
|
-
const layer = DesignCore.LayerManager.
|
|
179
|
+
for (let i = 0; i < DesignCore.Scene.entities.count(); i++) {
|
|
180
|
+
const layer = DesignCore.LayerManager.getItemByName(DesignCore.Scene.entities.get(i).layer);
|
|
73
181
|
|
|
74
|
-
if (!layer
|
|
182
|
+
if (!layer?.isVisible) {
|
|
75
183
|
continue;
|
|
76
184
|
}
|
|
77
185
|
|
|
78
|
-
const itemSnaps = DesignCore.Scene.
|
|
186
|
+
const itemSnaps = DesignCore.Scene.entities.get(i).snaps(DesignCore.Mouse.pointOnScene(), delta); // get an array of snap point from the item
|
|
79
187
|
if (itemSnaps) {
|
|
80
188
|
for (let j = 0; j < itemSnaps.length; j++) {
|
|
81
189
|
const length = itemSnaps[j].distance(DesignCore.Mouse.pointOnScene());
|
|
@@ -93,7 +201,7 @@ export class Snapping {
|
|
|
93
201
|
/**
|
|
94
202
|
* Get the polar snap point from the current mouse position
|
|
95
203
|
* @param {Point} previousPoint
|
|
96
|
-
* @
|
|
204
|
+
* @return {Point} or undefined
|
|
97
205
|
*/
|
|
98
206
|
polarSnap(previousPoint) {
|
|
99
207
|
if (!this.active) {
|
|
@@ -120,7 +228,7 @@ export class Snapping {
|
|
|
120
228
|
/**
|
|
121
229
|
* Get the ortho snap point from the current mouse position
|
|
122
230
|
* @param {Point} previousPoint
|
|
123
|
-
* @
|
|
231
|
+
* @return {Point} or undefined
|
|
124
232
|
*/
|
|
125
233
|
orthoSnap(previousPoint) {
|
|
126
234
|
if (!this.active) {
|
|
@@ -128,13 +236,13 @@ export class Snapping {
|
|
|
128
236
|
}
|
|
129
237
|
|
|
130
238
|
let snapPoint;
|
|
131
|
-
const
|
|
132
|
-
const
|
|
239
|
+
const mousePoint = DesignCore.Mouse.pointOnScene();
|
|
240
|
+
const delta = mousePoint.subtract(previousPoint);
|
|
133
241
|
|
|
134
|
-
if (Math.abs(x) > Math.abs(y)) {
|
|
135
|
-
snapPoint = new Point(
|
|
242
|
+
if (Math.abs(delta.x) > Math.abs(delta.y)) {
|
|
243
|
+
snapPoint = new Point(mousePoint.x, previousPoint.y);
|
|
136
244
|
} else {
|
|
137
|
-
snapPoint = new Point(previousPoint.x,
|
|
245
|
+
snapPoint = new Point(previousPoint.x, mousePoint.y);
|
|
138
246
|
}
|
|
139
247
|
return snapPoint;
|
|
140
248
|
}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State Manager Class
|
|
3
|
+
* Manages the history of states for undo/redo functionality
|
|
4
|
+
*
|
|
5
|
+
* The design of this class is based on a command design pattern.
|
|
6
|
+
* The commands consist of Add, Remove and Update.
|
|
7
|
+
* Each command has a do() and undo() method to perform and revert the action respectively.
|
|
8
|
+
*/
|
|
9
|
+
export class StateManager {
|
|
10
|
+
#history = [];
|
|
11
|
+
#historyIndex = 0;
|
|
12
|
+
#maxHistoryStates = 10;
|
|
13
|
+
#isModified = false;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Create StateManager
|
|
17
|
+
* @param {EntityManager} entityManager
|
|
18
|
+
*/
|
|
19
|
+
constructor() {
|
|
20
|
+
this.stateCallbackFunction;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Add a new state to the history
|
|
25
|
+
* state: instance of State (AddState, RemoveState, UpdateState)
|
|
26
|
+
* @param {State} state
|
|
27
|
+
* */
|
|
28
|
+
addState(state) {
|
|
29
|
+
// Remove all future states
|
|
30
|
+
if (this.#historyIndex < this.#history.length && this.#historyIndex !== -1) {
|
|
31
|
+
this.#history.splice(this.#historyIndex);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Add the new state and increment the index
|
|
35
|
+
this.#history.push(state);
|
|
36
|
+
this.#historyIndex++;
|
|
37
|
+
|
|
38
|
+
this.limitHistory();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Limit the history to the maximum number of states */
|
|
42
|
+
limitHistory() {
|
|
43
|
+
while (this.#history.length > this.#maxHistoryStates) {
|
|
44
|
+
this.#history.shift();
|
|
45
|
+
this.#historyIndex--;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Get the previous state
|
|
51
|
+
* @return {State}
|
|
52
|
+
* */
|
|
53
|
+
getPreviousState() {
|
|
54
|
+
return this.#history[this.#historyIndex - 1];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Get the current state
|
|
59
|
+
* @return {State}
|
|
60
|
+
* */
|
|
61
|
+
getCurrentState() {
|
|
62
|
+
return this.#history[this.#historyIndex];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get the next state
|
|
67
|
+
* @return {State}
|
|
68
|
+
* */
|
|
69
|
+
getNextState() {
|
|
70
|
+
return this.#history[this.#historyIndex + 1];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Clear the history */
|
|
74
|
+
clearHistory() {
|
|
75
|
+
this.#history = [];
|
|
76
|
+
this.#historyIndex = 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Get the length of the history
|
|
81
|
+
* @return {number}
|
|
82
|
+
* */
|
|
83
|
+
getHistoryLength() {
|
|
84
|
+
return this.#history.length;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Commit a set of state changes
|
|
89
|
+
* @param {EntityManager} entityManger
|
|
90
|
+
* @param {Array} stateChanges
|
|
91
|
+
*/
|
|
92
|
+
commit(entityManger, stateChanges) {
|
|
93
|
+
const state = new State(entityManger, stateChanges);
|
|
94
|
+
this.addState(state);
|
|
95
|
+
state.do();
|
|
96
|
+
this.stateChanged();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Undo the last action */
|
|
100
|
+
undo() {
|
|
101
|
+
const lastState = this.getPreviousState();
|
|
102
|
+
|
|
103
|
+
if (lastState) {
|
|
104
|
+
lastState.undo();
|
|
105
|
+
this.#historyIndex--;
|
|
106
|
+
this.stateChanged();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Redo the last undone action */
|
|
111
|
+
redo() {
|
|
112
|
+
if (this.#historyIndex < this.#history.length) {
|
|
113
|
+
const currentState = this.getCurrentState();
|
|
114
|
+
|
|
115
|
+
if (currentState) {
|
|
116
|
+
currentState.do();
|
|
117
|
+
this.#historyIndex++;
|
|
118
|
+
this.stateChanged();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Check if undo is possible
|
|
125
|
+
* @return {boolean} true if undo is possible
|
|
126
|
+
* */
|
|
127
|
+
canUndo() {
|
|
128
|
+
return this.#historyIndex > 0;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Check if redo is possible
|
|
133
|
+
* @return {boolean} true if redo is possible
|
|
134
|
+
* */
|
|
135
|
+
canRedo() {
|
|
136
|
+
return this.#historyIndex < this.#history.length;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Get the modified state */
|
|
140
|
+
get isModified() {
|
|
141
|
+
return this.#isModified;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Set the state changed callback function
|
|
146
|
+
* @param {function} callback
|
|
147
|
+
*/
|
|
148
|
+
setStateCallbackFunction(callback) {
|
|
149
|
+
this.stateCallbackFunction = callback;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Set the modified state
|
|
154
|
+
* @param {boolean} isModified
|
|
155
|
+
*/
|
|
156
|
+
stateChanged(isModified=true) {
|
|
157
|
+
this.#isModified = isModified;
|
|
158
|
+
|
|
159
|
+
if (this.stateCallbackFunction) {
|
|
160
|
+
this.stateCallbackFunction();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Base State Class */
|
|
166
|
+
class State {
|
|
167
|
+
/**
|
|
168
|
+
* Create State
|
|
169
|
+
* @param {EntityManager} entityManager
|
|
170
|
+
* @param {Array} stateChanges
|
|
171
|
+
* */
|
|
172
|
+
constructor(entityManager, stateChanges) {
|
|
173
|
+
this.entityManager = entityManager;
|
|
174
|
+
this.stateChanges = stateChanges;
|
|
175
|
+
this.undoStateChanges = [];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Perform the state changes */
|
|
179
|
+
do() {
|
|
180
|
+
this.undoStateChanges = [];
|
|
181
|
+
for (const stateChange of this.stateChanges) {
|
|
182
|
+
if (stateChange instanceof AddState) {
|
|
183
|
+
this.entityManager.add(stateChange.entity);
|
|
184
|
+
const undoStateChange = new RemoveState(stateChange.entity, {});
|
|
185
|
+
this.undoStateChanges.push(undoStateChange);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (stateChange instanceof RemoveState) {
|
|
189
|
+
const index = this.entityManager.indexOf(stateChange.entity);
|
|
190
|
+
if (index !== -1) {
|
|
191
|
+
this.entityManager.remove(index);
|
|
192
|
+
const undoStateChange = new AddState(stateChange.entity, {});
|
|
193
|
+
this.undoStateChanges.push(undoStateChange);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (stateChange instanceof UpdateState) {
|
|
198
|
+
const index = this.entityManager.indexOf(stateChange.entity);
|
|
199
|
+
if (index !== -1) {
|
|
200
|
+
// capture previous properties for undo
|
|
201
|
+
const previousProperties = {};
|
|
202
|
+
for (const prop of Object.getOwnPropertyNames(stateChange.properties)) {
|
|
203
|
+
previousProperties[prop] = stateChange.entity[prop];
|
|
204
|
+
}
|
|
205
|
+
const undoStateChange = new UpdateState(stateChange.entity, previousProperties);
|
|
206
|
+
this.undoStateChanges.push(undoStateChange);
|
|
207
|
+
|
|
208
|
+
this.entityManager.update(index, stateChange.properties);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** Undo the state changes */
|
|
215
|
+
undo() {
|
|
216
|
+
for (const stateChange of this.undoStateChanges) {
|
|
217
|
+
if (stateChange instanceof AddState) {
|
|
218
|
+
this.entityManager.add(stateChange.entity);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (stateChange instanceof RemoveState) {
|
|
222
|
+
const index = this.entityManager.indexOf(stateChange.entity);
|
|
223
|
+
if (index !== -1) {
|
|
224
|
+
this.entityManager.remove(index);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (stateChange instanceof UpdateState) {
|
|
229
|
+
const index = this.entityManager.indexOf(stateChange.entity);
|
|
230
|
+
if (index !== -1) {
|
|
231
|
+
this.entityManager.update(index, stateChange.properties);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* State Change Base Class
|
|
241
|
+
* Holds an entity and the properties to be changed
|
|
242
|
+
*/
|
|
243
|
+
class StateChange {
|
|
244
|
+
/**
|
|
245
|
+
* Create a state change
|
|
246
|
+
* @param {object} entity
|
|
247
|
+
* @param {object} properties
|
|
248
|
+
*/
|
|
249
|
+
constructor(entity, properties) {
|
|
250
|
+
this.entity = entity;
|
|
251
|
+
this.properties = properties;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** Add State Class */
|
|
256
|
+
export class AddState extends StateChange {
|
|
257
|
+
/**
|
|
258
|
+
* Create Add State
|
|
259
|
+
* @param {object} entity
|
|
260
|
+
* @param {object} properties
|
|
261
|
+
*/
|
|
262
|
+
constructor(entity, properties={}) {
|
|
263
|
+
super(entity, properties);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** Remove State Class */
|
|
268
|
+
export class RemoveState extends StateChange {
|
|
269
|
+
/** Create Remove State
|
|
270
|
+
* @param {object} entity
|
|
271
|
+
* @param {object} properties
|
|
272
|
+
*/
|
|
273
|
+
constructor(entity, properties={}) {
|
|
274
|
+
super(entity, properties);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** Update State Class */
|
|
279
|
+
export class UpdateState extends StateChange {
|
|
280
|
+
/**
|
|
281
|
+
* Create Update State
|
|
282
|
+
* @param {object} entity
|
|
283
|
+
* @param {object} properties
|
|
284
|
+
*/
|
|
285
|
+
constructor(entity, properties) {
|
|
286
|
+
super(entity, properties);
|
|
287
|
+
}
|
|
288
|
+
}
|