@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,6 +1,12 @@
1
- import {Point} from '../entities/point.js';
1
+ import { Point } from '../entities/point.js';
2
2
 
3
+ /** BoundingBox Class */
3
4
  export class BoundingBox {
5
+ /**
6
+ * Create BoundingBox
7
+ * @param {Point} firstCorner
8
+ * @param {Point} secondCorner
9
+ */
4
10
  constructor(firstCorner = new Point(), secondCorner = new Point()) {
5
11
  this.pt1 = firstCorner;
6
12
  this.pt2 = secondCorner;
@@ -48,9 +54,32 @@ export class BoundingBox {
48
54
  return this.yMax - this.yMin;
49
55
  }
50
56
 
57
+ /**
58
+ * return bounding box center point
59
+ */
60
+ get centerPoint() {
61
+ return new Point(this.xMin + this.xLength / 2, this.yMin + this.yLength / 2);
62
+ }
63
+
64
+ /**
65
+ * Determine if point is inside bounding box
66
+ * @param {Object} point
67
+ * @return {boolean} true if point is inside false if not
68
+ */
69
+ isInside(point) {
70
+ // get bounding box corners
71
+ const bottomLeft = new Point(this.xMin, this.yMin);
72
+ const bottomRight = new Point(this.xMax, this.yMin);
73
+ const topRight = new Point(this.xMax, this.yMax);
74
+ const topLeft = new Point(this.xMin, this.yMax);
75
+ // check if point is in rectangle
76
+ return point.isInRectangle(bottomLeft, bottomRight, topRight, topLeft);
77
+ }
78
+
51
79
  /**
52
80
  * Return the bounding box for points
53
81
  * @param {Array} points
82
+ * @return {BoundingBox}
54
83
  */
55
84
  static fromPoints(points) {
56
85
  if (!points.length) {
@@ -64,25 +93,56 @@ export class BoundingBox {
64
93
  return new BoundingBox(new Point(xMin, yMin), new Point(xMax, yMax));
65
94
  }
66
95
 
96
+ /**
97
+ * Generate bounding box from entities
98
+ * @param {Array} entities
99
+ * @return {BoundingBox}
100
+ */
101
+ static fromEntities(entities) {
102
+ if (!entities.length) {
103
+ return;
104
+ }
105
+
106
+ let xmin = Infinity;
107
+ let xmax = -Infinity;
108
+ let ymin = Infinity;
109
+ let ymax = -Infinity;
110
+
111
+ for (const ent of entities) {
112
+ const bbox = ent.boundingBox();
113
+
114
+ if (!bbox) {
115
+ continue;
116
+ }
117
+
118
+ xmin = Math.min(xmin, bbox.xMin);
119
+ xmax = Math.max(xmax, bbox.xMax);
120
+ ymin = Math.min(ymin, bbox.yMin);
121
+ ymax = Math.max(ymax, bbox.yMax);
122
+ }
123
+
124
+ return new BoundingBox(new Point(xmin, ymin), new Point(xmax, ymax));
125
+ }
126
+
67
127
  /**
68
128
  * Calculate the boundingbox for a line
69
- * @param {point} startPoint
70
- * @param {point} endPoint
71
- * @returns - BoundingBox
129
+ * @param {Point} startPoint
130
+ * @param {Point} endPoint
131
+ * @return {BoundingBox}
72
132
  */
73
- static lineBoundingBox( startPoint, endPoint) {
133
+ static lineBoundingBox(startPoint, endPoint) {
74
134
  return new BoundingBox(startPoint, endPoint);
75
135
  }
76
136
 
77
137
  /**
78
138
  * Calculate the boundingbox for an arc
79
- * @param {point} centerPoint
80
- * @param {point} startPoint
81
- * @param {point} endPoint
139
+ * @param {Point} centerPoint
140
+ * @param {Point} startPoint
141
+ * @param {Point} endPoint
82
142
  * @param {number} direction - ccw > 0, cw < 0
83
- * @returns - BoundingBox
143
+ * @return {BoundingBox}
84
144
  */
85
- static arcBoundingBox(centerPoint, startPoint, endPoint, direction=1) {
145
+ static arcBoundingBox(centerPoint, startPoint, endPoint, direction = 1) {
86
146
  const startAngle = centerPoint.angle(startPoint);
87
147
  const endAngle = centerPoint.angle(endPoint);
88
148
  const radius = centerPoint.distance(startPoint);
@@ -122,12 +182,12 @@ export class BoundingBox {
122
182
  * @param {number} endAngle - angle in radians
123
183
  * @param {number} axisAngle - angle in radians. i.e 90 deg = Math.PI / 2.
124
184
  * @param {number} direction - ccw > 0, cw < 0
125
- * @returns bool
185
+ * @return {boolean}
126
186
  */
127
- static crossesAxis(startAngle, endAngle, axisAngle, direction=1) {
187
+ static crossesAxis(startAngle, endAngle, axisAngle, direction = 1) {
128
188
  const circle = Math.PI * 2;
129
189
  const referenceStartAngle = (startAngle - axisAngle + circle) % circle;
130
- const referenceEndAngle = (endAngle - axisAngle + circle ) % circle;
190
+ const referenceEndAngle = (endAngle - axisAngle + circle) % circle;
131
191
 
132
192
  // if refStartAngle > refEndAngle then the arc crosses the axis
133
193
  let crosses = referenceStartAngle >= referenceEndAngle;
@@ -1,10 +1,16 @@
1
- import {Matrix} from './matrix.js';
2
- import {Colours} from './colours.js';
3
- import {Point} from '../entities/point.js';
1
+ import { Matrix } from './matrix.js';
2
+ import { Colours } from './colours.js';
3
+ import { Point } from '../entities/point.js';
4
+ import { Input } from './input.js';
4
5
 
5
- import {DesignCore} from '../designCore.js';
6
+ import { DesignCore } from '../designCore.js';
6
7
 
8
+ /** Canvas Class */
7
9
  export class Canvas {
10
+ #panCursorTimeout;
11
+ #baseCursorState = 'DEFAULT';
12
+
13
+ /** Create Canvas */
8
14
  constructor() {
9
15
  this.cvs = null;
10
16
  this.matrix = new Matrix();
@@ -19,38 +25,101 @@ export class Canvas {
19
25
  this.lastDelta = new Point();
20
26
  this.flipped = false;
21
27
 
28
+ this.paintState;
29
+
30
+ this.paintStates = {
31
+ ENTITIES: 'ENTITIES',
32
+ TEMPORARY: 'TEMPORARY',
33
+ SELECTED: 'SELECTED',
34
+ AUXILLARY: 'AUXILLARY',
35
+ };
36
+
37
+ this.cursorStates = Input.Cursor;
38
+
39
+ this.cursorState = Input.Cursor.DEFAULT;
40
+ this.#baseCursorState = Input.Cursor.DEFAULT;
41
+
22
42
  // function to call external pain command for the ui
23
43
  this.externalPaintCallbackFunction;
44
+ this.externalCursorCallbackFunction;
24
45
  }
25
46
 
47
+ /**
48
+ * Get canvas scale
49
+ * @return {number}
50
+ */
26
51
  getScale() {
27
52
  return this.matrix.getScale();
28
53
  }
29
54
 
55
+ /**
56
+ * Set external paint callback
57
+ * This is called when painting is required
58
+ * @param {Object} callback
59
+ */
30
60
  setExternalPaintCallbackFunction(callback) {
31
61
  // set the callback
32
62
  this.externalPaintCallbackFunction = callback;
33
63
  }
34
64
 
35
- setCanvasWidget(cnvs) {
36
- this.cvs = cnvs;
65
+ /**
66
+ * Set external cursor callback
67
+ * Called when the cursor state changes.
68
+ * Pass undefined or null to unregister the callback.
69
+ * @param {Function|undefined|null} callback
70
+ */
71
+ setCursorCallbackFunction(callback) {
72
+ this.externalCursorCallbackFunction = callback;
37
73
  }
38
74
 
75
+ /**
76
+ * Update the cursor state and notify the UI
77
+ * @param {string} state - one of this.cursorStates
78
+ */
79
+ #setCursor(state) {
80
+ if (this.cursorState === state) return;
81
+ this.cursorState = state;
82
+ this.externalCursorCallbackFunction?.(state);
83
+ }
84
+
85
+ /**
86
+ * Set the cursor based on the input types requested by a command prompt.
87
+ * If a cursorHint is provided it is used directly; otherwise the cursor is
88
+ * derived from the cursor property of each type (first non-null wins),
89
+ * falling back to DEFAULT.
90
+ * @param {Array} types - array of Input.Type values
91
+ * @param {string|null} cursorHint - optional override from PromptOptions.cursor
92
+ */
93
+ setCursorForInputTypes(types, cursorHint = null) {
94
+ this.#baseCursorState = cursorHint ??
95
+ types.map((t) => t.cursor).find(Boolean) ??
96
+ Input.Cursor.DEFAULT;
97
+ this.#setCursor(this.#baseCursorState);
98
+ }
99
+
100
+ /**
101
+ * Handle mouse movement
102
+ */
39
103
  mouseMoved() {
40
104
  if (DesignCore.Mouse.buttonTwoDown) {
41
105
  this.pan();
106
+ return;
42
107
  }
43
108
 
44
109
  DesignCore.Scene.inputManager.mouseMoved();
45
110
  }
46
111
 
112
+ /**
113
+ * Handle mouse downs
114
+ * @param {number} button
115
+ */
47
116
  mouseDown(button) {
48
117
  switch (button) {
49
118
  case 0: // left button
50
119
  break;
51
120
  case 1: // middle button
52
- // TODO: Reenable cursor styles
53
- // ev.target.style.cursor = "move";
121
+ clearTimeout(this.#panCursorTimeout);
122
+ this.#panCursorTimeout = setTimeout(() => this.#setCursor(Input.Cursor.GRABBING), 250);
54
123
  break;
55
124
  case 2: // right button
56
125
  break;
@@ -59,14 +128,19 @@ export class Canvas {
59
128
  DesignCore.Scene.inputManager.mouseDown(button);
60
129
  };
61
130
 
131
+ /**
132
+ * Handle mouse up
133
+ * @param {number} button
134
+ */
62
135
  mouseUp(button) {
63
136
  switch (button) {
64
- case 0: // left buttonbreak;
137
+ case 0: // left button
138
+ break;
65
139
  case 1: // middle button
140
+ clearTimeout(this.#panCursorTimeout);
66
141
  this.lastDelta = new Point();
67
142
  this.requestPaint();
68
- // TODO: Reenable cursor styles
69
- // ev.target.style.cursor = "crosshair";
143
+ this.#setCursor(this.#baseCursorState);
70
144
  break;
71
145
  case 2: // right button
72
146
  break;
@@ -75,6 +149,10 @@ export class Canvas {
75
149
  DesignCore.Scene.inputManager.mouseUp(button);
76
150
  };
77
151
 
152
+ /**
153
+ * Handle double click
154
+ * @param {number} button
155
+ */
78
156
  doubleClick(button) {
79
157
  switch (button) {
80
158
  case 0: // left button
@@ -87,6 +165,9 @@ export class Canvas {
87
165
  }
88
166
  };
89
167
 
168
+ /**
169
+ * Pan the canvas
170
+ */
90
171
  pan() {
91
172
  // pandelta: mouse drag distance in scene scale
92
173
  this.panDelta = DesignCore.Mouse.pointOnScene().subtract(DesignCore.Mouse.transformToScene(DesignCore.Mouse.mouseDownCanvasPoint));
@@ -99,13 +180,22 @@ export class Canvas {
99
180
  this.requestPaint();
100
181
  }
101
182
 
183
+ /**
184
+ * Handle mouse wheel - Zoom
185
+ * @param {number} delta
186
+ */
102
187
  wheel(delta) {
188
+ if (DesignCore.Mouse.buttonTwoDown) return;
103
189
  const scale = Math.pow(1 + Math.abs(delta), delta > 0 ? 1 : -1);
104
190
  if (scale < 1 && this.getScale() > this.minScaleFactor || scale > 1 && this.getScale() < this.maxScaleFactor) {
105
191
  this.zoom(scale);
106
192
  }
107
193
  };
108
194
 
195
+ /**
196
+ * Zoom the canvas
197
+ * @param {number} scale
198
+ */
109
199
  zoom(scale) {
110
200
  const zoomPoint = DesignCore.Mouse.pointOnScene();
111
201
  this.matrix.scale(scale, scale);
@@ -113,31 +203,50 @@ export class Canvas {
113
203
  this.requestPaint();
114
204
  }
115
205
 
206
+ /**
207
+ * Zoom to a window
208
+ * @param {Point} pt1
209
+ * @param {Point} pt2
210
+ */
211
+ zoomToWindow(pt1, pt2) {
212
+ const xMin = Math.min(pt1.x, pt2.x);
213
+ const yMin = Math.min(pt1.y, pt2.y);
214
+ const xMax = Math.max(pt1.x, pt2.x);
215
+ const yMax = Math.max(pt1.y, pt2.y);
216
+
217
+ const width = xMax - xMin;
218
+ const height = yMax - yMin;
219
+
220
+ if (width === 0 || height === 0) {
221
+ return;
222
+ }
223
+
224
+ const selectionCenter = new Point(xMin + width / 2, yMin + height / 2);
225
+ const screenCenter = new Point(this.width / 2, this.height / 2);
226
+ const translateDelta = DesignCore.Mouse.transformToScene(screenCenter).subtract(selectionCenter);
227
+ const targetScale = Math.min((this.width / width), (this.height / height));
228
+ const scaleDelta = targetScale / this.getScale() * 0.9;
229
+
230
+ this.matrix.scale(scaleDelta, scaleDelta);
231
+ this.matrix.translate((selectionCenter.x / scaleDelta) - selectionCenter.x, (selectionCenter.y / scaleDelta) - selectionCenter.y);
232
+ this.matrix.translate(translateDelta.x / scaleDelta, translateDelta.y / scaleDelta);
233
+ this.requestPaint();
234
+ }
235
+
236
+ /**
237
+ * Set the zoom to include all scene items
238
+ */
116
239
  zoomExtents() {
117
240
  const extents = DesignCore.Scene.boundingBox();
118
241
 
119
242
  if (extents) {
120
- // calculate the center of all items
121
- const selectionCenter = new Point(extents.xMin + (extents.xLength / 2), extents.yMin + (extents.yLength / 2));
122
- // get the center of the screen transformed to a scene position
123
- const screenCenter = new Point(this.width / 2, this.height / 2);
124
- // calculate the translation delta required to center on screen
125
- const translateDelta = DesignCore.Mouse.transformToScene(screenCenter).subtract(selectionCenter);
126
- // calculate the scale required to fill the screen
127
- const targetScale = Math.min((this.width / extents.xLength), (this.height / extents.yLength));
128
- // calculate the scale delta required to fill 90% of the screen
129
- const scaleDelta = targetScale / this.getScale() * 0.9;
130
- // apply scale
131
- this.matrix.scale(scaleDelta, scaleDelta);
132
- // translate to counteract the scale
133
- this.matrix.translate((selectionCenter.x / scaleDelta) - selectionCenter.x, (selectionCenter.y / scaleDelta) - selectionCenter.y);
134
- // translate to the center of the screen
135
- this.matrix.translate(translateDelta.x / scaleDelta, translateDelta.y / scaleDelta);
136
- // request paint to update
137
- this.requestPaint();
243
+ this.zoomToWindow(new Point(extents.xMin, extents.yMin), new Point(extents.xMax, extents.yMax));
138
244
  }
139
245
  }
140
246
 
247
+ /**
248
+ * Request the canvas is painted
249
+ */
141
250
  requestPaint() {
142
251
  // paint request is passed to an external paint function
143
252
  // This function then calls this.paint(), the canvas paint function
@@ -147,6 +256,12 @@ export class Canvas {
147
256
  }
148
257
  }
149
258
 
259
+ /**
260
+ * Paint the canvas
261
+ * @param {object} context
262
+ * @param {number} width
263
+ * @param {number} height
264
+ */
150
265
  paint(context, width, height) {
151
266
  // This paint request is called by an external paint function
152
267
  // some ui framework create and destroy the context for every paint
@@ -163,12 +278,12 @@ export class Canvas {
163
278
  this.flipped = true;
164
279
  }
165
280
 
166
- // set the tranform for the context
281
+ // set the transform for the context
167
282
  // this will set all the pan and zoom actions
168
283
  try {
169
284
  context.setTransform(this.matrix);
170
285
  } catch {
171
- // context.setMatrix(this.matrix)
286
+ // context.setMatrix(this.matrix)
172
287
  context.translate(this.matrix.e, this.matrix.f);
173
288
  context.scale(this.matrix.a, this.matrix.d);
174
289
  }
@@ -179,11 +294,11 @@ export class Canvas {
179
294
  // Paint the scene background
180
295
  try {// HTML
181
296
  // this.clear()
182
- context.fillStyle = DesignCore.Settings.canvasbackgroundcolour;
297
+ context.fillStyle = Colours.rgbToString(DesignCore.Settings.canvasbackgroundcolour);
183
298
  context.fillRect(origin.x, origin.y, width / this.getScale(), height / this.getScale());
184
299
  // context.globalAlpha = this.cvs.alpha
185
300
  } catch { // Cairo
186
- const rgbColour = Colours.hexToScaledRGB(DesignCore.Settings.canvasbackgroundcolour);
301
+ const rgbColour = Colours.rgbToScaledRGB(DesignCore.Settings.canvasbackgroundcolour);
187
302
  context.setSourceRGB(rgbColour.r, rgbColour.g, rgbColour.b);
188
303
  const scaled = new Point(width, height);
189
304
  const sc = DesignCore.Mouse.transformToScene(scaled);
@@ -197,74 +312,140 @@ export class Canvas {
197
312
 
198
313
  this.paintGrid(context, width, height);
199
314
 
315
+ const scale = this.getScale();
316
+
200
317
  // Paint the primary scene items
201
- for (let i = 0; i <DesignCore.Scene.items.length; i++) {
202
- const layer = DesignCore.LayerManager.getStyleByName(DesignCore.Scene.items[i].layer);
318
+ this.paintState = this.paintStates.ENTITIES;
319
+
320
+ const entityCount = DesignCore.Scene.entities.count();
321
+ for (let i = 0; i < entityCount; i++) {
322
+ const entity = DesignCore.Scene.entities.get(i);
323
+ const layer = DesignCore.LayerManager.getItemByName(entity.layer);
203
324
 
204
- if (!layer.isVisible) {
325
+ if (!layer?.isVisible) {
205
326
  continue;
206
327
  }
207
328
 
208
- this.setContext(DesignCore.Scene.items[i], context);
209
- DesignCore.Scene.items[i].draw(context, this.getScale());
329
+ this.setContext(entity, context, undefined, scale);
330
+ entity.draw(context, scale);
210
331
  }
211
332
 
212
333
  // Paint the temporary scene items
213
- for (let j = 0; j <DesignCore.Scene.tempItems.length; j++) {
214
- this.setContext(DesignCore.Scene.tempItems[j], context);
215
- DesignCore.Scene.tempItems[j].draw(context, this.getScale());
334
+ this.paintState = this.paintStates.TEMPORARY;
335
+ const tempCount = DesignCore.Scene.tempEntities.count();
336
+ for (let j = 0; j < tempCount; j++) {
337
+ const entity = DesignCore.Scene.tempEntities.get(j);
338
+ this.setContext(entity, context, undefined, scale);
339
+ entity.draw(context, scale);
216
340
  }
217
341
 
218
342
  // Paint the selected scene items
219
- for (let k = 0; k <DesignCore.Scene.selectionManager.selectedItems.length; k++) {
220
- this.setContext(DesignCore.Scene.selectionManager.selectedItems[k], context);
221
- DesignCore.Scene.selectionManager.selectedItems[k].draw(context, this.getScale());
343
+ this.paintState = this.paintStates.SELECTED;
344
+ const selectedItems = DesignCore.Scene.selectionManager.selectedItems;
345
+ for (let k = 0; k < selectedItems.length; k++) {
346
+ const entity = selectedItems[k];
347
+ this.setContext(entity, context, undefined, scale);
348
+ entity.draw(context, scale);
222
349
  }
223
350
 
224
351
  // Paint the auxiliary scene items
225
352
  // auxiliary items include things like the selection window, snap points etc
226
353
  // these items have their own draw routine
227
- for (let l = 0; l <DesignCore.Scene.auxiliaryItems.length; l++) {
228
- DesignCore.Scene.auxiliaryItems[l].draw(context, this.getScale());
354
+ this.paintState = this.paintStates.AUXILLARY;
355
+ const auxCount = DesignCore.Scene.auxiliaryEntities.count();
356
+ for (let l = 0; l < auxCount; l++) {
357
+ DesignCore.Scene.auxiliaryEntities.get(l).draw(context, scale);
229
358
  }
359
+
360
+ this.paintState = undefined;
230
361
  }
231
362
 
232
363
  /**
233
364
  * Set the scene context
234
365
  * @param {entity} item
235
- * @param {object} context - scene painting context from ui
236
- * @param {string} contextColour - colour to overide item colour
366
+ * @param {Object} context - scene painting context from ui
367
+ * @param {Object} block - insert or dimension element for the current block, required for colour ByBlock
237
368
  */
238
- setContext(item, context) {
239
- const colour = item.getColour();
369
+ setContext(item, context, block = undefined) {
370
+ const scale = this.getScale();
371
+ let colour = item.getDrawColour();
240
372
  const lineType = item.getLineType();
241
- const lineWidth = item.lineWidth / this.getScale();
373
+ let lineWidth = item.lineWidth / scale;
374
+
375
+ if (this.paintState === this.paintStates.SELECTED) {
376
+ // Set Context for selected items
377
+ colour = DesignCore.Core.settings.selecteditemscolour;
378
+ lineWidth = (item.lineWidth * 2) / scale;
379
+ } else if (this.paintState === this.paintStates.TEMPORARY) {
380
+ // Set context for temp items
381
+ lineWidth = (item.lineWidth * 2) / scale;
382
+ }
383
+
384
+ if (block && this.paintState != this.paintStates.SELECTED) {
385
+ // set colour for items with colour byblock
386
+ if (item.entityColour.aci === 0) {
387
+ colour = block.getDrawColour();
388
+ }
389
+ }
390
+
391
+ // ACI 7: white on dark background, black on light background
392
+ if (this.paintState !== this.paintStates.SELECTED && this.#isAci7(item, block)) {
393
+ const bg = DesignCore.Settings.canvasbackgroundcolour;
394
+ colour = (bg.r + bg.g + bg.b) / 3 < 128 ? { r: 255, g: 255, b: 255 } : { r: 0, g: 0, b: 0 };
395
+ }
242
396
 
243
397
  try { // HTML Canvas
244
- context.strokeStyle = colour;
245
- context.fillStyle = colour;
398
+ context.strokeStyle = Colours.rgbToString(colour);
399
+ context.fillStyle = Colours.rgbToString(colour);
246
400
  context.lineWidth = lineWidth;
247
- context.setLineDash(lineType.getPattern(this.getScale()));
401
+ context.setLineDash(lineType.getPattern(scale));
248
402
  context.beginPath();
249
403
  } catch { // Cairo
250
- const rgbColour = Colours.hexToScaledRGB(colour);
404
+ const rgbColour = Colours.rgbToScaledRGB(colour);
251
405
  context.setSourceRGB(rgbColour.r, rgbColour.g, rgbColour.b);
252
- context.setDash(lineType.getPattern(this.getScale()), 1);
406
+ context.setDash(lineType.getPattern(scale), 1);
253
407
  context.setLineWidth(lineWidth);
254
408
  }
255
409
  }
256
410
 
411
+ /**
412
+ * Resolve whether the effective draw colour for an item is ACI 7.
413
+ * Follows ByLayer and ByBlock indirection.
414
+ * @param {entity} item
415
+ * @param {entity} block - enclosing insert/dimension, or undefined
416
+ * @return {boolean}
417
+ */
418
+ #isAci7(item, block) {
419
+ let colour;
420
+ if (item.entityColour.byBlock && block) {
421
+ colour = block.entityColour.byLayer ?
422
+ DesignCore.LayerManager.getItemByName(block.layer)?.layerColour :
423
+ block.entityColour;
424
+ } else if (item.entityColour.byLayer) {
425
+ colour = DesignCore.LayerManager.getItemByName(item.layer)?.layerColour;
426
+ } else {
427
+ colour = item.entityColour;
428
+ }
429
+ return colour?.aci === 7 && !colour?.isTrueColour;
430
+ }
431
+
432
+ /**
433
+ * Paint the background grid
434
+ * @param {object} context
435
+ */
257
436
  paintGrid(context) {
437
+ const scale = this.getScale();
438
+
258
439
  // TODO: Move grid linewidth to settings?
259
440
  let lineWidth = 0.75;
260
441
 
261
442
  try { // HTML Canvas
262
- context.strokeStyle = DesignCore.Settings.gridcolour;
263
- context.lineWidth = lineWidth / this.getScale();
443
+ context.strokeStyle = Colours.rgbToString(DesignCore.Settings.gridcolour);
444
+ context.lineWidth = lineWidth / scale;
264
445
  context.beginPath();
265
446
  } catch { // Cairo
266
- context.setLineWidth(lineWidth / this.getScale());
267
- const rgbColour = Colours.hexToScaledRGB(DesignCore.Settings.gridcolour);
447
+ context.setLineWidth(lineWidth / scale);
448
+ const rgbColour = Colours.rgbToScaledRGB(DesignCore.Settings.gridcolour);
268
449
  context.setSourceRGB(rgbColour.r, rgbColour.g, rgbColour.b);
269
450
  }
270
451
 
@@ -284,26 +465,31 @@ export class Canvas {
284
465
  context.lineTo(0, ygridmin);
285
466
  context.stroke();
286
467
 
468
+ // only draw the grid if within scale limits
469
+ if (scale < this.minScaleFactor || scale > this.maxScaleFactor) {
470
+ return;
471
+ }
472
+
287
473
  if (DesignCore.Settings['drawgrid']) {
288
474
  // set a feint linewidth for the grid
289
475
  lineWidth = lineWidth * 0.25;
290
476
 
291
477
  try { // HTML Canvas
292
- context.lineWidth = lineWidth / this.getScale();
478
+ context.lineWidth = lineWidth / scale;
293
479
  context.beginPath();
294
480
  } catch { // Cairo
295
- context.setLineWidth(lineWidth / this.getScale());
481
+ context.setLineWidth(lineWidth / scale);
296
482
  }
297
483
 
298
484
  // TODO: add setting for grid spacing
299
485
  let gridInterval = 100;
300
486
 
301
487
  // define the grid spacing based on zoom level
302
- if (this.getScale() > 50) {
488
+ if (scale > 50) {
303
489
  gridInterval = 1;
304
- } else if (this.getScale() > 5) {
490
+ } else if (scale > 5) {
305
491
  gridInterval = 10;
306
- } else if (this.getScale() < 0.6) {
492
+ } else if (scale < 0.6) {
307
493
  gridInterval = 1000;
308
494
  } else {
309
495
  gridInterval = 100;
@@ -334,6 +520,11 @@ export class Canvas {
334
520
  }
335
521
  }
336
522
 
523
+ /**
524
+ * Calculate the scene offset from the canvas size
525
+ * i.e at 1:1 its the same as the canvas
526
+ * @return {number}
527
+ */
337
528
  getSceneOffset() {
338
529
  // Calculate the scene offset from the canvas size
339
530
  // i.e at 1:1 its the same as the canvas