@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.
Files changed (254) hide show
  1. package/.eslintrc.json +14 -7
  2. package/.github/workflows/DesignCoreQA.yml +3 -1
  3. package/README.md +11 -4
  4. package/TODO.md +19 -0
  5. package/core/core/core.js +49 -42
  6. package/core/designCore.js +61 -2
  7. package/core/dimensions/alignedDimension.js +142 -0
  8. package/core/dimensions/angularDimension.js +550 -0
  9. package/core/dimensions/baseCircularDimension.js +244 -0
  10. package/core/dimensions/baseDimension.js +558 -0
  11. package/core/dimensions/baseLinearDimension.js +371 -0
  12. package/core/dimensions/diametricDimension.js +82 -0
  13. package/core/dimensions/dimension.js +298 -0
  14. package/core/dimensions/linearDimension.js +29 -0
  15. package/core/dimensions/radialDimension.js +78 -0
  16. package/core/dimensions/rotatedDimension.js +167 -0
  17. package/core/entities/arc.js +314 -60
  18. package/core/entities/arctext.js +642 -0
  19. package/core/entities/basePolyline.js +553 -94
  20. package/core/entities/circle.js +181 -54
  21. package/core/entities/entity.js +154 -74
  22. package/core/entities/hatch.js +807 -0
  23. package/core/entities/insert.js +200 -39
  24. package/core/entities/line.js +196 -134
  25. package/core/entities/lwpolyline.js +21 -44
  26. package/core/entities/point.js +194 -29
  27. package/core/entities/polyline.js +54 -7
  28. package/core/entities/rectangle.js +43 -13
  29. package/core/entities/solid.js +43 -6
  30. package/core/entities/text.js +324 -181
  31. package/core/lib/boundingBox.js +73 -13
  32. package/core/lib/canvas.js +256 -65
  33. package/core/lib/clipboard.js +198 -0
  34. package/core/lib/colour.js +144 -0
  35. package/core/lib/colours.js +367 -301
  36. package/core/lib/commandLine.js +16 -28
  37. package/core/lib/commandManager.js +115 -58
  38. package/core/lib/constants.js +23 -0
  39. package/core/lib/dxf/dxf.js +249 -34
  40. package/core/lib/dxf/dxfFile.js +23 -38
  41. package/core/lib/dxf/dxfIterator.js +17 -5
  42. package/core/lib/dxf/dxfRead.js +23 -7
  43. package/core/lib/dxf/dxfWrite.js +39 -129
  44. package/core/lib/dxf/handleManager.js +97 -0
  45. package/core/lib/dxf/sections/blocks.js +16 -2
  46. package/core/lib/dxf/sections/entities.js +17 -3
  47. package/core/lib/dxf/sections/header.js +10 -1
  48. package/core/lib/dxf/sections/objects.js +36 -0
  49. package/core/lib/dxf/sections/section.js +43 -5
  50. package/core/lib/dxf/sections/tables.js +17 -3
  51. package/core/lib/entityManager.js +178 -0
  52. package/core/lib/fileio.js +14 -4
  53. package/core/lib/headers.js +229 -0
  54. package/core/lib/input.js +46 -0
  55. package/core/lib/inputManager.js +199 -194
  56. package/core/lib/intersect.js +341 -468
  57. package/core/lib/logging.js +25 -1
  58. package/core/lib/matrix.js +6 -8
  59. package/core/lib/mouse.js +24 -79
  60. package/core/lib/patterns.js +690 -0
  61. package/core/lib/promptOptions.js +133 -0
  62. package/core/lib/scene.js +71 -174
  63. package/core/lib/selectionManager.js +74 -48
  64. package/core/lib/selectionWindow.js +24 -10
  65. package/core/lib/settings.js +18 -11
  66. package/core/lib/snapping.js +129 -21
  67. package/core/lib/stateManager.js +288 -0
  68. package/core/lib/strings.js +57 -5
  69. package/core/lib/utils.js +95 -11
  70. package/core/objects/dictionary.js +43 -0
  71. package/core/objects/dictionaryManager.js +80 -0
  72. package/core/properties/dimType.js +117 -0
  73. package/core/properties/flags.js +66 -0
  74. package/core/properties/property.js +26 -0
  75. package/core/properties/propertyManager.js +65 -19
  76. package/core/tables/appId.js +31 -0
  77. package/core/tables/appIdManager.js +44 -0
  78. package/core/tables/block.js +323 -0
  79. package/core/tables/blockManager.js +48 -0
  80. package/core/tables/blockRecord.js +29 -0
  81. package/core/tables/blockRecordManager.js +37 -0
  82. package/core/tables/dimStyle.js +627 -0
  83. package/core/tables/dimStyleManager.js +187 -0
  84. package/core/tables/endblk.js +28 -0
  85. package/core/tables/layer.js +219 -0
  86. package/core/tables/layerManager.js +47 -0
  87. package/core/tables/ltype.js +85 -0
  88. package/core/tables/ltypeManager.js +65 -0
  89. package/core/tables/style.js +145 -0
  90. package/core/tables/styleManager.js +55 -0
  91. package/core/tables/styleManagerBase.js +110 -0
  92. package/core/tables/tableManagerBase.js +354 -0
  93. package/core/tables/ucs.js +28 -0
  94. package/core/tables/ucsManager.js +44 -0
  95. package/core/tables/view.js +28 -0
  96. package/core/tables/viewManager.js +44 -0
  97. package/core/tables/vport.js +70 -0
  98. package/core/tables/vportManager.js +65 -0
  99. package/core/tools/chamfer.js +343 -0
  100. package/core/tools/chamferFilletBase.js +162 -0
  101. package/core/tools/copy.js +68 -40
  102. package/core/tools/copybase.js +65 -0
  103. package/core/tools/copyclip.js +59 -0
  104. package/core/tools/cornerEntity.js +138 -0
  105. package/core/tools/cutclip.js +72 -0
  106. package/core/tools/distance.js +37 -9
  107. package/core/tools/erase.js +43 -13
  108. package/core/tools/explode.js +117 -0
  109. package/core/tools/extend.js +71 -32
  110. package/core/tools/fillet.js +336 -0
  111. package/core/tools/identify.js +33 -6
  112. package/core/tools/matchProp.js +106 -0
  113. package/core/tools/mirror.js +141 -0
  114. package/core/tools/move.js +65 -32
  115. package/core/tools/offset.js +321 -0
  116. package/core/tools/pan.js +54 -0
  117. package/core/tools/pasteclip.js +93 -0
  118. package/core/tools/purge.js +90 -0
  119. package/core/tools/rotate.js +105 -70
  120. package/core/tools/scale.js +166 -0
  121. package/core/tools/tool.js +14 -4
  122. package/core/tools/trim.js +71 -32
  123. package/core/tools/zoom.js +152 -0
  124. package/package.json +3 -305
  125. package/test/dimensions/alignedDimension.test.js +211 -0
  126. package/test/dimensions/angularDimension.test.js +243 -0
  127. package/test/dimensions/baseDimension.test.js +239 -0
  128. package/test/dimensions/diametricDimension.test.js +203 -0
  129. package/test/dimensions/dimension.test.js +102 -0
  130. package/test/dimensions/radialDimension.test.js +203 -0
  131. package/test/dimensions/rotatedDimension.test.js +224 -0
  132. package/test/entities/arc.test.js +463 -41
  133. package/test/entities/arctext.test.js +329 -0
  134. package/test/entities/basePolyline.test.js +459 -10
  135. package/test/entities/circle.test.js +312 -7
  136. package/test/entities/entity.test.js +28 -9
  137. package/test/entities/hatch.test.js +606 -0
  138. package/test/entities/insert.test.js +90 -0
  139. package/test/entities/line.test.js +182 -6
  140. package/test/entities/point.test.js +375 -37
  141. package/test/entities/solid.test.js +156 -0
  142. package/test/entities/text.test.js +533 -7
  143. package/test/integration/exportIntegration.reference.dxf +1706 -0
  144. package/test/integration/exportIntegration.test.js +186 -0
  145. package/test/integration/importExportIntegration.test.js +126 -0
  146. package/test/integration/intersectionIntegration.test.js +880 -0
  147. package/test/integration/userInputIntegration.reference.dxf +1410 -0
  148. package/test/integration/userInputIntegration.test.js +269 -0
  149. package/test/lib/boundingBox.test.js +26 -2
  150. package/test/lib/canvas.test.js +613 -5
  151. package/test/lib/clipboard.test.js +70 -0
  152. package/test/lib/colour.test.js +114 -0
  153. package/test/lib/colours.test.js +63 -18
  154. package/test/lib/commandLine.test.js +159 -22
  155. package/test/lib/commandManager.test.js +4 -4
  156. package/test/lib/constants.test.js +9 -0
  157. package/test/lib/dxf/dxfFile.test.js +6 -2
  158. package/test/lib/dxf/dxfIterator.test.js +1 -1
  159. package/test/lib/dxf/dxfWrite.test.js +173 -0
  160. package/test/lib/dxf/handleManager.test.js +137 -0
  161. package/test/lib/dxf/sections/blocks.test.js +5 -5
  162. package/test/lib/dxf/sections/entities.test.js +4 -4
  163. package/test/lib/dxf/sections/header.test.js +18 -4
  164. package/test/lib/dxf/sections/objects.test.js +132 -0
  165. package/test/lib/dxf/sections/section.test.js +29 -29
  166. package/test/lib/dxf/sections/tables.test.js +3 -3
  167. package/test/lib/entityManager.test.js +163 -0
  168. package/test/lib/headers.test.js +233 -0
  169. package/test/lib/inputManager.test.js +1144 -5
  170. package/test/lib/intersect.test.js +454 -331
  171. package/test/lib/logging.test.js +1 -1
  172. package/test/lib/matrix.test.js +1 -1
  173. package/test/lib/mouse.test.js +327 -4
  174. package/test/lib/patterns.test.js +105 -0
  175. package/test/lib/promptOptions.test.js +179 -0
  176. package/test/lib/scene.test.js +16 -52
  177. package/test/lib/selectionManager.test.js +17 -5
  178. package/test/lib/settings.test.js +111 -5
  179. package/test/lib/snapping.test.js +142 -4
  180. package/test/lib/stateManager.test.js +155 -0
  181. package/test/lib/utils.test.js +81 -1
  182. package/test/objects/dictionary.test.js +81 -0
  183. package/test/objects/dictionaryManager.test.js +34 -0
  184. package/test/properties/dimType.test.js +62 -0
  185. package/test/properties/flags.test.js +164 -0
  186. package/test/properties/property.test.js +13 -0
  187. package/test/properties/propertyManager.test.js +10 -11
  188. package/test/tables/appId.test.js +46 -0
  189. package/test/tables/appIdManager.test.js +72 -0
  190. package/test/tables/block.test.js +157 -0
  191. package/test/tables/blockManager.test.js +52 -0
  192. package/test/tables/blockRecord.test.js +39 -0
  193. package/test/tables/blockRecordManager.test.js +60 -0
  194. package/test/tables/dimstyle.test.js +72 -0
  195. package/test/tables/endblk.test.js +30 -0
  196. package/test/tables/layer.test.js +95 -0
  197. package/test/tables/layerManager.test.js +172 -0
  198. package/test/{styles → tables}/ltype.test.js +7 -7
  199. package/test/{styles → tables}/ltypeManager.test.js +2 -2
  200. package/test/tables/style.test.js +44 -0
  201. package/test/tables/stylemanagerbase.test.js +220 -0
  202. package/test/tables/tableManagerBase.test.js +194 -0
  203. package/test/tables/ucs.test.js +37 -0
  204. package/test/tables/ucsManager.test.js +48 -0
  205. package/test/tables/view.test.js +37 -0
  206. package/test/tables/viewManager.test.js +48 -0
  207. package/test/tables/vport.test.js +117 -0
  208. package/test/tables/vportManager.test.js +54 -0
  209. package/test/test-helpers/test-helpers.js +66 -0
  210. package/test/tools/chamfer.test.js +970 -0
  211. package/test/tools/chamferFilletBase.test.js +446 -0
  212. package/test/tools/copy.test.js +22 -14
  213. package/test/tools/copybase.test.js +93 -0
  214. package/test/tools/copyclip.test.js +92 -0
  215. package/test/tools/cornerEntity.test.js +201 -0
  216. package/test/tools/cutclip.test.js +94 -0
  217. package/test/tools/distance.test.js +140 -18
  218. package/test/tools/erase.test.js +12 -12
  219. package/test/tools/explode.test.js +45 -0
  220. package/test/tools/extend.test.js +326 -44
  221. package/test/tools/fillet.test.js +831 -0
  222. package/test/tools/identify.test.js +115 -16
  223. package/test/tools/matchProp.test.js +84 -0
  224. package/test/tools/mirror.test.js +475 -0
  225. package/test/tools/move.test.js +75 -19
  226. package/test/tools/offset.test.js +748 -0
  227. package/test/tools/pan.test.js +72 -0
  228. package/test/tools/pasteclip.test.js +100 -0
  229. package/test/tools/purge.test.js +89 -0
  230. package/test/tools/rotate.test.js +89 -23
  231. package/test/tools/scale.test.js +529 -0
  232. package/test/tools/trim.test.js +419 -84
  233. package/test/tools/zoom.test.js +504 -0
  234. package/core/entities/alignedDimension.js +0 -279
  235. package/core/entities/angularDimension.js +0 -194
  236. package/core/entities/baseDimension.js +0 -227
  237. package/core/entities/block.js +0 -247
  238. package/core/entities/diametricDimension.js +0 -133
  239. package/core/entities/dimension.js +0 -202
  240. package/core/entities/radialDimension.js +0 -126
  241. package/core/styles/dimStyle.js +0 -719
  242. package/core/styles/dimStyleManager.js +0 -47
  243. package/core/styles/layer.js +0 -133
  244. package/core/styles/layerManager.js +0 -40
  245. package/core/styles/ltype.js +0 -86
  246. package/core/styles/ltypeManager.js +0 -50
  247. package/core/styles/style.js +0 -158
  248. package/core/styles/styleManager.js +0 -43
  249. package/core/styles/styleManagerBase.js +0 -299
  250. package/test/entities/block.test.js +0 -22
  251. package/test/styles/dimstyle.test.js +0 -19
  252. package/test/styles/layerManager.test.js +0 -150
  253. package/test/styles/style.test.js +0 -33
  254. package/test/styles/stylemanagerbase.test.js +0 -219
@@ -1,20 +1,25 @@
1
- import {Point} from '../entities/point.js';
2
- import {Colours} from './colours.js';
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 = '#FF0000';
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 = '#FF0000';
19
+ this.colour = DesignCore.Settings.selectionWindow;
15
20
  this.dashPattern = [5];
16
21
  } else {
17
- this.colour = '#0000FF';
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.hexToScaledRGB(colour);
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);
@@ -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 = '#1e1e1e'; // "#000000";
9
- this.selecteditemscolour = '#00FF00';
10
- this.snapcolour = '#FF0000';
11
- this.gridcolour = '#77767b';
12
- this.helpergeometrycolour = '#00BFFF';
13
- this.polarsnapcolour = '#38B44A';
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
- * @returns
54
+ * @return {string}
48
55
  */
49
56
  getSetting(setting) {
50
57
  // TODO: Validate setting exists
@@ -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.toString();
24
+ const snapColour = DesignCore.Settings.snapcolour;
15
25
  const radius = 4;
16
26
 
17
27
  try { // HTML Canvas
18
- ctx.strokeStyle = snapColour;
28
+ ctx.fillStyle = Colours.rgbToString(snapColour);
19
29
  ctx.beginPath();
20
30
  } catch { // Cairo
21
- const rgbColour = Colours.hexToScaledRGB(snapColour);
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
- * @returns Point or undefined
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.addToAuxiliaryItems(new SnapPoint(snapPoint));
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
- * @returns Point or undefined
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.items.length; i++) {
72
- const layer = DesignCore.LayerManager.getStyleByName(DesignCore.Scene.items[i].layer);
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.isVisible) {
182
+ if (!layer?.isVisible) {
75
183
  continue;
76
184
  }
77
185
 
78
- const itemSnaps = DesignCore.Scene.items[i].snaps(DesignCore.Mouse.pointOnScene(), delta); // get an array of snap point from the item
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
- * @returns Point or undefined
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
- * @returns Point or undefined
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 x = DesignCore.Mouse.pointOnScene().x - previousPoint.x;
132
- const y = DesignCore.Mouse.pointOnScene().y - previousPoint.y;
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(DesignCore.Mouse.pointOnScene().x, previousPoint.y);
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, DesignCore.Mouse.pointOnScene().y);
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
+ }