plotboilerplate 1.14.0 → 1.17.0

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 (232) hide show
  1. package/README.md +2 -0
  2. package/changelog.md +57 -0
  3. package/dist/index.esm.js +856 -694
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/index.esm.min.js +1 -1
  6. package/dist/index.esm.min.js.map +1 -1
  7. package/dist/plotboilerplate.browser.min.js +1 -1
  8. package/dist/plotboilerplate.browser.min.js.map +1 -1
  9. package/dist/plotboilerplate.js +858 -598
  10. package/dist/plotboilerplate.min.js +1 -1
  11. package/package.json +1 -1
  12. package/src/cjs/BezierPath.d.ts +32 -14
  13. package/src/cjs/BezierPath.js +65 -24
  14. package/src/cjs/BezierPath.js.map +1 -1
  15. package/src/cjs/Bounds.d.ts +22 -1
  16. package/src/cjs/Bounds.js +24 -1
  17. package/src/cjs/Bounds.js.map +1 -1
  18. package/src/cjs/Circle.d.ts +15 -13
  19. package/src/cjs/Circle.js +16 -34
  20. package/src/cjs/Circle.js.map +1 -1
  21. package/src/cjs/CircleSector.d.ts +17 -16
  22. package/src/cjs/CircleSector.js +12 -24
  23. package/src/cjs/CircleSector.js.map +1 -1
  24. package/src/cjs/CubicBezierCurve.d.ts +16 -15
  25. package/src/cjs/CubicBezierCurve.js +57 -94
  26. package/src/cjs/CubicBezierCurve.js.map +1 -1
  27. package/src/cjs/KeyHandler.d.ts +10 -3
  28. package/src/cjs/KeyHandler.js +28 -23
  29. package/src/cjs/KeyHandler.js.map +1 -1
  30. package/src/cjs/Line.d.ts +2 -15
  31. package/src/cjs/Line.js +6 -31
  32. package/src/cjs/Line.js.map +1 -1
  33. package/src/cjs/MouseHandler.js +43 -53
  34. package/src/cjs/MouseHandler.js.map +1 -1
  35. package/src/cjs/PBImage.d.ts +15 -13
  36. package/src/cjs/PBImage.js +11 -15
  37. package/src/cjs/PBImage.js.map +1 -1
  38. package/src/cjs/PBText.d.ts +13 -12
  39. package/src/cjs/PBText.js +8 -12
  40. package/src/cjs/PBText.js.map +1 -1
  41. package/src/cjs/PlotBoilerplate.js +3 -2
  42. package/src/cjs/PlotBoilerplate.js.map +1 -1
  43. package/src/cjs/Polygon.d.ts +44 -14
  44. package/src/cjs/Polygon.js +116 -66
  45. package/src/cjs/Polygon.js.map +1 -1
  46. package/src/cjs/Triangle.d.ts +15 -13
  47. package/src/cjs/Triangle.js +23 -64
  48. package/src/cjs/Triangle.js.map +1 -1
  49. package/src/cjs/VEllipse.d.ts +14 -9
  50. package/src/cjs/VEllipse.js +10 -18
  51. package/src/cjs/VEllipse.js.map +1 -1
  52. package/src/cjs/VEllipseSector.d.ts +15 -1
  53. package/src/cjs/VEllipseSector.js +11 -1
  54. package/src/cjs/VEllipseSector.js.map +1 -1
  55. package/src/cjs/Vector.d.ts +3 -15
  56. package/src/cjs/Vector.js +9 -49
  57. package/src/cjs/Vector.js.map +1 -1
  58. package/src/cjs/VertTuple.d.ts +15 -1
  59. package/src/cjs/VertTuple.js +14 -19
  60. package/src/cjs/VertTuple.js.map +1 -1
  61. package/src/cjs/Vertex.d.ts +47 -13
  62. package/src/cjs/Vertex.js +62 -22
  63. package/src/cjs/Vertex.js.map +1 -1
  64. package/src/cjs/VertexListeners.d.ts +12 -8
  65. package/src/cjs/VertexListeners.js +18 -25
  66. package/src/cjs/VertexListeners.js.map +1 -1
  67. package/src/cjs/draw.d.ts +41 -2
  68. package/src/cjs/draw.js +140 -3
  69. package/src/cjs/draw.js.map +1 -1
  70. package/src/cjs/drawgl.d.ts +38 -2
  71. package/src/cjs/drawgl.js +41 -2
  72. package/src/cjs/drawgl.js.map +1 -1
  73. package/src/cjs/drawutilssvg.d.ts +66 -3
  74. package/src/cjs/drawutilssvg.js +140 -15
  75. package/src/cjs/drawutilssvg.js.map +1 -1
  76. package/src/cjs/index.d.ts +0 -1
  77. package/src/cjs/index.js +0 -1
  78. package/src/cjs/index.js.map +1 -1
  79. package/src/cjs/interfaces/DrawLib.d.ts +61 -26
  80. package/src/cjs/interfaces/DrawLib.js +2 -0
  81. package/src/cjs/interfaces/DrawLib.js.map +1 -1
  82. package/src/cjs/interfaces/core.d.ts +0 -12
  83. package/src/cjs/module.d.ts +1 -3
  84. package/src/cjs/module.js +2 -5
  85. package/src/cjs/module.js.map +1 -1
  86. package/src/cjs/utils/creategui.js +16 -2
  87. package/src/cjs/utils/datastructures/Girih.d.ts +5 -0
  88. package/src/cjs/utils/datastructures/Girih.js +18 -14
  89. package/src/cjs/utils/datastructures/Girih.js.map +1 -1
  90. package/src/cjs/utils/datastructures/GirihPenroseRhombus.js +42 -25
  91. package/src/cjs/utils/datastructures/GirihPenroseRhombus.js.map +1 -1
  92. package/src/cjs/utils/datastructures/GirihTile.js +2 -13
  93. package/src/cjs/utils/datastructures/GirihTile.js.map +1 -1
  94. package/src/cjs/utils/findInVertexArray.d.ts +19 -0
  95. package/src/cjs/utils/findInVertexArray.js +29 -0
  96. package/src/cjs/utils/findInVertexArray.js.map +1 -0
  97. package/src/cjs/utils/helpers/BezierPathInteractionHelper.d.ts +17 -1
  98. package/src/cjs/utils/helpers/BezierPathInteractionHelper.js +50 -32
  99. package/src/cjs/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
  100. package/src/cjs/utils/io/DndFileHandler.d.ts +63 -0
  101. package/src/cjs/utils/io/DndFileHandler.js +112 -0
  102. package/src/cjs/utils/io/DndFileHandler.js.map +1 -0
  103. package/src/cjs/utils/io/FileDrop.d.ts +98 -0
  104. package/src/cjs/utils/io/FileDrop.js +142 -0
  105. package/src/cjs/utils/io/FileDrop.js.map +1 -0
  106. package/src/esm/BezierPath.d.ts +32 -14
  107. package/src/esm/BezierPath.js +65 -24
  108. package/src/esm/BezierPath.js.map +1 -1
  109. package/src/esm/Bounds.d.ts +22 -1
  110. package/src/esm/Bounds.js +24 -1
  111. package/src/esm/Bounds.js.map +1 -1
  112. package/src/esm/Circle.d.ts +15 -13
  113. package/src/esm/Circle.js +16 -34
  114. package/src/esm/Circle.js.map +1 -1
  115. package/src/esm/CircleSector.d.ts +17 -16
  116. package/src/esm/CircleSector.js +12 -24
  117. package/src/esm/CircleSector.js.map +1 -1
  118. package/src/esm/CubicBezierCurve.d.ts +16 -15
  119. package/src/esm/CubicBezierCurve.js +57 -94
  120. package/src/esm/CubicBezierCurve.js.map +1 -1
  121. package/src/esm/KeyHandler.d.ts +10 -3
  122. package/src/esm/KeyHandler.js +28 -23
  123. package/src/esm/KeyHandler.js.map +1 -1
  124. package/src/esm/Line.d.ts +2 -15
  125. package/src/esm/Line.js +6 -31
  126. package/src/esm/Line.js.map +1 -1
  127. package/src/esm/MouseHandler.js +43 -53
  128. package/src/esm/MouseHandler.js.map +1 -1
  129. package/src/esm/PBImage.d.ts +15 -13
  130. package/src/esm/PBImage.js +11 -15
  131. package/src/esm/PBImage.js.map +1 -1
  132. package/src/esm/PBText.d.ts +13 -12
  133. package/src/esm/PBText.js +8 -12
  134. package/src/esm/PBText.js.map +1 -1
  135. package/src/esm/PlotBoilerplate.js +3 -2
  136. package/src/esm/PlotBoilerplate.js.map +1 -1
  137. package/src/esm/Polygon.d.ts +44 -14
  138. package/src/esm/Polygon.js +116 -66
  139. package/src/esm/Polygon.js.map +1 -1
  140. package/src/esm/Triangle.d.ts +15 -13
  141. package/src/esm/Triangle.js +23 -64
  142. package/src/esm/Triangle.js.map +1 -1
  143. package/src/esm/VEllipse.d.ts +14 -9
  144. package/src/esm/VEllipse.js +10 -18
  145. package/src/esm/VEllipse.js.map +1 -1
  146. package/src/esm/VEllipseSector.d.ts +15 -1
  147. package/src/esm/VEllipseSector.js +11 -1
  148. package/src/esm/VEllipseSector.js.map +1 -1
  149. package/src/esm/Vector.d.ts +3 -15
  150. package/src/esm/Vector.js +9 -49
  151. package/src/esm/Vector.js.map +1 -1
  152. package/src/esm/VertTuple.d.ts +15 -1
  153. package/src/esm/VertTuple.js +14 -19
  154. package/src/esm/VertTuple.js.map +1 -1
  155. package/src/esm/Vertex.d.ts +47 -13
  156. package/src/esm/Vertex.js +62 -22
  157. package/src/esm/Vertex.js.map +1 -1
  158. package/src/esm/VertexListeners.d.ts +12 -8
  159. package/src/esm/VertexListeners.js +18 -25
  160. package/src/esm/VertexListeners.js.map +1 -1
  161. package/src/esm/draw.d.ts +41 -2
  162. package/src/esm/draw.js +139 -3
  163. package/src/esm/draw.js.map +1 -1
  164. package/src/esm/drawgl.d.ts +38 -2
  165. package/src/esm/drawgl.js +41 -2
  166. package/src/esm/drawgl.js.map +1 -1
  167. package/src/esm/drawutilssvg.d.ts +66 -3
  168. package/src/esm/drawutilssvg.js +140 -15
  169. package/src/esm/drawutilssvg.js.map +1 -1
  170. package/src/esm/index.d.ts +0 -1
  171. package/src/esm/index.js +0 -1
  172. package/src/esm/index.js.map +1 -1
  173. package/src/esm/interfaces/DrawLib.d.ts +61 -26
  174. package/src/esm/interfaces/DrawLib.js +2 -0
  175. package/src/esm/interfaces/DrawLib.js.map +1 -1
  176. package/src/esm/interfaces/core.d.ts +0 -12
  177. package/src/esm/module.d.ts +1 -3
  178. package/src/esm/module.js +5 -4
  179. package/src/esm/module.js.map +1 -1
  180. package/src/esm/utils/datastructures/Girih.d.ts +5 -0
  181. package/src/esm/utils/datastructures/Girih.js +18 -14
  182. package/src/esm/utils/datastructures/Girih.js.map +1 -1
  183. package/src/esm/utils/datastructures/GirihPenroseRhombus.js +42 -25
  184. package/src/esm/utils/datastructures/GirihPenroseRhombus.js.map +1 -1
  185. package/src/esm/utils/datastructures/GirihTile.js +2 -13
  186. package/src/esm/utils/datastructures/GirihTile.js.map +1 -1
  187. package/src/esm/utils/findInVertexArray.d.ts +19 -0
  188. package/src/esm/utils/findInVertexArray.js +25 -0
  189. package/src/esm/utils/findInVertexArray.js.map +1 -0
  190. package/src/esm/utils/helpers/BezierPathInteractionHelper.d.ts +17 -1
  191. package/src/esm/utils/helpers/BezierPathInteractionHelper.js +49 -32
  192. package/src/esm/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
  193. package/src/esm/utils/io/DndFileHandler.d.ts +63 -0
  194. package/src/esm/utils/io/DndFileHandler.js +106 -0
  195. package/src/esm/utils/io/DndFileHandler.js.map +1 -0
  196. package/src/esm/utils/io/FileDrop.d.ts +98 -0
  197. package/src/esm/utils/io/FileDrop.js +136 -0
  198. package/src/esm/utils/io/FileDrop.js.map +1 -0
  199. package/src/ts/BezierPath.ts +78 -22
  200. package/src/ts/Bounds.ts +25 -1
  201. package/src/ts/Circle.ts +187 -200
  202. package/src/ts/CircleSector.ts +141 -141
  203. package/src/ts/CubicBezierCurve.ts +738 -810
  204. package/src/ts/KeyHandler.ts +221 -212
  205. package/src/ts/Line.ts +48 -80
  206. package/src/ts/MouseHandler.ts +356 -368
  207. package/src/ts/PBImage.ts +67 -69
  208. package/src/ts/PBText.ts +16 -14
  209. package/src/ts/PlotBoilerplate.ts +4 -2
  210. package/src/ts/Polygon.ts +493 -451
  211. package/src/ts/Triangle.ts +444 -489
  212. package/src/ts/VEllipse.ts +18 -17
  213. package/src/ts/VEllipseSector.ts +20 -1
  214. package/src/ts/Vector.ts +124 -160
  215. package/src/ts/VertTuple.ts +333 -338
  216. package/src/ts/Vertex.ts +75 -21
  217. package/src/ts/VertexListeners.ts +248 -266
  218. package/src/ts/draw.ts +192 -3
  219. package/src/ts/drawgl.ts +44 -2
  220. package/src/ts/drawutilssvg.ts +181 -15
  221. package/src/ts/index.ts +0 -1
  222. package/src/ts/interfaces/DrawLib.ts +69 -26
  223. package/src/ts/interfaces/core.ts +0 -11
  224. package/src/ts/module.ts +2 -4
  225. package/src/ts/utils/datastructures/Girih.ts +204 -209
  226. package/src/ts/utils/datastructures/GirihPenroseRhombus.ts +170 -152
  227. package/src/ts/utils/datastructures/GirihTile.ts +394 -419
  228. package/src/ts/utils/findInVertexArray.ts +28 -0
  229. package/src/ts/utils/helpers/BezierPathInteractionHelper.ts +56 -34
  230. package/src/ts/utils/io/FileDrop.ts +178 -0
  231. package/src/ts/SVGBuilder.ts +0 -109
  232. package/src/ts/utils/algorithms/sh-tmp.ts~ +0 -59
package/dist/index.esm.js CHANGED
@@ -99,7 +99,6 @@ class VertexListeners {
99
99
  this.dragEnd = [];
100
100
  this.vertex = vertex;
101
101
  }
102
- ;
103
102
  /**
104
103
  * Add a click listener.
105
104
  *
@@ -113,7 +112,6 @@ class VertexListeners {
113
112
  VertexListeners._addListener(this.click, listener);
114
113
  return this;
115
114
  }
116
- ;
117
115
  /**
118
116
  * The click listener is a function with a single drag event param.
119
117
  * @callback VertexListeners~clickListener
@@ -132,7 +130,6 @@ class VertexListeners {
132
130
  this.click = VertexListeners._removeListener(this.click, listener);
133
131
  return this;
134
132
  }
135
- ;
136
133
  /**
137
134
  * The click listener is a function with a single drag event param.
138
135
  * @callback VertexListeners~clickListener
@@ -151,7 +148,6 @@ class VertexListeners {
151
148
  VertexListeners._addListener(this.drag, listener);
152
149
  return this;
153
150
  }
154
- ;
155
151
  /**
156
152
  * The drag listener is a function with a single drag event param.
157
153
  * @callback VertexListeners~dragListener
@@ -170,7 +166,6 @@ class VertexListeners {
170
166
  this.drag = VertexListeners._removeListener(this.drag, listener);
171
167
  return this;
172
168
  }
173
- ;
174
169
  /**
175
170
  * Add a dragStart listener.
176
171
  *
@@ -184,7 +179,6 @@ class VertexListeners {
184
179
  VertexListeners._addListener(this.dragStart, listener);
185
180
  return this;
186
181
  }
187
- ;
188
182
  /**
189
183
  * The drag-start listener is a function with a single drag event param.
190
184
  * @callback VertexListeners~dragStartListener
@@ -203,7 +197,6 @@ class VertexListeners {
203
197
  this.dragStart = VertexListeners._removeListener(this.dragStart, listener);
204
198
  return this;
205
199
  }
206
- ;
207
200
  /**
208
201
  * Add a dragEnd listener.
209
202
  *
@@ -218,27 +211,25 @@ class VertexListeners {
218
211
  VertexListeners._addListener(this.dragEnd, listener);
219
212
  return this;
220
213
  }
221
- ;
222
214
  /**
223
215
  * The drag-end listener is a function with a single drag event param.
224
216
  * @callback VertexListeners~dragEndListener
225
217
  * @param {Event} e - The (extended) drag event.
226
218
  */
227
219
  /**
228
- * Remove a drag listener.
229
- *
230
- * @method removeDragEndListener
231
- * @param {VertexListeners~clickListener} listener - The drag listener to remove (a callback).
232
- * @return {VertexListeners} this (for chaining)
233
- * @instance
234
- * @memberof VertexListeners
235
- **/
220
+ * Remove a drag listener.
221
+ *
222
+ * @method removeDragEndListener
223
+ * @param {VertexListeners~clickListener} listener - The drag listener to remove (a callback).
224
+ * @return {VertexListeners} this (for chaining)
225
+ * @instance
226
+ * @memberof VertexListeners
227
+ **/
236
228
  removeDragEndListener(listener) {
237
229
  // this.drag.push( listener );
238
230
  this.dragEnd = VertexListeners._removeListener(this.dragEnd, listener);
239
231
  return this;
240
232
  }
241
- ;
242
233
  /**
243
234
  * Fire a click event with the given event instance to all
244
235
  * installed click listeners.
@@ -252,7 +243,6 @@ class VertexListeners {
252
243
  fireClickEvent(e) {
253
244
  VertexListeners._fireEvent(this, this.click, e);
254
245
  }
255
- ;
256
246
  /**
257
247
  * Fire a drag event with the given event instance to all
258
248
  * installed drag listeners.
@@ -266,7 +256,6 @@ class VertexListeners {
266
256
  fireDragEvent(e) {
267
257
  VertexListeners._fireEvent(this, this.drag, e);
268
258
  }
269
- ;
270
259
  /**
271
260
  * Fire a dragStart event with the given event instance to all
272
261
  * installed drag-start listeners.
@@ -280,7 +269,6 @@ class VertexListeners {
280
269
  fireDragStartEvent(e) {
281
270
  VertexListeners._fireEvent(this, this.dragStart, e);
282
271
  }
283
- ;
284
272
  /**
285
273
  * Fire a dragEnd event with the given event instance to all
286
274
  * installed drag-end listeners.
@@ -294,13 +282,21 @@ class VertexListeners {
294
282
  fireDragEndEvent(e) {
295
283
  VertexListeners._fireEvent(this, this.dragEnd, e);
296
284
  }
297
- ;
285
+ /**
286
+ * Removes all listeners from this listeners object.
287
+ */
288
+ removeAllListeners() {
289
+ this.click = [];
290
+ this.drag = [];
291
+ this.dragStart = [];
292
+ this.dragEnd = [];
293
+ }
298
294
  /**
299
295
  * @private
300
296
  **/
301
297
  static _fireEvent(_self, listeners, e) {
302
298
  const ve = e;
303
- if (typeof ve.params == 'undefined')
299
+ if (typeof ve.params == "undefined")
304
300
  ve.params = { vertex: _self.vertex };
305
301
  else
306
302
  ve.params.vertex = _self.vertex;
@@ -308,7 +304,6 @@ class VertexListeners {
308
304
  listeners[i](ve);
309
305
  }
310
306
  }
311
- ;
312
307
  /**
313
308
  * @private
314
309
  */
@@ -320,7 +315,6 @@ class VertexListeners {
320
315
  listeners.push(newListener);
321
316
  return true;
322
317
  }
323
- ;
324
318
  /**
325
319
  * @private
326
320
  */
@@ -331,7 +325,6 @@ class VertexListeners {
331
325
  }
332
326
  return listeners;
333
327
  }
334
- ;
335
328
  }
336
329
 
337
330
  /**
@@ -360,7 +353,11 @@ class VertexListeners {
360
353
  * @modified 2021-03-01 Changed the second param `center` in the `rotate` function from Vertex to XYCoords.
361
354
  * @modified 2021-12-01 Changed the type of param of `scale` to XYCoords.
362
355
  * @modified 2021-12-01 Added function `scaleXY` for non uniform scaling.
363
- * @version 2.5.0
356
+ * @modified 2021-12-17 Added the functions `lerp` and `lerpAbs` for linear interpolations.
357
+ * @modified 2022-01-31 Added `Vertex.utils.arrayToJSON`.
358
+ * @modified 2022-02-02 Added the `destroy` method.
359
+ * @modified 2022-02-02 Cleared the `Vertex.toSVGString` function (deprecated). Use `drawutilssvg` instead.
360
+ * @version 2.7.0
364
361
  *
365
362
  * @file Vertex
366
363
  * @public
@@ -713,6 +710,43 @@ class Vertex {
713
710
  scale(factor, center) {
714
711
  return this.scaleXY({ x: factor, y: factor }, center);
715
712
  }
713
+ /**
714
+ * Perform a linear interpolation towards the given target vertex.
715
+ * The amount value `t` is relative, `t=0.0` means no change, `t=1.0`
716
+ * means this point will be moved to the exact target position.
717
+ *
718
+ * `t=0.5` will move this point to the middle of the connecting
719
+ * linear segment.
720
+ *
721
+ * @param {XYCoords} target - The target position to lerp this vertex to.
722
+ * @param {number} t - The relative amount, usually in [0..1], but other values will work, too.
723
+ * @returns
724
+ */
725
+ lerp(target, t) {
726
+ var diff = this.difference(target);
727
+ // return new Vertex(this.x + diff.x * t, this.y + diff.y * t);
728
+ this.x += diff.x * t;
729
+ this.y += diff.y * t;
730
+ return this;
731
+ }
732
+ /**
733
+ * Perform a linear interpolation towards the given target vertex (absolute variant).
734
+ * The amount value `t` is absolute, which means the lerp amount is a direct distance
735
+ * value. This point will have move the amount of the passed distance `u`.
736
+ *
737
+ * @param {XYCoords} target - The target position to lerp this vertex to.
738
+ * @param {number} t - The absolute move amount to use to lerping.
739
+ * @returns
740
+ */
741
+ lerpAbs(target, u) {
742
+ var dist = this.distance(target);
743
+ var diff = this.difference(target);
744
+ var step = { x: diff.x / dist, y: diff.y / dist };
745
+ // return new Vertex(this.x + step.x * u, this.y + step.y * u);
746
+ this.x += step.x * u;
747
+ this.y += step.y * u;
748
+ return this;
749
+ }
716
750
  /**
717
751
  * This is a vector-like behavior and 'scales' this vertex
718
752
  * towards/from a given center by two independent x- and y- scale factors.
@@ -810,28 +844,14 @@ class Vertex {
810
844
  return "(" + this.x + "," + this.y + ")";
811
845
  }
812
846
  /**
813
- * Convert this vertex to SVG code.
814
- *
815
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
816
- * @method toSVGString
817
- * @param {object=} options - An optional set of options, like 'className'.
818
- * @return {string} A string representing the SVG code for this vertex.
819
- * @instance
820
- * @memberof Vertex
821
- **/
822
- toSVGString(options) {
823
- options = options || {};
824
- var buffer = [];
825
- buffer.push("<circle");
826
- if (options.className)
827
- buffer.push(' class="' + options.className + '"');
828
- buffer.push(' cx="' + this.x + '"');
829
- buffer.push(' cy="' + this.y + '"');
830
- buffer.push(' r="2"');
831
- buffer.push(" />");
832
- return buffer.join("");
847
+ * This function should invalidate any installed listeners and invalidate this object.
848
+ * After calling this function the object might not hold valid data any more and
849
+ * should not be used.
850
+ */
851
+ destroy() {
852
+ this.listeners.removeAllListeners();
853
+ this.isDestroyed = true;
833
854
  }
834
- // END Vertex
835
855
  /**
836
856
  * Create a new random vertex inside the given viewport.
837
857
  *
@@ -886,6 +906,19 @@ Vertex.utils = {
886
906
  vertices.push(new Vertex(zB.x * scaleX, zB.y * scaleY));
887
907
  vertices.push(new Vertex(zB.x * scaleX - headlen * 1.35 * Math.cos(angle + Math.PI / 8), zB.y * scaleY - headlen * 1.35 * Math.sin(angle + Math.PI / 8)));
888
908
  return vertices;
909
+ },
910
+ /**
911
+ * Convert the given vertices (array) to a JSON string.
912
+ *
913
+ * @param {number?} precision - (optional) The numeric precision to be used (number of precision digits).
914
+ * @returns {string}
915
+ */
916
+ arrayToJSON(vertices, precision) {
917
+ return JSON.stringify(vertices.map(function (vert) {
918
+ return typeof precision === undefined
919
+ ? { x: vert.x, y: vert.y }
920
+ : { x: Number(vert.x.toFixed(precision)), y: Number(vert.y.toFixed(precision)) };
921
+ }));
889
922
  }
890
923
  };
891
924
 
@@ -910,7 +943,12 @@ Vertex.utils = {
910
943
  * @modified 2021-01-29 Added the `isClockwise` function.
911
944
  * @modified 2021-01-29 Added the `area` function.
912
945
  * @modified 2021-01-29 Changed the param type for `containsVert` from Vertex to XYCoords.
913
- * @version 1.7.0
946
+ * @modified 2021-12-14 Added the `perimeter()` function.
947
+ * @modified 2021-12-16 Added the `getEvenDistributionPolygon()` function.
948
+ * @modified 2022-02-02 Added the `destroy` method.
949
+ * @modified 2022-02-02 Cleared the `Polygon.toSVGString` function (deprecated). Use `drawutilssvg` instead.
950
+ * @modified 2022-03-08 Added the `Polygon.clone()` function.
951
+ * @version 1.10.0
914
952
  *
915
953
  * @file Polygon
916
954
  * @public
@@ -941,12 +979,11 @@ class Polygon {
941
979
  **/
942
980
  this.className = "Polygon";
943
981
  this.uid = UIDGenerator.next();
944
- if (typeof vertices == 'undefined')
982
+ if (typeof vertices == "undefined")
945
983
  vertices = [];
946
984
  this.vertices = vertices;
947
985
  this.isOpen = isOpen;
948
986
  }
949
- ;
950
987
  /**
951
988
  * Add a vertex to the end of the `vertices` array.
952
989
  *
@@ -958,7 +995,6 @@ class Polygon {
958
995
  addVertex(vert) {
959
996
  this.vertices.push(vert);
960
997
  }
961
- ;
962
998
  /**
963
999
  * Get the polygon vertex at the given position (index).
964
1000
  *
@@ -981,7 +1017,6 @@ class Polygon {
981
1017
  else
982
1018
  return this.vertices[index % this.vertices.length];
983
1019
  }
984
- ;
985
1020
  /**
986
1021
  * Move the polygon's vertices by the given amount.
987
1022
  *
@@ -991,13 +1026,12 @@ class Polygon {
991
1026
  * @memberof Polygon
992
1027
  * @return {Polygon} this for chaining
993
1028
  **/
994
- move(vert) {
1029
+ move(amount) {
995
1030
  for (var i in this.vertices) {
996
- this.vertices[i].add(vert);
1031
+ this.vertices[i].add(amount);
997
1032
  }
998
1033
  return this;
999
1034
  }
1000
- ;
1001
1035
  /**
1002
1036
  * Check if the given vertex is inside this polygon.<br>
1003
1037
  * <br>
@@ -1017,14 +1051,12 @@ class Polygon {
1017
1051
  for (var i = 0, j = this.vertices.length - 1; i < this.vertices.length; j = i++) {
1018
1052
  let xi = this.vertices[i].x, yi = this.vertices[i].y;
1019
1053
  let xj = this.vertices[j].x, yj = this.vertices[j].y;
1020
- var intersect = ((yi > vert.y) != (yj > vert.y))
1021
- && (vert.x < (xj - xi) * (vert.y - yi) / (yj - yi) + xi);
1054
+ var intersect = yi > vert.y != yj > vert.y && vert.x < ((xj - xi) * (vert.y - yi)) / (yj - yi) + xi;
1022
1055
  if (intersect)
1023
1056
  inside = !inside;
1024
1057
  }
1025
1058
  return inside;
1026
1059
  }
1027
- ;
1028
1060
  /**
1029
1061
  * Calculate the area of the given polygon (unsigned).
1030
1062
  *
@@ -1038,7 +1070,6 @@ class Polygon {
1038
1070
  area() {
1039
1071
  return Polygon.utils.area(this.vertices);
1040
1072
  }
1041
- ;
1042
1073
  /**
1043
1074
  * Calulate the signed polyon area by interpreting the polygon as a matrix
1044
1075
  * and calculating its determinant.
@@ -1051,7 +1082,6 @@ class Polygon {
1051
1082
  signedArea() {
1052
1083
  return Polygon.utils.signedArea(this.vertices);
1053
1084
  }
1054
- ;
1055
1085
  /**
1056
1086
  * Get the winding order of this polgon: clockwise or counterclockwise.
1057
1087
  *
@@ -1063,7 +1093,28 @@ class Polygon {
1063
1093
  isClockwise() {
1064
1094
  return Polygon.utils.signedArea(this.vertices) < 0;
1065
1095
  }
1066
- ;
1096
+ /**
1097
+ * Get the perimeter of this polygon.
1098
+ * The perimeter is the absolute length of the outline.
1099
+ *
1100
+ * If this polygon is open then the last segment (connecting the first and the
1101
+ * last vertex) will be skipped.
1102
+ *
1103
+ * @method perimeter
1104
+ * @instance
1105
+ * @memberof Polygon
1106
+ * @return {number}
1107
+ */
1108
+ perimeter() {
1109
+ let length = 0;
1110
+ for (var i = 1; i < this.vertices.length; i++) {
1111
+ length += this.vertices[i - 1].distance(this.vertices[i]);
1112
+ }
1113
+ if (!this.isOpen && this.vertices.length > 1) {
1114
+ length += this.vertices[0].distance(this.vertices[this.vertices.length - 1]);
1115
+ }
1116
+ return length;
1117
+ }
1067
1118
  /**
1068
1119
  * Scale the polygon relative to the given center.
1069
1120
  *
@@ -1076,14 +1127,13 @@ class Polygon {
1076
1127
  **/
1077
1128
  scale(factor, center) {
1078
1129
  for (var i in this.vertices) {
1079
- if (typeof this.vertices[i].scale == 'function')
1130
+ if (typeof this.vertices[i].scale == "function")
1080
1131
  this.vertices[i].scale(factor, center);
1081
1132
  else
1082
- console.log('There seems to be a null vertex!', this.vertices[i]);
1133
+ console.log("There seems to be a null vertex!", this.vertices[i]);
1083
1134
  }
1084
1135
  return this;
1085
1136
  }
1086
- ;
1087
1137
  /**
1088
1138
  * Rotate the polygon around the given center.
1089
1139
  *
@@ -1100,7 +1150,52 @@ class Polygon {
1100
1150
  }
1101
1151
  return this;
1102
1152
  }
1103
- ;
1153
+ /**
1154
+ * Convert this polygon into a new polygon with n evenly distributed vertices.
1155
+ *
1156
+ * @param {number} pointCount - Must not be negative.
1157
+ */
1158
+ getEvenDistributionPolygon(pointCount) {
1159
+ if (pointCount <= 0) {
1160
+ throw new Error("pointCount must be larger than zero; is " + pointCount + ".");
1161
+ }
1162
+ const result = new Polygon([], this.isOpen);
1163
+ if (this.vertices.length === 0) {
1164
+ return result;
1165
+ }
1166
+ // Fetch and add the start point from the source polygon
1167
+ let polygonPoint = new Vertex(this.vertices[0]);
1168
+ result.vertices.push(polygonPoint);
1169
+ if (this.vertices.length === 1) {
1170
+ return result;
1171
+ }
1172
+ const perimeter = this.perimeter();
1173
+ const stepSize = perimeter / pointCount;
1174
+ const n = this.vertices.length;
1175
+ let polygonIndex = 1;
1176
+ let nextPolygonPoint = new Vertex(this.vertices[1]);
1177
+ let segmentLength = polygonPoint.distance(nextPolygonPoint);
1178
+ let loopMax = this.isOpen ? n : n + 1;
1179
+ let curSegmentU = stepSize;
1180
+ var i = 1;
1181
+ while (i < pointCount && polygonIndex < loopMax) {
1182
+ // Check if next eq point is inside this segment
1183
+ if (curSegmentU < segmentLength) {
1184
+ let newPoint = polygonPoint.clone().lerpAbs(nextPolygonPoint, curSegmentU);
1185
+ result.vertices.push(newPoint);
1186
+ curSegmentU += stepSize;
1187
+ i++;
1188
+ }
1189
+ else {
1190
+ polygonIndex++;
1191
+ polygonPoint = nextPolygonPoint;
1192
+ nextPolygonPoint = new Vertex(this.vertices[polygonIndex % n]);
1193
+ curSegmentU = curSegmentU - segmentLength;
1194
+ segmentLength = polygonPoint.distance(nextPolygonPoint);
1195
+ }
1196
+ }
1197
+ return result;
1198
+ }
1104
1199
  /**
1105
1200
  * Get the bounding box (bounds) of this polygon.
1106
1201
  *
@@ -1112,7 +1207,14 @@ class Polygon {
1112
1207
  getBounds() {
1113
1208
  return Bounds.computeFromVertices(this.vertices);
1114
1209
  }
1115
- ;
1210
+ /**
1211
+ * Create a deep copy of this polygon.
1212
+ *
1213
+ * @return {Polygon} The cloned polygon.
1214
+ */
1215
+ clone() {
1216
+ return new Polygon(this.vertices.map(vert => vert.clone()), this.isOpen);
1217
+ }
1116
1218
  /**
1117
1219
  * Convert this polygon to a sequence of quadratic Bézier curves.<br>
1118
1220
  * <br>
@@ -1144,7 +1246,6 @@ class Polygon {
1144
1246
  }
1145
1247
  return qbezier;
1146
1248
  }
1147
- ;
1148
1249
  /**
1149
1250
  * Convert this polygon to a quadratic bezier curve, represented as an SVG data string.
1150
1251
  *
@@ -1157,13 +1258,12 @@ class Polygon {
1157
1258
  var qdata = this.toQuadraticBezierData();
1158
1259
  if (qdata.length == 0)
1159
1260
  return "";
1160
- var buffer = ['M ' + qdata[0].x + ' ' + qdata[0].y];
1261
+ var buffer = ["M " + qdata[0].x + " " + qdata[0].y];
1161
1262
  for (var i = 1; i < qdata.length; i += 2) {
1162
- buffer.push('Q ' + qdata[i].x + ' ' + qdata[i].y + ', ' + qdata[i + 1].x + ' ' + qdata[i + 1].y);
1263
+ buffer.push("Q " + qdata[i].x + " " + qdata[i].y + ", " + qdata[i + 1].x + " " + qdata[i + 1].y);
1163
1264
  }
1164
- return buffer.join(' ');
1265
+ return buffer.join(" ");
1165
1266
  }
1166
- ;
1167
1267
  /**
1168
1268
  * Convert this polygon to a sequence of cubic Bézier curves.<br>
1169
1269
  * <br>
@@ -1180,7 +1280,7 @@ class Polygon {
1180
1280
  * @memberof Polygon
1181
1281
  **/
1182
1282
  toCubicBezierData(threshold) {
1183
- if (typeof threshold == 'undefined')
1283
+ if (typeof threshold == "undefined")
1184
1284
  threshold = 1.0;
1185
1285
  if (this.vertices.length < 3)
1186
1286
  return [];
@@ -1204,7 +1304,6 @@ class Polygon {
1204
1304
  }
1205
1305
  return cbezier;
1206
1306
  }
1207
- ;
1208
1307
  /**
1209
1308
  * Convert this polygon to a cubic bezier curve, represented as an SVG data string.
1210
1309
  *
@@ -1217,13 +1316,23 @@ class Polygon {
1217
1316
  var qdata = this.toCubicBezierData(threshold);
1218
1317
  if (qdata.length == 0)
1219
1318
  return "";
1220
- var buffer = ['M ' + qdata[0].x + ' ' + qdata[0].y];
1319
+ var buffer = ["M " + qdata[0].x + " " + qdata[0].y];
1221
1320
  for (var i = 1; i < qdata.length; i += 3) {
1222
- buffer.push('C ' + qdata[i].x + ' ' + qdata[i].y + ', ' + qdata[i + 1].x + ' ' + qdata[i + 1].y + ', ' + qdata[i + 2].x + ' ' + qdata[i + 2].y);
1223
- }
1224
- return buffer.join(' ');
1321
+ buffer.push("C " +
1322
+ qdata[i].x +
1323
+ " " +
1324
+ qdata[i].y +
1325
+ ", " +
1326
+ qdata[i + 1].x +
1327
+ " " +
1328
+ qdata[i + 1].y +
1329
+ ", " +
1330
+ qdata[i + 2].x +
1331
+ " " +
1332
+ qdata[i + 2].y);
1333
+ }
1334
+ return buffer.join(" ");
1225
1335
  }
1226
- ;
1227
1336
  /**
1228
1337
  * Convert this polygon to a cubic bezier path instance.
1229
1338
  *
@@ -1242,43 +1351,17 @@ class Polygon {
1242
1351
  }
1243
1352
  return BezierPath.fromArray(pathdata);
1244
1353
  }
1245
- ;
1246
1354
  /**
1247
- * Create an SVG representation of this polygon.
1248
- *
1249
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
1250
- * @method toSVGString
1251
- * @param {object=} options - An optional set of options, like 'className'.
1252
- * @return {string} The SVG string.
1253
- * @instance
1254
- * @memberof Polygon
1255
- **/
1256
- toSVGString(options) {
1257
- options = options || {};
1258
- var buffer = [];
1259
- buffer.push('<path');
1260
- if (options.className)
1261
- buffer.push(' class="' + options.className + '"');
1262
- buffer.push(' d="');
1263
- if (this.vertices.length > 0) {
1264
- buffer.push('M ');
1265
- buffer.push(this.vertices[0].x.toString());
1266
- buffer.push(' ');
1267
- buffer.push(this.vertices[0].y.toString());
1268
- for (var i = 1; i < this.vertices.length; i++) {
1269
- buffer.push(' L ');
1270
- buffer.push(this.vertices[i].x.toString());
1271
- buffer.push(' ');
1272
- buffer.push(this.vertices[i].y.toString());
1273
- }
1274
- if (!this.isOpen) {
1275
- buffer.push(' Z');
1276
- }
1355
+ * This function should invalidate any installed listeners and invalidate this object.
1356
+ * After calling this function the object might not hold valid data any more and
1357
+ * should not be used.
1358
+ */
1359
+ destroy() {
1360
+ for (var i = 0; i < this.vertices.length; i++) {
1361
+ this.vertices[i].destroy();
1277
1362
  }
1278
- buffer.push('" />');
1279
- return buffer.join('');
1363
+ this.isDestroyed = true;
1280
1364
  }
1281
- ;
1282
1365
  }
1283
1366
  Polygon.utils = {
1284
1367
  /**
@@ -1298,8 +1381,8 @@ Polygon.utils = {
1298
1381
  const addY = vertices[(i + 1) % l].y;
1299
1382
  const subX = vertices[(i + 1) % l].x;
1300
1383
  const subY = vertices[i].y;
1301
- total += (addX * addY * 0.5);
1302
- total -= (subX * subY * 0.5);
1384
+ total += addX * addY * 0.5;
1385
+ total -= subX * subY * 0.5;
1303
1386
  }
1304
1387
  return Math.abs(total);
1305
1388
  },
@@ -1328,7 +1411,8 @@ Polygon.utils = {
1328
1411
  * @modified 2020-11-19 Set min, max, width and height to private.
1329
1412
  * @modified 2021-02-02 Added the `toPolygon` method.
1330
1413
  * @modified 2021-06-21 (mid-summer) Added `getCenter` method.
1331
- * @version 1.3.0
1414
+ * @modified 2022-02-01 Added the `toString` function.
1415
+ * @version 1.4.0
1332
1416
  **/
1333
1417
  /**
1334
1418
  * @classdesc A bounds class with min and max values. Implementing IBounds.
@@ -1363,9 +1447,31 @@ class Bounds {
1363
1447
  toPolygon() {
1364
1448
  return new Polygon([new Vertex(this.min), new Vertex(this.max.x, this.min.y), new Vertex(this.max), new Vertex(this.min.x, this.max.y)], false);
1365
1449
  }
1450
+ /**
1451
+ * Get the center of this boinding box.
1452
+ *
1453
+ * @method getCenter
1454
+ * @instance
1455
+ * @memberof Bounds
1456
+ * @returns {Vertex} The center of these bounds.
1457
+ */
1366
1458
  getCenter() {
1367
1459
  return new Vertex(this.min.x + (this.max.x - this.min.x) / 2.0, this.min.y + (this.max.y - this.min.y) / 2);
1368
1460
  }
1461
+ /**
1462
+ * Convert these bounds to a human readable form.
1463
+ *
1464
+ * Note: the returned format might change in the future, so please do not
1465
+ * rely on the returned string format.
1466
+ *
1467
+ * @method toString
1468
+ * @instance
1469
+ * @memberof Bounds
1470
+ * @returns {string} Get these bounds in a human readable form.
1471
+ */
1472
+ toString() {
1473
+ return `{ min: ${this.min.toString()}, max : ${this.max.toString()}, width: ${this.width}, height : ${this.height} }`;
1474
+ }
1369
1475
  /**
1370
1476
  * Compute the minimal bounding box for a given set of vertices.
1371
1477
  *
@@ -1406,7 +1512,8 @@ class Bounds {
1406
1512
  * @modified 2020-12-04 Changed `getClosestT` param from `Vertex` to `XYCoords` (generalized).
1407
1513
  * @modified 2020-12-04 Added the `hasPoint(XYCoords)` function.
1408
1514
  * @modified 2021-01-20 Added UID.
1409
- * @version 1.1.0
1515
+ * @modified 2022-02-02 Added the `destroy` method.
1516
+ * @version 1.2.0
1410
1517
  */
1411
1518
  /**
1412
1519
  * @classdesc An abstract base classes for vertex tuple constructs, like Lines or Vectors.
@@ -1440,7 +1547,6 @@ class VertTuple {
1440
1547
  length() {
1441
1548
  return Math.sqrt(Math.pow(this.b.x - this.a.x, 2) + Math.pow(this.b.y - this.a.y, 2));
1442
1549
  }
1443
- ;
1444
1550
  /**
1445
1551
  * Set the length of this vector to the given amount. This only works if this
1446
1552
  * vector is not a null vector.
@@ -1453,7 +1559,6 @@ class VertTuple {
1453
1559
  setLength(length) {
1454
1560
  return this.scale(length / this.length());
1455
1561
  }
1456
- ;
1457
1562
  /**
1458
1563
  * Substract the given vertex from this line's end points.
1459
1564
  *
@@ -1468,7 +1573,6 @@ class VertTuple {
1468
1573
  this.b.sub(amount);
1469
1574
  return this;
1470
1575
  }
1471
- ;
1472
1576
  /**
1473
1577
  * Add the given vertex to this line's end points.
1474
1578
  *
@@ -1483,7 +1587,6 @@ class VertTuple {
1483
1587
  this.b.add(amount);
1484
1588
  return this;
1485
1589
  }
1486
- ;
1487
1590
  /**
1488
1591
  * Normalize this line (set to length 1).
1489
1592
  *
@@ -1496,7 +1599,6 @@ class VertTuple {
1496
1599
  this.b.set(this.a.x + (this.b.x - this.a.x) / this.length(), this.a.y + (this.b.y - this.a.y) / this.length());
1497
1600
  return this;
1498
1601
  }
1499
- ;
1500
1602
  /**
1501
1603
  * Scale this line by the given factor.
1502
1604
  *
@@ -1510,7 +1612,6 @@ class VertTuple {
1510
1612
  this.b.set(this.a.x + (this.b.x - this.a.x) * factor, this.a.y + (this.b.y - this.a.y) * factor);
1511
1613
  return this;
1512
1614
  }
1513
- ;
1514
1615
  /**
1515
1616
  * Move this line to a new location.
1516
1617
  *
@@ -1526,7 +1627,6 @@ class VertTuple {
1526
1627
  this.b.add(diff);
1527
1628
  return this;
1528
1629
  }
1529
- ;
1530
1630
  /**
1531
1631
  * Get the angle between this and the passed line (in radians).
1532
1632
  *
@@ -1537,7 +1637,7 @@ class VertTuple {
1537
1637
  * @memberof VertTuple
1538
1638
  **/
1539
1639
  angle(line) {
1540
- if (line == null || typeof line == 'undefined') {
1640
+ if (line == null || typeof line == "undefined") {
1541
1641
  line = this.factory(new Vertex(0, 0), new Vertex(100, 0));
1542
1642
  }
1543
1643
  // Compute the angle from x axis and the return the difference :)
@@ -1547,7 +1647,6 @@ class VertTuple {
1547
1647
  // The result might be negative, but isn't it usually nicer to determine angles in positive values only?
1548
1648
  return Math.atan2(v1.x, v1.y) - Math.atan2(v0.x, v0.y);
1549
1649
  }
1550
- ;
1551
1650
  /**
1552
1651
  * Get line point at position t in [0 ... 1]:<br>
1553
1652
  * <pre>[P(0)]=[A]--------------------[P(t)]------[B]=[P(1)]</pre><br>
@@ -1563,7 +1662,6 @@ class VertTuple {
1563
1662
  vertAt(t) {
1564
1663
  return new Vertex(this.a.x + (this.b.x - this.a.x) * t, this.a.y + (this.b.y - this.a.y) * t);
1565
1664
  }
1566
- ;
1567
1665
  /**
1568
1666
  * Get the denominator of this and the given line.
1569
1667
  *
@@ -1577,9 +1675,8 @@ class VertTuple {
1577
1675
  **/
1578
1676
  denominator(line) {
1579
1677
  // http://jsfiddle.net/justin_c_rounds/Gd2S2/
1580
- return ((line.b.y - line.a.y) * (this.b.x - this.a.x)) - ((line.b.x - line.a.x) * (this.b.y - this.a.y));
1678
+ return (line.b.y - line.a.y) * (this.b.x - this.a.x) - (line.b.x - line.a.x) * (this.b.y - this.a.y);
1581
1679
  }
1582
- ;
1583
1680
  /**
1584
1681
  * Checks if this and the given line are co-linear.
1585
1682
  *
@@ -1594,7 +1691,6 @@ class VertTuple {
1594
1691
  colinear(line) {
1595
1692
  return Math.abs(this.denominator(line)) < Vertex.EPSILON;
1596
1693
  }
1597
- ;
1598
1694
  /**
1599
1695
  * Get the closest position T from this line to the specified point.
1600
1696
  *
@@ -1617,7 +1713,6 @@ class VertTuple {
1617
1713
  // t = Math.max(0, Math.min(1, t));
1618
1714
  return t;
1619
1715
  }
1620
- ;
1621
1716
  /**
1622
1717
  * Check if the given point is located on this line. Optionally also check if
1623
1718
  * that point is located between point `a` and `b`.
@@ -1653,7 +1748,6 @@ class VertTuple {
1653
1748
  var t = this.getClosestT(p);
1654
1749
  return this.vertAt(t);
1655
1750
  }
1656
- ;
1657
1751
  /**
1658
1752
  * The the minimal distance between this line and the specified point.
1659
1753
  *
@@ -1668,7 +1762,6 @@ class VertTuple {
1668
1762
  // https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
1669
1763
  return Math.sqrt(VertTuple.vtutils.dist2(p, this.vertAt(this.getClosestT(p))));
1670
1764
  }
1671
- ;
1672
1765
  /**
1673
1766
  * Create a deep clone of this instance.
1674
1767
  *
@@ -1680,7 +1773,6 @@ class VertTuple {
1680
1773
  clone() {
1681
1774
  return this.factory(this.a.clone(), this.b.clone());
1682
1775
  }
1683
- ;
1684
1776
  /**
1685
1777
  * Create a string representation of this line.
1686
1778
  *
@@ -1692,7 +1784,16 @@ class VertTuple {
1692
1784
  toString() {
1693
1785
  return "{ a : " + this.a.toString() + ", b : " + this.b.toString() + " }";
1694
1786
  }
1695
- ;
1787
+ /**
1788
+ * This function should invalidate any installed listeners and invalidate this object.
1789
+ * After calling this function the object might not hold valid data any more and
1790
+ * should not be used.
1791
+ */
1792
+ destroy() {
1793
+ this.a.destroy();
1794
+ this.b.destroy();
1795
+ this.isDestroyed = true;
1796
+ }
1696
1797
  }
1697
1798
  /**
1698
1799
  * @private
@@ -1714,7 +1815,9 @@ VertTuple.vtutils = {
1714
1815
  * @modified 2019-12-04 Added the Vector.inv() function.
1715
1816
  * @modified 2020-03-23 Ported to Typescript from JS.
1716
1817
  * @modified 2021-01-20 Added UID.
1717
- * @version 1.3.0
1818
+ * @modified 2022-02-02 Added the `destroy` method.
1819
+ * @modified 2022-02-02 Cleared the `Vector.toSVGString` function (deprecated). Use `drawutilssvg` instead.
1820
+ * @version 1.4.0
1718
1821
  *
1719
1822
  * @file Vector
1720
1823
  * @public
@@ -1745,7 +1848,6 @@ class Vector extends VertTuple {
1745
1848
  **/
1746
1849
  this.className = "Vector";
1747
1850
  }
1748
- ;
1749
1851
  /**
1750
1852
  * Get the perpendicular of this vector which is located at a.
1751
1853
  *
@@ -1760,7 +1862,6 @@ class Vector extends VertTuple {
1760
1862
  v.b.add(this.a);
1761
1863
  return v;
1762
1864
  }
1763
- ;
1764
1865
  /**
1765
1866
  * The inverse of a vector is a vector witht the same magnitude but oppose direction.
1766
1867
  *
@@ -1774,7 +1875,6 @@ class Vector extends VertTuple {
1774
1875
  this.b = tmp;
1775
1876
  return this;
1776
1877
  }
1777
- ;
1778
1878
  /**
1779
1879
  * This function computes the inverse of the vector, which means 'a' stays untouched.
1780
1880
  *
@@ -1785,7 +1885,6 @@ class Vector extends VertTuple {
1785
1885
  this.b.y = this.a.y - (this.b.y - this.a.y);
1786
1886
  return this;
1787
1887
  }
1788
- ;
1789
1888
  /**
1790
1889
  * Get the intersection if this vector and the specified vector.
1791
1890
  *
@@ -1801,53 +1900,15 @@ class Vector extends VertTuple {
1801
1900
  return null;
1802
1901
  var a = this.a.y - line.a.y;
1803
1902
  var b = this.a.x - line.a.x;
1804
- var numerator1 = ((line.b.x - line.a.x) * a) - ((line.b.y - line.a.y) * b);
1805
- var numerator2 = ((this.b.x - this.a.x) * a) - ((this.b.y - this.a.y) * b);
1903
+ var numerator1 = (line.b.x - line.a.x) * a - (line.b.y - line.a.y) * b;
1904
+ var numerator2 = (this.b.x - this.a.x) * a - (this.b.y - this.a.y) * b;
1806
1905
  a = numerator1 / denominator; // NaN if parallel lines
1807
1906
  b = numerator2 / denominator;
1808
1907
  // TODO:
1809
1908
  // FOR A VECTOR THE LINE-INTERSECTION MUST BE ON BOTH VECTORS
1810
1909
  // if we cast these lines infinitely in both directions, they intersect here:
1811
- return new Vertex(this.a.x + (a * (this.b.x - this.a.x)), this.a.y + (a * (this.b.y - this.a.y)));
1910
+ return new Vertex(this.a.x + a * (this.b.x - this.a.x), this.a.y + a * (this.b.y - this.a.y));
1812
1911
  }
1813
- ;
1814
- /**
1815
- * Create an SVG representation of this line.
1816
- *
1817
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
1818
- * @method toSVGString
1819
- * @override
1820
- * @param {object=} options - A set of options, like 'className'.
1821
- * @return {string} The SVG string representation.
1822
- * @instance
1823
- * @memberof Vector
1824
- **/
1825
- toSVGString(options) {
1826
- options = options || {};
1827
- var buffer = [];
1828
- var vertices = Vector.utils.buildArrowHead(this.a, this.b, 8, 1.0, 1.0);
1829
- buffer.push('<g');
1830
- if (options.className)
1831
- buffer.push(' class="' + options.className + '"');
1832
- buffer.push('>');
1833
- buffer.push(' <line');
1834
- buffer.push(' x1="' + this.a.x + '"');
1835
- buffer.push(' y1="' + this.a.y + '"');
1836
- buffer.push(' x2="' + vertices[0].x + '"');
1837
- buffer.push(' y2="' + vertices[0].y + '"');
1838
- buffer.push(' />');
1839
- // Add arrow head
1840
- buffer.push(' <polygon points="');
1841
- for (var i = 0; i < vertices.length; i++) {
1842
- if (i > 0)
1843
- buffer.push(' ');
1844
- buffer.push('' + vertices[i].x + ',' + vertices[i].y);
1845
- }
1846
- buffer.push('"/>');
1847
- buffer.push('</g>');
1848
- return buffer.join('');
1849
- }
1850
- ;
1851
1912
  }
1852
1913
  Vector.utils = {
1853
1914
  /**
@@ -1878,10 +1939,10 @@ Vector.utils = {
1878
1939
  buildArrowHead: (zA, zB, headlen, scaleX, scaleY) => {
1879
1940
  var angle = Math.atan2((zB.y - zA.y) * scaleY, (zB.x - zA.x) * scaleX);
1880
1941
  var vertices = [];
1881
- vertices.push(new Vertex(zB.x * scaleX - (headlen) * Math.cos(angle), zB.y * scaleY - (headlen) * Math.sin(angle)));
1882
- vertices.push(new Vertex(zB.x * scaleX - (headlen * 1.35) * Math.cos(angle - Math.PI / 8), zB.y * scaleY - (headlen * 1.35) * Math.sin(angle - Math.PI / 8)));
1942
+ vertices.push(new Vertex(zB.x * scaleX - headlen * Math.cos(angle), zB.y * scaleY - headlen * Math.sin(angle)));
1943
+ vertices.push(new Vertex(zB.x * scaleX - headlen * 1.35 * Math.cos(angle - Math.PI / 8), zB.y * scaleY - headlen * 1.35 * Math.sin(angle - Math.PI / 8)));
1883
1944
  vertices.push(new Vertex(zB.x * scaleX, zB.y * scaleY));
1884
- vertices.push(new Vertex(zB.x * scaleX - (headlen * 1.35) * Math.cos(angle + Math.PI / 8), zB.y * scaleY - (headlen * 1.35) * Math.sin(angle + Math.PI / 8)));
1945
+ vertices.push(new Vertex(zB.x * scaleX - headlen * 1.35 * Math.cos(angle + Math.PI / 8), zB.y * scaleY - headlen * 1.35 * Math.sin(angle + Math.PI / 8)));
1885
1946
  return vertices;
1886
1947
  }
1887
1948
  };
@@ -1906,7 +1967,9 @@ Vector.utils = {
1906
1967
  * @modified 2020-07-14 Changed the moveCurvePoint(...,Vertex) to moveCurvePoint(...,XYCoords), which is more generic.
1907
1968
  * @modified 2020-07-24 Added the getClosestT function and the helper function locateIntervalByDistance(...).
1908
1969
  * @modified 2021-01-20 Added UID.
1909
- * @version 2.5.0
1970
+ * @modified 2022-02-02 Added the `destroy` method.
1971
+ * @modified 2022-02-02 Cleared the `toSVGPathData` function (deprecated). Use `drawutilssvg` instead.
1972
+ * @version 2.6.0
1910
1973
  *
1911
1974
  * @file CubicBezierCurve
1912
1975
  * @public
@@ -1955,7 +2018,6 @@ class CubicBezierCurve {
1955
2018
  this.arcLength = null;
1956
2019
  this.updateArcLengths();
1957
2020
  }
1958
- ;
1959
2021
  /**
1960
2022
  * Move the given curve point (the start point, end point or one of the two
1961
2023
  * control points).
@@ -1992,7 +2054,6 @@ class CubicBezierCurve {
1992
2054
  if (updateArcLengths)
1993
2055
  this.updateArcLengths();
1994
2056
  }
1995
- ;
1996
2057
  /**
1997
2058
  * Translate the whole curve by the given {x,y} amount: moves all four points.
1998
2059
  *
@@ -2009,7 +2070,6 @@ class CubicBezierCurve {
2009
2070
  this.endPoint.add(amount);
2010
2071
  return this;
2011
2072
  }
2012
- ;
2013
2073
  /**
2014
2074
  * Reverse this curve, means swapping start- and end-point and swapping
2015
2075
  * start-control- and end-control-point.
@@ -2028,7 +2088,6 @@ class CubicBezierCurve {
2028
2088
  this.endControlPoint = tmp;
2029
2089
  return this;
2030
2090
  }
2031
- ;
2032
2091
  /**
2033
2092
  * Get the total curve length.<br>
2034
2093
  * <br>
@@ -2047,7 +2106,6 @@ class CubicBezierCurve {
2047
2106
  getLength() {
2048
2107
  return this.arcLength;
2049
2108
  }
2050
- ;
2051
2109
  /**
2052
2110
  * Uptate the internal arc segment buffer and their lengths.<br>
2053
2111
  * <br>
@@ -2085,7 +2143,6 @@ class CubicBezierCurve {
2085
2143
  }
2086
2144
  this.arcLength = newLength;
2087
2145
  }
2088
- ;
2089
2146
  /**
2090
2147
  * Get a 't' (relative position on curve) with the closest distance to point 'p'.
2091
2148
  *
@@ -2108,7 +2165,6 @@ class CubicBezierCurve {
2108
2165
  } while (iteration < 4 && this.getPointAt(result.tPrev).distance(this.getPointAt(result.tNext)) > desiredEpsilon);
2109
2166
  return result.t;
2110
2167
  }
2111
- ;
2112
2168
  /**
2113
2169
  * This helper function locates the 't' on a fixed step interval with the minimal distance
2114
2170
  * between the curve (at 't') and the given point.
@@ -2137,12 +2193,12 @@ class CubicBezierCurve {
2137
2193
  minDist = dist;
2138
2194
  }
2139
2195
  }
2140
- return { t: tStart + tDiff * (minIndex / stepCount),
2196
+ return {
2197
+ t: tStart + tDiff * (minIndex / stepCount),
2141
2198
  tPrev: tStart + tDiff * (Math.max(0, minIndex - 1) / stepCount),
2142
2199
  tNext: tStart + tDiff * (Math.min(stepCount, minIndex + 1) / stepCount)
2143
2200
  };
2144
2201
  }
2145
- ;
2146
2202
  /**
2147
2203
  * Get the bounds of this bezier curve.
2148
2204
  *
@@ -2164,7 +2220,6 @@ class CubicBezierCurve {
2164
2220
  }
2165
2221
  return new Bounds(min, max);
2166
2222
  }
2167
- ;
2168
2223
  /**
2169
2224
  * Get the start point of the curve.<br>
2170
2225
  * <br>
@@ -2178,7 +2233,6 @@ class CubicBezierCurve {
2178
2233
  getStartPoint() {
2179
2234
  return this.startPoint;
2180
2235
  }
2181
- ;
2182
2236
  /**
2183
2237
  * Get the end point of the curve.<br>
2184
2238
  * <br>
@@ -2192,7 +2246,6 @@ class CubicBezierCurve {
2192
2246
  getEndPoint() {
2193
2247
  return this.endPoint;
2194
2248
  }
2195
- ;
2196
2249
  /**
2197
2250
  * Get the start control point of the curve.<br>
2198
2251
  * <br>
@@ -2206,7 +2259,6 @@ class CubicBezierCurve {
2206
2259
  getStartControlPoint() {
2207
2260
  return this.startControlPoint;
2208
2261
  }
2209
- ;
2210
2262
  /**
2211
2263
  * Get the end control point of the curve.<br>
2212
2264
  * <br>
@@ -2220,7 +2272,6 @@ class CubicBezierCurve {
2220
2272
  getEndControlPoint() {
2221
2273
  return this.endControlPoint;
2222
2274
  }
2223
- ;
2224
2275
  /**
2225
2276
  * Get one of the four curve points specified by the passt point ID.
2226
2277
  *
@@ -2241,7 +2292,6 @@ class CubicBezierCurve {
2241
2292
  return this.endControlPoint;
2242
2293
  throw new Error(`Invalid point ID '${id}'.`);
2243
2294
  }
2244
- ;
2245
2295
  /**
2246
2296
  * Get the curve point at a given position t, where t is in [0,1].<br>
2247
2297
  * <br>
@@ -2256,13 +2306,16 @@ class CubicBezierCurve {
2256
2306
  **/
2257
2307
  getPointAt(t) {
2258
2308
  // Perform some powerful math magic
2259
- const x = this.startPoint.x * Math.pow(1.0 - t, 3) + this.startControlPoint.x * 3 * t * Math.pow(1.0 - t, 2)
2260
- + this.endControlPoint.x * 3 * Math.pow(t, 2) * (1.0 - t) + this.endPoint.x * Math.pow(t, 3);
2261
- const y = this.startPoint.y * Math.pow(1.0 - t, 3) + this.startControlPoint.y * 3 * t * Math.pow(1.0 - t, 2)
2262
- + this.endControlPoint.y * 3 * Math.pow(t, 2) * (1.0 - t) + this.endPoint.y * Math.pow(t, 3);
2309
+ const x = this.startPoint.x * Math.pow(1.0 - t, 3) +
2310
+ this.startControlPoint.x * 3 * t * Math.pow(1.0 - t, 2) +
2311
+ this.endControlPoint.x * 3 * Math.pow(t, 2) * (1.0 - t) +
2312
+ this.endPoint.x * Math.pow(t, 3);
2313
+ const y = this.startPoint.y * Math.pow(1.0 - t, 3) +
2314
+ this.startControlPoint.y * 3 * t * Math.pow(1.0 - t, 2) +
2315
+ this.endControlPoint.y * 3 * Math.pow(t, 2) * (1.0 - t) +
2316
+ this.endPoint.y * Math.pow(t, 3);
2263
2317
  return new Vertex(x, y);
2264
2318
  }
2265
- ;
2266
2319
  /**
2267
2320
  * Get the curve point at a given position u, where u is in [0,arcLength].<br>
2268
2321
  * <br>
@@ -2278,7 +2331,6 @@ class CubicBezierCurve {
2278
2331
  getPoint(u) {
2279
2332
  return this.getPointAt(u / this.arcLength);
2280
2333
  }
2281
- ;
2282
2334
  /**
2283
2335
  * Get the curve tangent vector at a given absolute curve position t in [0,1].<br>
2284
2336
  * <br>
@@ -2299,18 +2351,11 @@ class CubicBezierCurve {
2299
2351
  const t2 = t * t;
2300
2352
  // (1 - t)^2 = (1-t)*(1-t) = 1 - t - t + t^2 = 1 - 2*t + t^2
2301
2353
  const nt2 = 1 - 2 * t + t2;
2302
- const tX = -3 * a.x * nt2 +
2303
- b.x * (3 * nt2 - 6 * (t - t2)) +
2304
- c.x * (6 * (t - t2) - 3 * t2) +
2305
- 3 * d.x * t2;
2306
- const tY = -3 * a.y * nt2 +
2307
- b.y * (3 * nt2 - 6 * (t - t2)) +
2308
- c.y * (6 * (t - t2) - 3 * t2) +
2309
- 3 * d.y * t2;
2354
+ const tX = -3 * a.x * nt2 + b.x * (3 * nt2 - 6 * (t - t2)) + c.x * (6 * (t - t2) - 3 * t2) + 3 * d.x * t2;
2355
+ const tY = -3 * a.y * nt2 + b.y * (3 * nt2 - 6 * (t - t2)) + c.y * (6 * (t - t2) - 3 * t2) + 3 * d.y * t2;
2310
2356
  // Note: my implementation does NOT normalize tangent vectors!
2311
2357
  return new Vertex(tX, tY);
2312
2358
  }
2313
- ;
2314
2359
  /**
2315
2360
  * Get a sub curve at the given start end end offsets (values between 0.0 and 1.0).
2316
2361
  *
@@ -2336,7 +2381,6 @@ class CubicBezierCurve {
2336
2381
  // pb.draw.cubicBezier( startVec.a, endVec.a, startVec.b, endVec.b, '#8800ff', 2 );
2337
2382
  return new CubicBezierCurve(startVec.a, endVec.a, startVec.b, endVec.b);
2338
2383
  }
2339
- ;
2340
2384
  /**
2341
2385
  * Convert a relative curve position u to the absolute curve position t.
2342
2386
  *
@@ -2347,9 +2391,8 @@ class CubicBezierCurve {
2347
2391
  * @return {number}
2348
2392
  **/
2349
2393
  convertU2T(u) {
2350
- return Math.max(0.0, Math.min(1.0, (u / this.arcLength)));
2394
+ return Math.max(0.0, Math.min(1.0, u / this.arcLength));
2351
2395
  }
2352
- ;
2353
2396
  /**
2354
2397
  * Get the curve tangent vector at a given relative position u in [0,arcLength].<br>
2355
2398
  * <br>
@@ -2364,7 +2407,6 @@ class CubicBezierCurve {
2364
2407
  getTangent(u) {
2365
2408
  return this.getTangentAt(this.convertU2T(u));
2366
2409
  }
2367
- ;
2368
2410
  /**
2369
2411
  * Get the curve perpendicular at a given relative position u in [0,arcLength] as a vector.<br>
2370
2412
  * <br>
@@ -2379,7 +2421,6 @@ class CubicBezierCurve {
2379
2421
  getPerpendicular(u) {
2380
2422
  return this.getPerpendicularAt(this.convertU2T(u));
2381
2423
  }
2382
- ;
2383
2424
  /**
2384
2425
  * Get the curve perpendicular at a given absolute position t in [0,1] as a vector.<br>
2385
2426
  * <br>
@@ -2395,7 +2436,6 @@ class CubicBezierCurve {
2395
2436
  const tangentVector = this.getTangentAt(t);
2396
2437
  return new Vertex(tangentVector.y, -tangentVector.x);
2397
2438
  }
2398
- ;
2399
2439
  /**
2400
2440
  * Clone this Bézier curve (deep clone).
2401
2441
  *
@@ -2407,7 +2447,6 @@ class CubicBezierCurve {
2407
2447
  clone() {
2408
2448
  return new CubicBezierCurve(this.getStartPoint().clone(), this.getEndPoint().clone(), this.getStartControlPoint().clone(), this.getEndControlPoint().clone());
2409
2449
  }
2410
- ;
2411
2450
  /**
2412
2451
  * Check if this and the specified curve are equal.<br>
2413
2452
  * <br>
@@ -2426,17 +2465,25 @@ class CubicBezierCurve {
2426
2465
  // Let's see if this restricted version works out.
2427
2466
  if (!curve)
2428
2467
  return false;
2429
- if (!curve.startPoint ||
2430
- !curve.endPoint ||
2431
- !curve.startControlPoint ||
2432
- !curve.endControlPoint)
2468
+ if (!curve.startPoint || !curve.endPoint || !curve.startControlPoint || !curve.endControlPoint)
2433
2469
  return false;
2434
- return this.startPoint.equals(curve.startPoint)
2435
- && this.endPoint.equals(curve.endPoint)
2436
- && this.startControlPoint.equals(curve.startControlPoint)
2437
- && this.endControlPoint.equals(curve.endControlPoint);
2470
+ return (this.startPoint.equals(curve.startPoint) &&
2471
+ this.endPoint.equals(curve.endPoint) &&
2472
+ this.startControlPoint.equals(curve.startControlPoint) &&
2473
+ this.endControlPoint.equals(curve.endControlPoint));
2474
+ }
2475
+ /**
2476
+ * This function should invalidate any installed listeners and invalidate this object.
2477
+ * After calling this function the object might not hold valid data any more and
2478
+ * should not be used.
2479
+ */
2480
+ destroy() {
2481
+ this.startPoint.destroy();
2482
+ this.endPoint.destroy();
2483
+ this.startControlPoint.destroy();
2484
+ this.endControlPoint.destroy();
2485
+ this.isDestroyed = true;
2438
2486
  }
2439
- ;
2440
2487
  /**
2441
2488
  * Quick check for class instance.
2442
2489
  * Is there a better way?
@@ -2462,41 +2509,6 @@ class CubicBezierCurve {
2462
2509
  */
2463
2510
  return obj instanceof CubicBezierCurve;
2464
2511
  }
2465
- ;
2466
- /**
2467
- * Create an SVG path data representation of this bézier curve.
2468
- *
2469
- * Path data string format is:<br>
2470
- * <pre>'M x0 y1 C dx0 dy1 dx1 dy1 x1 x2'</pre><br>
2471
- * or in other words<br>
2472
- * <pre>'M startoint.x startPoint.y C startControlPoint.x startControlPoint.y endControlPoint.x endControlPoint.y endPoint.x endPoint.y'</pre>
2473
- *
2474
- * @method toSVGPathData
2475
- * @instance
2476
- * @memberof CubicBezierCurve
2477
- * @return {string} The SVG path data string.
2478
- **/
2479
- toSVGPathData() {
2480
- var buffer = [];
2481
- buffer.push('M ');
2482
- buffer.push(this.startPoint.x.toString());
2483
- buffer.push(' ');
2484
- buffer.push(this.startPoint.y.toString());
2485
- buffer.push(' C ');
2486
- buffer.push(this.startControlPoint.x.toString());
2487
- buffer.push(' ');
2488
- buffer.push(this.startControlPoint.y.toString());
2489
- buffer.push(' ');
2490
- buffer.push(this.endControlPoint.x.toString());
2491
- buffer.push(' ');
2492
- buffer.push(this.endControlPoint.y.toString());
2493
- buffer.push(' ');
2494
- buffer.push(this.endPoint.x.toString());
2495
- buffer.push(' ');
2496
- buffer.push(this.endPoint.y.toString());
2497
- return buffer.join('');
2498
- }
2499
- ;
2500
2512
  /**
2501
2513
  * Convert this curve to a JSON string.
2502
2514
  *
@@ -2509,18 +2521,33 @@ class CubicBezierCurve {
2509
2521
  toJSON(prettyFormat) {
2510
2522
  var jsonString = "{ " + // begin object
2511
2523
  (prettyFormat ? "\n\t" : "") +
2512
- "\"startPoint\" : [" + this.getStartPoint().x + "," + this.getStartPoint().y + "], " +
2524
+ '"startPoint" : [' +
2525
+ this.getStartPoint().x +
2526
+ "," +
2527
+ this.getStartPoint().y +
2528
+ "], " +
2513
2529
  (prettyFormat ? "\n\t" : "") +
2514
- "\"endPoint\" : [" + this.getEndPoint().x + "," + this.getEndPoint().y + "], " +
2530
+ '"endPoint" : [' +
2531
+ this.getEndPoint().x +
2532
+ "," +
2533
+ this.getEndPoint().y +
2534
+ "], " +
2515
2535
  (prettyFormat ? "\n\t" : "") +
2516
- "\"startControlPoint\": [" + this.getStartControlPoint().x + "," + this.getStartControlPoint().y + "], " +
2536
+ '"startControlPoint": [' +
2537
+ this.getStartControlPoint().x +
2538
+ "," +
2539
+ this.getStartControlPoint().y +
2540
+ "], " +
2517
2541
  (prettyFormat ? "\n\t" : "") +
2518
- "\"endControlPoint\" : [" + this.getEndControlPoint().x + "," + this.getEndControlPoint().y + "]" +
2542
+ '"endControlPoint" : [' +
2543
+ this.getEndControlPoint().x +
2544
+ "," +
2545
+ this.getEndControlPoint().y +
2546
+ "]" +
2519
2547
  (prettyFormat ? "\n\t" : "") +
2520
2548
  " }"; // end object
2521
2549
  return jsonString;
2522
2550
  }
2523
- ;
2524
2551
  /**
2525
2552
  * Parse a Bézier curve from the given JSON string.
2526
2553
  *
@@ -2535,7 +2562,6 @@ class CubicBezierCurve {
2535
2562
  var obj = JSON.parse(jsonString);
2536
2563
  return CubicBezierCurve.fromObject(obj);
2537
2564
  }
2538
- ;
2539
2565
  /**
2540
2566
  * Try to convert the passed object to a CubicBezierCurve.
2541
2567
  *
@@ -2550,16 +2576,15 @@ class CubicBezierCurve {
2550
2576
  if (typeof obj !== "object")
2551
2577
  throw "Can only build from object.";
2552
2578
  if (!obj.startPoint)
2553
- throw "Object member \"startPoint\" missing.";
2579
+ throw 'Object member "startPoint" missing.';
2554
2580
  if (!obj.endPoint)
2555
- throw "Object member \"endPoint\" missing.";
2581
+ throw 'Object member "endPoint" missing.';
2556
2582
  if (!obj.startControlPoint)
2557
- throw "Object member \"startControlPoint\" missing.";
2583
+ throw 'Object member "startControlPoint" missing.';
2558
2584
  if (!obj.endControlPoint)
2559
- throw "Object member \"endControlPoint\" missing.";
2585
+ throw 'Object member "endControlPoint" missing.';
2560
2586
  return new CubicBezierCurve(new Vertex(obj.startPoint[0], obj.startPoint[1]), new Vertex(obj.endPoint[0], obj.endPoint[1]), new Vertex(obj.startControlPoint[0], obj.startControlPoint[1]), new Vertex(obj.endControlPoint[0], obj.endControlPoint[1]));
2561
2587
  }
2562
- ;
2563
2588
  /**
2564
2589
  * Convert a 4-element array of vertices to a cubic bézier curve.
2565
2590
  *
@@ -2576,7 +2601,6 @@ class CubicBezierCurve {
2576
2601
  throw "Can only build from array with four elements.";
2577
2602
  return new CubicBezierCurve(arr[0], arr[1], arr[2], arr[3]);
2578
2603
  }
2579
- ;
2580
2604
  }
2581
2605
  /** @constant {number} */
2582
2606
  CubicBezierCurve.START_POINT = 0;
@@ -2609,7 +2633,10 @@ CubicBezierCurve.END_POINT = 3;
2609
2633
  * @modified 2020-07-24 Added the getClosestT(Vertex) function.
2610
2634
  * @modified 2020-12-29 Constructor is now private (no explicit use intended).
2611
2635
  * @modified 2021-05-25 Added BezierPath.fromReducedList( Array<number> ).
2612
- * @version 2.3.1
2636
+ * @modified 2022-01-31 Added `BezierPath.getEvenDistributionVertices(number)`.
2637
+ * @modified 2022-02-02 Added the `destroy` method.
2638
+ * @modified 2022-02-02 Cleared the `toSVGString` function (deprecated). Use `drawutilssvg` instead.
2639
+ * @version 2.5.0
2613
2640
  *
2614
2641
  * @file BezierPath
2615
2642
  * @public
@@ -3498,6 +3525,59 @@ class BezierPath {
3498
3525
  }
3499
3526
  return new Bounds(min, max);
3500
3527
  }
3528
+ /**
3529
+ * Get n 'equally' distributed vertices along this Bézier path.
3530
+ *
3531
+ * As the changing curvature of the B slines makes prediction of distances difficult, the
3532
+ * returned vertices' distances are only relatively equal:
3533
+ * - the distance grows where curvature is large.
3534
+ * - the distance shrinks where curvature is small.
3535
+ *
3536
+ * Only the distance mean of all consecutive is 1/n-th of the total arc length.
3537
+ *
3538
+ * Usually this approximation is good enough for most use cases.
3539
+ *
3540
+ * @param {number} pointCount - (must be at least 2) The number of desired points (start and end point included).
3541
+ * @return {Array<Vertex>}
3542
+ */
3543
+ getEvenDistributionVertices(pointCount) {
3544
+ if (pointCount < 2) {
3545
+ throw new Error("pointCount must be larger than one; is " + pointCount + ".");
3546
+ }
3547
+ const result = [];
3548
+ if (this.bezierCurves.length === 0) {
3549
+ return result;
3550
+ }
3551
+ // Fetch and add the start point from the source polygon
3552
+ var polygonPoint = new Vertex(this.bezierCurves[0].startPoint);
3553
+ result.push(polygonPoint);
3554
+ // if (this.bezierCurves.length === 1) {
3555
+ // return result;
3556
+ // }
3557
+ const perimeter = this.totalArcLength;
3558
+ const stepSize = perimeter / (pointCount - 1);
3559
+ const n = this.bezierCurves.length;
3560
+ let curveIndex = 0;
3561
+ let segmentLength = this.bezierCurves[0].arcLength;
3562
+ let curSegmentU = stepSize;
3563
+ let i = 1;
3564
+ while (i < pointCount && curveIndex < n) {
3565
+ // Check if next eq point is inside this segment
3566
+ if (curSegmentU < segmentLength) {
3567
+ var newPoint = this.bezierCurves[curveIndex].getPoint(curSegmentU);
3568
+ result.push(newPoint);
3569
+ curSegmentU += stepSize;
3570
+ i++;
3571
+ }
3572
+ else {
3573
+ curveIndex++;
3574
+ curSegmentU = curSegmentU - segmentLength;
3575
+ segmentLength = curveIndex < n ? this.bezierCurves[curveIndex].arcLength : 0;
3576
+ }
3577
+ }
3578
+ result.push(new Vertex(this.bezierCurves[n - 1].endPoint));
3579
+ return result;
3580
+ }
3501
3581
  /**
3502
3582
  * Clone this BezierPath (deep clone).
3503
3583
  *
@@ -3544,30 +3624,15 @@ class BezierPath {
3544
3624
  return true;
3545
3625
  }
3546
3626
  /**
3547
- * Create a <pre>&lt;path&gt;</pre> SVG representation of this bézier curve.
3548
- *
3549
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
3550
- * @method toSVGString
3551
- * @param {object=} [options={}] - Like options.className
3552
- * @param {string=} [options.className] - The classname to use for the SVG item.
3553
- * @instance
3554
- * @memberof BezierPath
3555
- * @return {string} The SVG string.
3556
- **/
3557
- toSVGString(options) {
3558
- options = options || {};
3559
- var buffer = [];
3560
- buffer.push("<path");
3561
- if (options.className)
3562
- buffer.push(' class="' + options.className + '"');
3563
- buffer.push(' d="');
3564
- for (var c = 0; c < this.bezierCurves.length; c++) {
3565
- if (c > 0)
3566
- buffer.push(" ");
3567
- buffer.push(this.bezierCurves[c].toSVGPathData());
3627
+ * This function should invalidate any installed listeners and invalidate this object.
3628
+ * After calling this function the object might not hold valid data any more and
3629
+ * should not be used.
3630
+ */
3631
+ destroy() {
3632
+ for (var i = 0; i < this.bezierCurves.length; i++) {
3633
+ this.bezierCurves[i].destroy();
3568
3634
  }
3569
- buffer.push('" />');
3570
- return buffer.join("");
3635
+ this.isDestroyed = true;
3571
3636
  }
3572
3637
  /**
3573
3638
  * Create a JSON string representation of this bézier curve.
@@ -3794,7 +3859,8 @@ BezierPath.END_POINT = 3;
3794
3859
  * @modified 2020-03-16 The Line.angle(Line) parameter is now optional. The baseline (x-axis) will be used if not defined.
3795
3860
  * @modified 2020-03-23 Ported to Typescript from JS.
3796
3861
  * @modified 2020-12-04 The `intersection` function returns undefined if both lines are parallel.
3797
- * @version 2.1.3
3862
+ * @modified 2022-02-02 Added the `destroy` method.
3863
+ * @version 2.2.0
3798
3864
  *
3799
3865
  * @file Line
3800
3866
  * @public
@@ -3839,45 +3905,19 @@ class Line extends VertTuple {
3839
3905
  return null;
3840
3906
  let a = this.a.y - line.a.y;
3841
3907
  let b = this.a.x - line.a.x;
3842
- const numerator1 = ((line.b.x - line.a.x) * a) - ((line.b.y - line.a.y) * b);
3843
- const numerator2 = ((this.b.x - this.a.x) * a) - ((this.b.y - this.a.y) * b);
3908
+ const numerator1 = (line.b.x - line.a.x) * a - (line.b.y - line.a.y) * b;
3909
+ const numerator2 = (this.b.x - this.a.x) * a - (this.b.y - this.a.y) * b;
3844
3910
  a = numerator1 / denominator; // NaN if parallel lines
3845
3911
  b = numerator2 / denominator;
3846
3912
  // Catch NaN?
3847
- const x = this.a.x + (a * (this.b.x - this.a.x));
3848
- const y = this.a.y + (a * (this.b.y - this.a.y));
3913
+ const x = this.a.x + a * (this.b.x - this.a.x);
3914
+ const y = this.a.y + a * (this.b.y - this.a.y);
3849
3915
  if (isNaN(a) || isNaN(x) || isNaN(y)) {
3850
3916
  return undefined;
3851
3917
  }
3852
3918
  // if we cast these lines infinitely in both directions, they intersect here:
3853
3919
  return new Vertex(x, y);
3854
3920
  }
3855
- ;
3856
- /**
3857
- * Create an SVG representation of this line.
3858
- *
3859
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
3860
- * @method toSVGString
3861
- * @param {options} p - A set of options, like the 'classname' to use
3862
- * for the line object.
3863
- * @return {string} The SVG string representing this line.
3864
- * @instance
3865
- * @memberof Line
3866
- **/
3867
- toSVGString(options) {
3868
- options = options || {};
3869
- var buffer = [];
3870
- buffer.push('<line');
3871
- if (options.className)
3872
- buffer.push(' class="' + options.className + '"');
3873
- buffer.push(' x1="' + this.a.x + '"');
3874
- buffer.push(' y1="' + this.a.y + '"');
3875
- buffer.push(' x2="' + this.b.x + '"');
3876
- buffer.push(' y2="' + this.b.y + '"');
3877
- buffer.push(' />');
3878
- return buffer.join('');
3879
- }
3880
- ;
3881
3921
  }
3882
3922
 
3883
3923
  /**
@@ -3889,7 +3929,9 @@ class Line extends VertTuple {
3889
3929
  * @modified 2020-09-07 Changed the vertAt function by switching sin and cos! The old version did not return the correct vertex (by angle) accoring to the assumed circle math.
3890
3930
  * @modified 2020-10-16 Added the containsCircle(...) function.
3891
3931
  * @modified 2021-01-20 Added UID.
3892
- * @version 1.2.0
3932
+ * @modified 2022-02-02 Added the `destroy` method.
3933
+ * @modified 2022-02-02 Cleared the `toSVGString` function (deprecated). Use `drawutilssvg` instead.
3934
+ * @version 1.3.0
3893
3935
  **/
3894
3936
  /**
3895
3937
  * @classdesc A simple circle: center point and radius.
@@ -3920,7 +3962,6 @@ class Circle {
3920
3962
  this.center = center;
3921
3963
  this.radius = radius;
3922
3964
  }
3923
- ;
3924
3965
  /**
3925
3966
  * Check if the given circle is fully contained inside this circle.
3926
3967
  *
@@ -3933,7 +3974,6 @@ class Circle {
3933
3974
  containsCircle(circle) {
3934
3975
  return this.center.distance(circle.center) + circle.radius < this.radius;
3935
3976
  }
3936
- ;
3937
3977
  /**
3938
3978
  * Calculate the distance from this circle to the given line.
3939
3979
  *
@@ -3952,7 +3992,6 @@ class Circle {
3952
3992
  const closestPointOnLine = line.getClosestPoint(this.center);
3953
3993
  return closestPointOnLine.distance(this.center) - this.radius;
3954
3994
  }
3955
- ;
3956
3995
  /**
3957
3996
  * Get the vertex on the this circle for the given angle.
3958
3997
  *
@@ -3966,7 +4005,6 @@ class Circle {
3966
4005
  // Find the point on the circle respective the angle. Then move relative to center.
3967
4006
  return Circle.circleUtils.vertAt(angle, this.radius).add(this.center);
3968
4007
  }
3969
- ;
3970
4008
  /**
3971
4009
  * Get a tangent line of this circle for a given angle.
3972
4010
  *
@@ -3983,7 +4021,6 @@ class Circle {
3983
4021
  // Construct the perpendicular of the line in point a. Then move relative to center.
3984
4022
  return new Vector(pointA, new Vertex(0, 0)).add(this.center).perp();
3985
4023
  }
3986
- ;
3987
4024
  /**
3988
4025
  * Calculate the intersection points (if exists) with the given circle.
3989
4026
  *
@@ -4023,48 +4060,33 @@ class Circle {
4023
4060
  // x4 = P2.x - h*(P1.y - P0.y)/d;
4024
4061
  // y4 = P2.y + h*(P1.x - P0.x)/d;
4025
4062
  // return pair<Point, Point>(Point(x3, y3), Point(x4, y4));
4026
- // }
4063
+ // }
4027
4064
  var p0 = this.center;
4028
4065
  var p1 = circle.center;
4029
4066
  var d = p0.distance(p1);
4030
4067
  var a = (this.radius * this.radius - circle.radius * circle.radius + d * d) / (2 * d);
4031
4068
  var h = Math.sqrt(this.radius * this.radius - a * a);
4032
4069
  var p2 = p1.clone().scale(a / d, p0);
4033
- var x3 = p2.x + h * (p1.y - p0.y) / d;
4034
- var y3 = p2.y - h * (p1.x - p0.x) / d;
4035
- var x4 = p2.x - h * (p1.y - p0.y) / d;
4036
- var y4 = p2.y + h * (p1.x - p0.x) / d;
4070
+ var x3 = p2.x + (h * (p1.y - p0.y)) / d;
4071
+ var y3 = p2.y - (h * (p1.x - p0.x)) / d;
4072
+ var x4 = p2.x - (h * (p1.y - p0.y)) / d;
4073
+ var y4 = p2.y + (h * (p1.x - p0.x)) / d;
4037
4074
  return new Line(new Vertex(x3, y3), new Vertex(x4, y4));
4038
4075
  }
4039
- ;
4040
4076
  /**
4041
- * Create an SVG representation of this circle.
4042
- *
4043
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
4044
- * @method toSVGString
4045
- * @param {object=} options - An optional set of options, like 'className'.
4046
- * @return {string} A string representing the SVG code for this vertex.
4047
- * @instance
4048
- * @memberof Circle
4049
- */
4050
- toSVGString(options) {
4051
- options = options || {};
4052
- var buffer = [];
4053
- buffer.push('<circle');
4054
- if (options.className)
4055
- buffer.push(' class="' + options.className + '"');
4056
- buffer.push(' cx="' + this.center.x + '"');
4057
- buffer.push(' cy="' + this.center.y + '"');
4058
- buffer.push(' r="' + this.radius + '"');
4059
- buffer.push(' />');
4060
- return buffer.join('');
4077
+ * This function should invalidate any installed listeners and invalidate this object.
4078
+ * After calling this function the object might not hold valid data any more and
4079
+ * should not be used.
4080
+ */
4081
+ destroy() {
4082
+ this.center.destroy();
4083
+ this.isDestroyed = true;
4061
4084
  }
4062
- ;
4063
4085
  } // END class
4064
4086
  Circle.circleUtils = {
4065
4087
  vertAt: (angle, radius) => {
4066
4088
  /* return new Vertex( Math.sin(angle) * radius,
4067
- Math.cos(angle) * radius ); */
4089
+ Math.cos(angle) * radius ); */
4068
4090
  return new Vertex(Math.cos(angle) * radius, Math.sin(angle) * radius);
4069
4091
  }
4070
4092
  };
@@ -4105,27 +4127,15 @@ class CircleSector {
4105
4127
  this.startAngle = startAngle;
4106
4128
  this.endAngle = endAngle;
4107
4129
  }
4108
- ;
4109
4130
  /**
4110
- * Create an SVG representation of this circle.
4111
- *
4112
- * @method toSVGString
4113
- * @param {object=} options - An optional set of options, like 'className'.
4114
- * @return {string} A string representing the SVG code for this vertex.
4115
- * @instance
4116
- * @memberof Circle
4117
- */
4118
- toSVGString(options) {
4119
- options = options || {};
4120
- var buffer = [];
4121
- buffer.push('<path ');
4122
- if (options.className)
4123
- buffer.push(' class="' + options.className + '"');
4124
- const data = CircleSector.circleSectorUtils.describeSVGArc(this.circle.center.x, this.circle.center.y, this.circle.radius, this.startAngle, this.endAngle);
4125
- buffer.push(' d="' + data.join(" ") + '" />');
4126
- return buffer.join('');
4131
+ * This function should invalidate any installed listeners and invalidate this object.
4132
+ * After calling this function the object might not hold valid data any more and
4133
+ * should not be used.
4134
+ */
4135
+ destroy() {
4136
+ this.circle.destroy();
4137
+ this.isDestroyed = true;
4127
4138
  }
4128
- ;
4129
4139
  } // END class
4130
4140
  CircleSector.circleSectorUtils = {
4131
4141
  /**
@@ -4134,11 +4144,11 @@ CircleSector.circleSectorUtils = {
4134
4144
  * TODO: generalize for ellipses (two radii).
4135
4145
  *
4136
4146
  * @param {number} angle - The angle in radians.
4137
- */
4147
+ */
4138
4148
  polarToCartesian: (centerX, centerY, radius, angle) => {
4139
4149
  return {
4140
- x: centerX + (radius * Math.cos(angle)),
4141
- y: centerY + (radius * Math.sin(angle))
4150
+ x: centerX + radius * Math.cos(angle),
4151
+ y: centerY + radius * Math.sin(angle)
4142
4152
  };
4143
4153
  },
4144
4154
  /**
@@ -4151,7 +4161,7 @@ CircleSector.circleSectorUtils = {
4151
4161
  * @return [ 'A', radiusx, radiusy, rotation=0, largeArcFlag=1|0, sweepFlag=0, endx, endy ]
4152
4162
  */
4153
4163
  describeSVGArc: (x, y, radius, startAngle, endAngle, options) => {
4154
- if (typeof options === 'undefined')
4164
+ if (typeof options === "undefined")
4155
4165
  options = { moveToStart: true };
4156
4166
  const end = CircleSector.circleSectorUtils.polarToCartesian(x, y, radius, endAngle);
4157
4167
  const start = CircleSector.circleSectorUtils.polarToCartesian(x, y, radius, startAngle);
@@ -4176,7 +4186,7 @@ CircleSector.circleSectorUtils = {
4176
4186
  }
4177
4187
  const pathData = [];
4178
4188
  if (options.moveToStart) {
4179
- pathData.push('M', start.x, start.y);
4189
+ pathData.push("M", start.x, start.y);
4180
4190
  }
4181
4191
  pathData.push("A", radius, radius, 0, largeArcFlag, sweepFlag, end.x, end.y);
4182
4192
  return pathData;
@@ -4214,7 +4224,11 @@ CircleSector.circleSectorUtils = {
4214
4224
  * @modified 2021-11-15 Adding more parameters tot the `text()` function: fontSize, textAlign, fontFamily, lineHeight.
4215
4225
  * @modified 2021-11-19 Fixing the `label(text,x,y)` position.
4216
4226
  * @modified 2021-11-19 Added the `color` param to the `label(...)` function.
4217
- * @version 1.4.0
4227
+ * @modified 2022-02-03 Added the `lineWidth` param to the `crosshair` function.
4228
+ * @modified 2022-02-03 Added the `cross(...)` function.
4229
+ * @modified 2022-03-26 Added the private `nodeDefs` and `bufferedNodeDefs` attributes.
4230
+ * @modified 2022-03-26 Added the `texturedPoly` function to draw textures polygons.
4231
+ * @version 1.6.0
4218
4232
  **/
4219
4233
  const RAD_TO_DEG = 180 / Math.PI;
4220
4234
  /**
@@ -4241,7 +4255,7 @@ class drawutilssvg {
4241
4255
  * @param {boolean=} isSecondary - (optional) Indicates if this is the primary or secondary instance. Only primary instances manage child nodes.
4242
4256
  * @param {SVGGElement=} gNode - (optional) Primary and seconday instances share the same &lt;g> node.
4243
4257
  **/
4244
- constructor(svgNode, offset, scale, canvasSize, fillShapes, drawConfig, isSecondary, gNode, bufferGNode) {
4258
+ constructor(svgNode, offset, scale, canvasSize, fillShapes, drawConfig, isSecondary, gNode, bufferGNode, nodeDefs, bufferNodeDefs) {
4245
4259
  this.svgNode = svgNode;
4246
4260
  this.offset = new Vertex(0, 0).set(offset);
4247
4261
  this.scale = new Vertex(1, 1).set(scale);
@@ -4253,14 +4267,23 @@ class drawutilssvg {
4253
4267
  if (isSecondary) {
4254
4268
  this.gNode = gNode;
4255
4269
  this.bufferGNode = bufferGNode;
4270
+ this.nodeDefs = nodeDefs;
4271
+ this.bufferedNodeDefs = bufferNodeDefs;
4256
4272
  }
4257
4273
  else {
4258
4274
  this.addStyleDefs(drawConfig);
4275
+ this.addDefsNode();
4259
4276
  this.gNode = this.createSVGNode("g");
4260
4277
  this.bufferGNode = this.createSVGNode("g");
4261
4278
  this.svgNode.appendChild(this.gNode);
4262
4279
  }
4263
4280
  }
4281
+ /**
4282
+ * Adds a default style defintion based on the passed DrawConfig.
4283
+ * Twaek the draw config to change default colors or line thicknesses.
4284
+ *
4285
+ * @param {DrawConfig} drawConfig
4286
+ */
4264
4287
  addStyleDefs(drawConfig) {
4265
4288
  this.nodeStyle = this.createSVGNode("style");
4266
4289
  this.svgNode.appendChild(this.nodeStyle);
@@ -4293,6 +4316,15 @@ class drawutilssvg {
4293
4316
  }
4294
4317
  this.nodeStyle.innerHTML = rules.join("\n");
4295
4318
  }
4319
+ /**
4320
+ * Adds the internal <defs> node.
4321
+ */
4322
+ addDefsNode() {
4323
+ this.nodeDefs = this.createSVGNode("defs");
4324
+ // this.svgNode.appendChild(this.nodeDefs);
4325
+ this.bufferedNodeDefs = this.createSVGNode("defs");
4326
+ this.svgNode.appendChild(this.nodeDefs);
4327
+ }
4296
4328
  /**
4297
4329
  * This is a simple way to include custom CSS class mappings to the style defs of the generated SVG.
4298
4330
  *
@@ -4430,7 +4462,7 @@ class drawutilssvg {
4430
4462
  copyInstance(fillShapes) {
4431
4463
  var copy = new drawutilssvg(this.svgNode, this.offset, this.scale, this.canvasSize, fillShapes, null, // no DrawConfig
4432
4464
  true, // isSecondary
4433
- this.gNode, this.bufferGNode);
4465
+ this.gNode, this.bufferGNode, this.nodeDefs, this.bufferedNodeDefs);
4434
4466
  return copy;
4435
4467
  }
4436
4468
  /**
@@ -4507,11 +4539,15 @@ class drawutilssvg {
4507
4539
  // layout updates.
4508
4540
  // Replace the old <g>-node with the buffer node.
4509
4541
  // https://stackoverflow.com/questions/27442464/how-to-update-a-svg-image-without-seeing-a-blinking
4542
+ this.svgNode.replaceChild(this.bufferedNodeDefs, this.nodeDefs);
4510
4543
  this.svgNode.replaceChild(this.bufferGNode, this.gNode);
4511
4544
  }
4512
- let tmp = this.gNode;
4545
+ const tmpGNode = this.gNode;
4513
4546
  this.gNode = this.bufferGNode;
4514
- this.bufferGNode = tmp;
4547
+ this.bufferGNode = tmpGNode;
4548
+ const tmpDefsNode = this.nodeDefs;
4549
+ this.nodeDefs = this.bufferedNodeDefs;
4550
+ this.bufferedNodeDefs = tmpDefsNode;
4515
4551
  }
4516
4552
  _x(x) {
4517
4553
  return this.offset.x + this.scale.x * x;
@@ -4603,6 +4639,74 @@ class drawutilssvg {
4603
4639
  node.setAttribute("href", image.src);
4604
4640
  return this._bindFillDraw(node, "image", null, null);
4605
4641
  }
4642
+ /**
4643
+ * Draw an image at the given position with the given size.<br>
4644
+ * <br>
4645
+ * Note: SVG images may have resizing issues at the moment.Draw a line and an arrow at the end (zB) of the given line with the specified (CSS-) color.
4646
+ *
4647
+ * @method texturedPoly
4648
+ * @param {Image} textureImage - The image object to draw.
4649
+ * @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
4650
+ * @param {Polygon} polygon - The polygon to use as clip path.
4651
+ * @param {Vertex} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
4652
+ * @param {number} rotation - The rotation to use for the polygon (and for the texture).
4653
+ * @return {void}
4654
+ * @instance
4655
+ * @memberof drawutilssvg
4656
+ **/
4657
+ texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation) {
4658
+ polygon.getBounds();
4659
+ const rotatedScalingOrigin = new Vertex(textureSize.min).clone().rotate(rotation, polygonPosition);
4660
+ polygonPosition.clone().add(rotatedScalingOrigin.difference(textureSize.min).inv());
4661
+ // Create something like this
4662
+ // ...
4663
+ // <defs>
4664
+ // <clipPath id="shape">
4665
+ // <path fill="none" d="..."/>
4666
+ // </clipPath>
4667
+ // </defs>
4668
+ // ...
4669
+ // <g clip-path="url(#shape)">
4670
+ // <g transform="scale(...)">
4671
+ // <image width="643" height="643" transform="rotate(...)" xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/beagle400.jpg" >
4672
+ // </g>
4673
+ // </g>
4674
+ // </image>
4675
+ // ...
4676
+ const clipPathNode = this.makeNode("clipPath");
4677
+ const clipPathId = `clippath_${UIDGenerator.next()}`; // TODO: use a better UUID generator here?
4678
+ clipPathNode.setAttribute("id", clipPathId);
4679
+ const gNode = this.makeNode("g");
4680
+ const imageNode = this.makeNode("image");
4681
+ imageNode.setAttribute("x", `${this._x(rotatedScalingOrigin.x)}`);
4682
+ imageNode.setAttribute("y", `${this._y(rotatedScalingOrigin.y)}`);
4683
+ imageNode.setAttribute("width", `${textureSize.width}`);
4684
+ imageNode.setAttribute("height", `${textureSize.height}`);
4685
+ imageNode.setAttribute("href", textureImage.src);
4686
+ // imageNode.setAttribute("opacity", "0.5");
4687
+ // SVG rotations in degrees
4688
+ imageNode.setAttribute("transform", `rotate(${rotation * RAD_TO_DEG}, ${this._x(rotatedScalingOrigin.x)}, ${this._y(rotatedScalingOrigin.y)})`);
4689
+ const pathNode = this.makeNode("path");
4690
+ const pathData = [];
4691
+ if (polygon.vertices.length > 0) {
4692
+ pathData.push("M", `${this._x(polygon.vertices[0].x)}`, `${this._y(polygon.vertices[0].y)}`);
4693
+ for (var i = 1; i < polygon.vertices.length; i++) {
4694
+ pathData.push("L", `${this._x(polygon.vertices[i].x)}`, `${this._y(polygon.vertices[i].y)}`);
4695
+ }
4696
+ }
4697
+ pathNode.setAttribute("d", pathData.join(" "));
4698
+ clipPathNode.appendChild(pathNode);
4699
+ this.bufferedNodeDefs.appendChild(clipPathNode);
4700
+ gNode.appendChild(imageNode);
4701
+ gNode.setAttribute("transform-origin", `${this._x(rotatedScalingOrigin.x)} ${this._y(rotatedScalingOrigin.y)}`);
4702
+ gNode.setAttribute("transform", `scale(${this.scale.x}, ${this.scale.y})`);
4703
+ const clipNode = this.makeNode("g");
4704
+ clipNode.appendChild(gNode);
4705
+ clipNode.setAttribute("clip-path", `url(#${clipPathId})`);
4706
+ // TODO: check if the image class is correct here or if we should use a 'clippedImage' class here
4707
+ this._bindFillDraw(clipNode, "image", null, null); // No color, no lineWidth
4708
+ return clipNode;
4709
+ }
4606
4710
  /**
4607
4711
  * Draw the given (cubic) bézier curve.
4608
4712
  *
@@ -4995,11 +5099,12 @@ class drawutilssvg {
4995
5099
  * @param {XYCoords} center - The center of the crosshair.
4996
5100
  * @param {number} radius - The radius of the crosshair.
4997
5101
  * @param {string} color - The CSS color to draw the crosshair with.
5102
+ * @param {number=0.5} lineWidth - (optional, default=0.5) The line width to use.
4998
5103
  * @return {void}
4999
5104
  * @instance
5000
5105
  * @memberof drawutilssvg
5001
5106
  */
5002
- crosshair(center, radius, color) {
5107
+ crosshair(center, radius, color, lineWidth) {
5003
5108
  const node = this.makeNode("path");
5004
5109
  const d = [
5005
5110
  "M",
@@ -5016,7 +5121,40 @@ class drawutilssvg {
5016
5121
  this._y(center.y) + radius
5017
5122
  ];
5018
5123
  node.setAttribute("d", d.join(" "));
5019
- return this._bindFillDraw(node, "crosshair", color, 0.5);
5124
+ return this._bindFillDraw(node, "crosshair", color, lineWidth || 0.5);
5125
+ }
5126
+ /**
5127
+ * Draw a cross with diagonal axes with given radius, color and lineWidth at the given position.<br>
5128
+ * <br>
5129
+ * Note that the x's radius will not be affected by scaling.
5130
+ *
5131
+ * @method crosshair
5132
+ * @param {XYCoords} center - The center of the crosshair.
5133
+ * @param {number} radius - The radius of the crosshair.
5134
+ * @param {string} color - The CSS color to draw the crosshair with.
5135
+ * @param {number=1} lineWidth - (optional, default=1.0) The line width to use.
5136
+ * @return {void}
5137
+ * @instance
5138
+ * @memberof drawutils
5139
+ */
5140
+ cross(center, radius, color, lineWidth) {
5141
+ const node = this.makeNode("path");
5142
+ const d = [
5143
+ "M",
5144
+ this._x(center.x) - radius,
5145
+ this._y(center.y) - radius,
5146
+ "L",
5147
+ this._x(center.x) + radius,
5148
+ this._y(center.y) + radius,
5149
+ "M",
5150
+ this._x(center.x) - radius,
5151
+ this._y(center.y) + radius,
5152
+ "L",
5153
+ this._x(center.x) + radius,
5154
+ this._y(center.y) - radius
5155
+ ];
5156
+ node.setAttribute("d", d.join(" "));
5157
+ return this._bindFillDraw(node, "cross", color, lineWidth || 1.0);
5020
5158
  }
5021
5159
  /**
5022
5160
  * Draw a polygon.
@@ -5179,14 +5317,6 @@ class drawutilssvg {
5179
5317
  if (this.isSecondary) {
5180
5318
  return;
5181
5319
  }
5182
- // // Clearing an SVG is equivalent to removing all its child elements.
5183
- // for (var i = 0; i < this.gNode.childNodes.length; i++) {
5184
- // // Hide all nodes here. Don't throw them away.
5185
- // // We can probably re-use them in the next draw cycle.
5186
- // var child: SVGElement = this.gNode.childNodes[i] as SVGElement;
5187
- // this.cache.set(child.getAttribute("id"), child);
5188
- // }
5189
- // this.removeAllChildNodes();
5190
5320
  // Add a covering rect with the given background color
5191
5321
  this.curId = "background";
5192
5322
  this.curClassName = undefined;
@@ -5212,6 +5342,9 @@ class drawutilssvg {
5212
5342
  while (this.bufferGNode.lastChild) {
5213
5343
  this.bufferGNode.removeChild(this.bufferGNode.lastChild);
5214
5344
  }
5345
+ while (this.bufferedNodeDefs.lastChild) {
5346
+ this.bufferedNodeDefs.removeChild(this.bufferedNodeDefs.lastChild);
5347
+ }
5215
5348
  }
5216
5349
  /**
5217
5350
  * Create a new and empty `SVGElement` &lt;svg&gt; in the svg-namespace.
@@ -5451,7 +5584,10 @@ drawutilssvg.HEAD_XML = [
5451
5584
  * @modified 2021-05-31 Added the `setConfiguration` function from `DrawLib`.
5452
5585
  * @modified 2021-11-12 Adding more parameters tot the `text()` function: fontSize, textAlign, fontFamily, lineHeight.
5453
5586
  * @modified 2021-11-19 Added the `color` param to the `label(...)` function.
5454
- * @version 1.10.0
5587
+ * @modified 2022-02-03 Added the `lineWidth` param to the `crosshair` function.
5588
+ * @modified 2022-02-03 Added the `cross(...)` function.
5589
+ * @modified 2022-03-27 Added the `texturedPoly` function.
5590
+ * @version 1.12.0
5455
5591
  **/
5456
5592
  // Todo: rename this class to Drawutils?
5457
5593
  /**
@@ -5605,6 +5741,96 @@ class drawutils {
5605
5741
  this.offset.x + position.x * this.scale.x, this.offset.y + position.y * this.scale.y, size.x * this.scale.x, size.y * this.scale.y);
5606
5742
  this.ctx.restore();
5607
5743
  }
5744
+ /**
5745
+ * Draw an image at the given position with the given size.<br>
5746
+ * <br>
5747
+ * Note: SVG images may have resizing issues at the moment.Draw a line and an arrow at the end (zB) of the given line with the specified (CSS-) color.
5748
+ *
5749
+ * @method texturedPoly
5750
+ * @param {Image} textureImage - The image object to draw.
5751
+ * @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
5752
+ * @param {Polygon} polygon - The polygon to use as clip path.
5753
+ * @param {Vertex} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
5754
+ * @param {number} rotation - The rotation to use for the polygon (and for the texture).
5755
+ * @param {XYCoords={x:0,y:0}} rotationCenter - (optional) The rotational center; default is center of bounding box.
5756
+ * @return {void}
5757
+ * @instance
5758
+ * @memberof drawutils
5759
+ **/
5760
+ texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation) {
5761
+ var basePolygonBounds = polygon.getBounds();
5762
+ var targetCenterDifference = polygonPosition.clone().difference(basePolygonBounds.getCenter());
5763
+ // var rotationalOffset = rotationCenter ? polygonPosition.difference(rotationCenter) : { x: 0, y: 0 };
5764
+ // var rotationalOffset = { x: 0, y: 0 };
5765
+ basePolygonBounds.getCenter().sub(targetCenterDifference);
5766
+ // Get the position offset of the polygon
5767
+ var targetTextureSize = new Vertex(textureSize.width, textureSize.height);
5768
+ // var targetTextureOffset = new Vertex(-textureSize.width / 2, -textureSize.height / 2).sub(targetCenterDifference);
5769
+ var targetTextureOffset = new Vertex(textureSize.min.x, textureSize.min.y).sub(polygonPosition);
5770
+ this.ctx.save();
5771
+ // this.ctx.translate(this.offset.x + rotationCenter.x * this.scale.x, this.offset.y + rotationCenter.y * this.scale.y);
5772
+ this.ctx.translate(this.offset.x + polygonPosition.x * this.scale.x, this.offset.y + polygonPosition.y * this.scale.y);
5773
+ drawutils.helpers.clipPoly(this.ctx, {
5774
+ x: -polygonPosition.x * this.scale.x,
5775
+ y: -polygonPosition.y * this.scale.y
5776
+ }, this.scale, polygon.vertices);
5777
+ this.ctx.scale(this.scale.x, this.scale.y);
5778
+ this.ctx.rotate(rotation);
5779
+ this.ctx.drawImage(textureImage, 0, 0, textureImage.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
5780
+ textureImage.naturalHeight - 1, // To avoid errors substract 1 here.
5781
+ targetTextureOffset.x, // * this.scale.x,
5782
+ targetTextureOffset.y, // * this.scale.y,
5783
+ targetTextureSize.x, // * this.scale.x,
5784
+ targetTextureSize.y // * this.scale.y
5785
+ );
5786
+ this.ctx.restore();
5787
+ }
5788
+ _texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation, rotationCenter = { x: 0, y: 0 }) {
5789
+ var basePolygonBounds = polygon.getBounds();
5790
+ var targetCenterDifference = polygonPosition.clone().difference(basePolygonBounds.getCenter());
5791
+ var rotationalOffset = rotationCenter ? polygonPosition.difference(rotationCenter) : { x: 0, y: 0 };
5792
+ // var rotationalOffset = { x: 0, y: 0 };
5793
+ var tileCenter = basePolygonBounds.getCenter().sub(targetCenterDifference);
5794
+ // Get the position offset of the polygon
5795
+ var targetTextureSize = new Vertex(textureSize.width, textureSize.height);
5796
+ var targetTextureOffset = new Vertex(-textureSize.width / 2, -textureSize.height / 2).sub(targetCenterDifference);
5797
+ this.ctx.save();
5798
+ // this.ctx.translate(
5799
+ // this.offset.x + (tileCenter.x - rotationalOffset.x * 0 + targetTextureOffset.x * 0.0) * this.scale.x,
5800
+ // this.offset.y + (tileCenter.y - rotationalOffset.y * 0 + targetTextureOffset.y * 0.0) * this.scale.y
5801
+ // );
5802
+ this.ctx.translate(this.offset.x + (tileCenter.x - rotationalOffset.x * 0 + targetTextureOffset.x * 0.0) * this.scale.x, this.offset.y + (tileCenter.y - rotationalOffset.y * 0 + targetTextureOffset.y * 0.0) * this.scale.y);
5803
+ this.ctx.rotate(rotation);
5804
+ drawutils.helpers.clipPoly(this.ctx, {
5805
+ x: (-targetCenterDifference.x * 1 - tileCenter.x - rotationalOffset.x) * this.scale.x,
5806
+ y: (-targetCenterDifference.y * 1 - tileCenter.y - rotationalOffset.y) * this.scale.y
5807
+ }, this.scale, polygon.vertices);
5808
+ this.ctx.drawImage(textureImage, 0, 0, textureImage.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
5809
+ textureImage.naturalHeight - 1, // To avoid errors substract 1 here.
5810
+ (-polygonPosition.x + targetTextureOffset.x * 1 - rotationalOffset.x * 1) * this.scale.x, (-polygonPosition.y + targetTextureOffset.y * 1 - rotationalOffset.y * 1) * this.scale.y, targetTextureSize.x * this.scale.x, targetTextureSize.y * this.scale.y);
5811
+ // const scaledTextureSize = new Bounds(
5812
+ // new Vertex(
5813
+ // -polygonPosition.x + targetTextureOffset.x - rotationalOffset.x,
5814
+ // -polygonPosition.y + targetTextureOffset.y - rotationalOffset.y
5815
+ // ).scaleXY(this.scale, rotationCenter),
5816
+ // new Vertex(
5817
+ // -polygonPosition.x + targetTextureOffset.x - rotationalOffset.x + targetTextureSize.x,
5818
+ // -polygonPosition.y + targetTextureOffset.y - rotationalOffset.y + targetTextureSize.y
5819
+ // ).scaleXY(this.scale, rotationCenter)
5820
+ // );
5821
+ // this.ctx.drawImage(
5822
+ // textureImage,
5823
+ // 0,
5824
+ // 0,
5825
+ // textureImage.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
5826
+ // textureImage.naturalHeight - 1, // To avoid errors substract 1 here.
5827
+ // scaledTextureSize.min.x,
5828
+ // scaledTextureSize.min.y,
5829
+ // scaledTextureSize.width,
5830
+ // scaledTextureSize.height
5831
+ // );
5832
+ this.ctx.restore();
5833
+ }
5608
5834
  /**
5609
5835
  * Draw a rectangle.
5610
5836
  *
@@ -6045,11 +6271,12 @@ class drawutils {
6045
6271
  * @param {XYCoords} center - The center of the crosshair.
6046
6272
  * @param {number} radius - The radius of the crosshair.
6047
6273
  * @param {string} color - The CSS color to draw the crosshair with.
6274
+ * @param {number=0.5} lineWidth - (optional, default=0.5) The line width to use.
6048
6275
  * @return {void}
6049
6276
  * @instance
6050
6277
  * @memberof drawutils
6051
6278
  */
6052
- crosshair(center, radius, color) {
6279
+ crosshair(center, radius, color, lineWidth) {
6053
6280
  this.ctx.save();
6054
6281
  this.ctx.beginPath();
6055
6282
  this.ctx.moveTo(this.offset.x + center.x * this.scale.x - radius, this.offset.y + center.y * this.scale.y);
@@ -6057,7 +6284,34 @@ class drawutils {
6057
6284
  this.ctx.moveTo(this.offset.x + center.x * this.scale.x, this.offset.y + center.y * this.scale.y - radius);
6058
6285
  this.ctx.lineTo(this.offset.x + center.x * this.scale.x, this.offset.y + center.y * this.scale.y + radius);
6059
6286
  this.ctx.strokeStyle = color;
6060
- this.ctx.lineWidth = 0.5;
6287
+ this.ctx.lineWidth = lineWidth || 0.5;
6288
+ this.ctx.stroke();
6289
+ this.ctx.closePath();
6290
+ this.ctx.restore();
6291
+ }
6292
+ /**
6293
+ * Draw a cross with diagonal axes with given radius, color and lineWidth at the given position.<br>
6294
+ * <br>
6295
+ * Note that the x's radius will not be affected by scaling.
6296
+ *
6297
+ * @method crosshair
6298
+ * @param {XYCoords} center - The center of the crosshair.
6299
+ * @param {number} radius - The radius of the crosshair.
6300
+ * @param {string} color - The CSS color to draw the crosshair with.
6301
+ * @param {number=1} lineWidth - (optional, default=1.0) The line width to use.
6302
+ * @return {void}
6303
+ * @instance
6304
+ * @memberof drawutils
6305
+ */
6306
+ cross(center, radius, color, lineWidth) {
6307
+ this.ctx.save();
6308
+ this.ctx.beginPath();
6309
+ this.ctx.moveTo(this.offset.x + center.x * this.scale.x - radius, this.offset.y + center.y * this.scale.y - radius);
6310
+ this.ctx.lineTo(this.offset.x + center.x * this.scale.x + radius, this.offset.y + center.y * this.scale.y + radius);
6311
+ this.ctx.moveTo(this.offset.x + center.x * this.scale.x - radius, this.offset.y + center.y * this.scale.y + radius);
6312
+ this.ctx.lineTo(this.offset.x + center.x * this.scale.x + radius, this.offset.y + center.y * this.scale.y - radius);
6313
+ this.ctx.strokeStyle = color;
6314
+ this.ctx.lineWidth = lineWidth || 1.0;
6061
6315
  this.ctx.stroke();
6062
6316
  this.ctx.closePath();
6063
6317
  this.ctx.restore();
@@ -6235,6 +6489,21 @@ class drawutils {
6235
6489
  this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
6236
6490
  }
6237
6491
  }
6492
+ drawutils.helpers = {
6493
+ // A helper function to define the clipping path.
6494
+ // This could be a candidate for the draw library.
6495
+ clipPoly: (ctx, offset, scale, vertices) => {
6496
+ ctx.beginPath();
6497
+ // Set clip mask
6498
+ ctx.moveTo(offset.x + vertices[0].x * scale.x, offset.y + vertices[0].y * scale.y);
6499
+ for (var i = 1; i < vertices.length; i++) {
6500
+ const vert = vertices[i];
6501
+ ctx.lineTo(offset.x + vert.x * scale.x, offset.y + vert.y * scale.y);
6502
+ }
6503
+ ctx.closePath();
6504
+ ctx.clip();
6505
+ }
6506
+ };
6238
6507
 
6239
6508
  /**
6240
6509
  * @author Ikaros Kappler
@@ -6244,7 +6513,10 @@ class drawutils {
6244
6513
  * @modified 2020-10-15 Re-added the text() function.
6245
6514
  * @modified 2021-01-24 Added the `setCurrentId` function.
6246
6515
  * @modified 2021-05-31 Added the `setConfiguration` function from `DrawLib`.
6247
- * @version 0.0.5
6516
+ * @modified 2022-02-03 Added the `lineWidth` param to the `crosshair` function.
6517
+ * @modified 2022-02-03 Added the `cross(...)` function.
6518
+ * @modified 2022-03-27 Added the `texturedPoly` function.
6519
+ * @version 0.0.7
6248
6520
  **/
6249
6521
  /**
6250
6522
  * @classdesc A wrapper class for basic drawing operations. This is the WebGL
@@ -6441,6 +6713,24 @@ class drawutilsgl {
6441
6713
  image(image, position, size) {
6442
6714
  // NOT YET IMPLEMENTED
6443
6715
  }
6716
+ /**
6717
+ * Draw an image at the given position with the given size.<br>
6718
+ * <br>
6719
+ * Note: SVG images may have resizing issues at the moment.Draw a line and an arrow at the end (zB) of the given line with the specified (CSS-) color.
6720
+ *
6721
+ * @method texturedPoly
6722
+ * @param {Image} textureImage - The image object to draw.
6723
+ * @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
6724
+ * @param {Polygon} polygon - The polygon to use as clip path.
6725
+ * @param {Vertex} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
6726
+ * @param {number} rotation - The rotation to use for the polygon (and for the texture).
6727
+ * @return {void}
6728
+ * @instance
6729
+ * @memberof drawutilsgl
6730
+ **/
6731
+ texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation) {
6732
+ // NOT YET IMPLEMENTED
6733
+ }
6444
6734
  // +---------------------------------------------------------------------------------
6445
6735
  // | This is the final helper function for drawing and filling stuff. It is not
6446
6736
  // | intended to be used from the outside.
@@ -6722,11 +7012,29 @@ class drawutilsgl {
6722
7012
  * @param {XYCoords} center - The center of the crosshair.
6723
7013
  * @param {number} radius - The radius of the crosshair.
6724
7014
  * @param {string} color - The CSS color to draw the crosshair with.
7015
+ * @param {number=0.5} lineWidth - (optional, default=0.5) The line width to use.
7016
+ * @return {void}
7017
+ * @instance
7018
+ * @memberof drawutils
7019
+ */
7020
+ crosshair(center, radius, color, lineWidth) {
7021
+ // NOT YET IMPLEMENTED
7022
+ }
7023
+ /**
7024
+ * Draw a cross with diagonal axes with given radius, color and lineWidth at the given position.<br>
7025
+ * <br>
7026
+ * Note that the x's radius will not be affected by scaling.
7027
+ *
7028
+ * @method crosshair
7029
+ * @param {XYCoords} center - The center of the crosshair.
7030
+ * @param {number} radius - The radius of the crosshair.
7031
+ * @param {string} color - The CSS color to draw the crosshair with.
7032
+ * @param {number=1} lineWidth - (optional, default=1.0) The line width to use.
6725
7033
  * @return {void}
6726
7034
  * @instance
6727
7035
  * @memberof drawutils
6728
7036
  */
6729
- crosshair(center, radius, color) {
7037
+ cross(center, radius, color, lineWidth) {
6730
7038
  // NOT YET IMPLEMENTED
6731
7039
  }
6732
7040
  /**
@@ -6966,7 +7274,9 @@ class GLU {
6966
7274
  * @modified 2020-12-28 Added the `getArea` function.
6967
7275
  * @modified 2021-01-20 Added UID.
6968
7276
  * @modified 2021-01-22 Always updating circumcircle when retieving it.
6969
- * @version 2.5.1
7277
+ * @modified 2022-02-02 Added the `destroy` method.
7278
+ * @modified 2022-02-02 Cleared the `Triangle.toSVGString` function (deprecated). Use `drawutilssvg` instead.
7279
+ * @version 2.6.0
6970
7280
  *
6971
7281
  * @file Triangle
6972
7282
  * @fileoverview A simple triangle class: three vertices.
@@ -7027,7 +7337,6 @@ class Triangle {
7027
7337
  throw `Cannot create triangle from array with less than three vertices (${arr.length})`;
7028
7338
  return new Triangle(arr[0], arr[1], arr[2]);
7029
7339
  }
7030
- ;
7031
7340
  /**
7032
7341
  * Get the area of this triangle. The returned area is never negative.
7033
7342
  *
@@ -7043,7 +7352,6 @@ class Triangle {
7043
7352
  getArea() {
7044
7353
  return Math.abs(Triangle.utils.signedArea(this.a.x, this.a.y, this.b.x, this.b.y, this.c.x, this.c.y));
7045
7354
  }
7046
- ;
7047
7355
  /**
7048
7356
  * Get the centroid of this triangle.
7049
7357
  *
@@ -7057,7 +7365,6 @@ class Triangle {
7057
7365
  getCentroid() {
7058
7366
  return new Vertex((this.a.x + this.b.x + this.c.x) / 3, (this.a.y + this.b.y + this.c.y) / 3);
7059
7367
  }
7060
- ;
7061
7368
  /**
7062
7369
  * Scale the triangle towards its centroid.
7063
7370
  *
@@ -7074,7 +7381,6 @@ class Triangle {
7074
7381
  this.c.scale(factor, centroid);
7075
7382
  return this;
7076
7383
  }
7077
- ;
7078
7384
  /**
7079
7385
  * Get the circumcircle of this triangle.
7080
7386
  *
@@ -7091,11 +7397,10 @@ class Triangle {
7091
7397
  * @memberof Triangle
7092
7398
  */
7093
7399
  getCircumcircle() {
7094
- // if( !this.center || !this.radius )
7400
+ // if( !this.center || !this.radius )
7095
7401
  this.calcCircumcircle();
7096
7402
  return new Circle(this.center.clone(), this.radius);
7097
7403
  }
7098
- ;
7099
7404
  /**
7100
7405
  * Check if this triangle and the passed triangle share an
7101
7406
  * adjacent edge.
@@ -7115,7 +7420,6 @@ class Triangle {
7115
7420
  var c = this.c.equals(tri.a) || this.c.equals(tri.b) || this.c.equals(tri.c);
7116
7421
  return (a && b) || (a && c) || (b && c);
7117
7422
  }
7118
- ;
7119
7423
  /**
7120
7424
  * Get that vertex of this triangle (a,b,c) that is not vert1 nor vert2 of
7121
7425
  * the passed two.
@@ -7128,14 +7432,13 @@ class Triangle {
7128
7432
  * @memberof Triangle
7129
7433
  */
7130
7434
  getThirdVertex(vert1, vert2) {
7131
- if (this.a.equals(vert1) && this.b.equals(vert2) || this.a.equals(vert2) && this.b.equals(vert1))
7435
+ if ((this.a.equals(vert1) && this.b.equals(vert2)) || (this.a.equals(vert2) && this.b.equals(vert1)))
7132
7436
  return this.c;
7133
- if (this.b.equals(vert1) && this.c.equals(vert2) || this.b.equals(vert2) && this.c.equals(vert1))
7437
+ if ((this.b.equals(vert1) && this.c.equals(vert2)) || (this.b.equals(vert2) && this.c.equals(vert1)))
7134
7438
  return this.a;
7135
7439
  //if( this.c.equals(vert1) && this.a.equals(vert2) || this.c.equals(vert2) && this.a.equals(vert1) )
7136
7440
  return this.b;
7137
7441
  }
7138
- ;
7139
7442
  /**
7140
7443
  * Re-compute the circumcircle of this triangle (if the vertices
7141
7444
  * have changed).
@@ -7175,8 +7478,7 @@ class Triangle {
7175
7478
  }
7176
7479
  this.radius_squared = dx * dx + dy * dy;
7177
7480
  this.radius = Math.sqrt(this.radius_squared);
7178
- }
7179
- ; // END calcCircumcircle
7481
+ } // END calcCircumcircle
7180
7482
  /**
7181
7483
  * Check if the passed vertex is inside this triangle's
7182
7484
  * circumcircle.
@@ -7191,9 +7493,8 @@ class Triangle {
7191
7493
  const dx = this.center.x - v.x;
7192
7494
  const dy = this.center.y - v.y;
7193
7495
  const dist_squared = dx * dx + dy * dy;
7194
- return (dist_squared <= this.radius_squared);
7496
+ return dist_squared <= this.radius_squared;
7195
7497
  }
7196
- ;
7197
7498
  /**
7198
7499
  * Get the rectangular bounds for this triangle.
7199
7500
  *
@@ -7205,7 +7506,6 @@ class Triangle {
7205
7506
  bounds() {
7206
7507
  return new Bounds(new Vertex(Triangle.utils.min3(this.a.x, this.b.x, this.c.x), Triangle.utils.min3(this.a.y, this.b.y, this.c.y)), new Vertex(Triangle.utils.max3(this.a.x, this.b.x, this.c.x), Triangle.utils.max3(this.a.y, this.b.y, this.c.y)));
7207
7508
  }
7208
- ;
7209
7509
  /**
7210
7510
  * Convert this triangle to a polygon instance.
7211
7511
  *
@@ -7219,7 +7519,6 @@ class Triangle {
7219
7519
  toPolygon() {
7220
7520
  return new Polygon([this.a, this.b, this.c]);
7221
7521
  }
7222
- ;
7223
7522
  /**
7224
7523
  * Get the determinant of this triangle.
7225
7524
  *
@@ -7232,7 +7531,6 @@ class Triangle {
7232
7531
  // (b.y - a.y)*(c.x - b.x) - (c.y - b.y)*(b.x - a.x);
7233
7532
  return (this.b.y - this.a.y) * (this.c.x - this.b.x) - (this.c.y - this.b.y) * (this.b.x - this.a.x);
7234
7533
  }
7235
- ;
7236
7534
  /**
7237
7535
  * Checks if the passed vertex (p) is inside this triangle.
7238
7536
  *
@@ -7247,7 +7545,6 @@ class Triangle {
7247
7545
  containsPoint(p) {
7248
7546
  return Triangle.utils.pointIsInTriangle(p.x, p.y, this.a.x, this.a.y, this.b.x, this.b.y, this.c.x, this.c.y);
7249
7547
  }
7250
- ;
7251
7548
  /**
7252
7549
  * Get that inner triangle which defines the maximal incircle.
7253
7550
  *
@@ -7266,7 +7563,6 @@ class Triangle {
7266
7563
  const circleIntersC = lineC.getClosestPoint(intersection);
7267
7564
  return new Triangle(circleIntersA, circleIntersB, circleIntersC);
7268
7565
  }
7269
- ;
7270
7566
  /**
7271
7567
  * Get the incircle of this triangle. That is the circle that touches each side
7272
7568
  * of this triangle in exactly one point.
@@ -7278,7 +7574,6 @@ class Triangle {
7278
7574
  getIncircle() {
7279
7575
  return this.getIncircularTriangle().getCircumcircle();
7280
7576
  }
7281
- ;
7282
7577
  /**
7283
7578
  * Get the incenter of this triangle (which is the center of the circumcircle).
7284
7579
  *
@@ -7292,7 +7587,6 @@ class Triangle {
7292
7587
  this.calcCircumcircle();
7293
7588
  return this.center.clone();
7294
7589
  }
7295
- ;
7296
7590
  /**
7297
7591
  * Converts this triangle into a human-readable string.
7298
7592
  *
@@ -7302,46 +7596,19 @@ class Triangle {
7302
7596
  * @memberof Triangle
7303
7597
  */
7304
7598
  toString() {
7305
- return '{ a : ' + this.a.toString() + ', b : ' + this.b.toString() + ', c : ' + this.c.toString() + '}';
7599
+ return "{ a : " + this.a.toString() + ", b : " + this.b.toString() + ", c : " + this.c.toString() + "}";
7306
7600
  }
7307
- ;
7308
7601
  /**
7309
- * Create an SVG representation of this triangle.
7310
- *
7311
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
7312
- * @method toSVGString
7313
- * @param {object=} options - An optional set of options, like 'className'.
7314
- * @return {string} The SVG string.
7315
- * @instance
7316
- * @memberof Triangle
7317
- **/
7318
- toSVGString(options) {
7319
- options = options || {};
7320
- var buffer = [];
7321
- buffer.push('<path');
7322
- if (options.className)
7323
- buffer.push(' class="' + options.className + '"');
7324
- buffer.push(' d="');
7325
- var vertices = [this.a, this.b, this.c];
7326
- if (vertices.length > 0) {
7327
- buffer.push('M ');
7328
- buffer.push(vertices[0].x);
7329
- buffer.push(' ');
7330
- buffer.push(vertices[0].y);
7331
- for (var i = 1; i < vertices.length; i++) {
7332
- buffer.push(' L ');
7333
- buffer.push(vertices[i].x);
7334
- buffer.push(' ');
7335
- buffer.push(vertices[i].y);
7336
- }
7337
- //if( !this.isOpen ) {
7338
- buffer.push(' Z');
7339
- //}
7340
- }
7341
- buffer.push('" />');
7342
- return buffer.join('');
7602
+ * This function should invalidate any installed listeners and invalidate this object.
7603
+ * After calling this function the object might not hold valid data any more and
7604
+ * should not be used.
7605
+ */
7606
+ destroy() {
7607
+ this.a.destroy();
7608
+ this.b.destroy();
7609
+ this.c.destroy();
7610
+ this.isDestroyed = true;
7343
7611
  }
7344
- ;
7345
7612
  }
7346
7613
  /**
7347
7614
  * An epsilon for comparison.
@@ -7353,10 +7620,10 @@ Triangle.EPSILON = 1.0e-6;
7353
7620
  Triangle.utils = {
7354
7621
  // Used in the bounds() function.
7355
7622
  max3(a, b, c) {
7356
- return (a >= b && a >= c) ? a : (b >= a && b >= c) ? b : c;
7623
+ return a >= b && a >= c ? a : b >= a && b >= c ? b : c;
7357
7624
  },
7358
7625
  min3(a, b, c) {
7359
- return (a <= b && a <= c) ? a : (b <= a && b <= c) ? b : c;
7626
+ return a <= b && a <= c ? a : b <= a && b <= c ? b : c;
7360
7627
  },
7361
7628
  signedArea(p0x, p0y, p1x, p1y, p2x, p2y) {
7362
7629
  return 0.5 * (-p1y * p2x + p0y * (-p1x + p2x) + p0x * (p1y - p2y) + p1x * p2y);
@@ -7372,9 +7639,9 @@ Triangle.utils = {
7372
7639
  // http://stackoverflow.com/questions/2049582/how-to-determine-a-point-in-a-2d-triangle
7373
7640
  // var area : number = 1/2*(-p1y*p2x + p0y*(-p1x + p2x) + p0x*(p1y - p2y) + p1x*p2y);
7374
7641
  var area = Triangle.utils.signedArea(p0x, p0y, p1x, p1y, p2x, p2y);
7375
- var s = 1 / (2 * area) * (p0y * p2x - p0x * p2y + (p2y - p0y) * px + (p0x - p2x) * py);
7376
- var t = 1 / (2 * area) * (p0x * p1y - p0y * p1x + (p0y - p1y) * px + (p1x - p0x) * py);
7377
- return s > 0 && t > 0 && (1 - s - t) > 0;
7642
+ var s = (1 / (2 * area)) * (p0y * p2x - p0x * p2y + (p2y - p0y) * px + (p0x - p2x) * py);
7643
+ var t = (1 / (2 * area)) * (p0x * p1y - p0y * p1x + (p0y - p1y) * px + (p1x - p0x) * py);
7644
+ return s > 0 && t > 0 && 1 - s - t > 0;
7378
7645
  }
7379
7646
  };
7380
7647
 
@@ -7545,7 +7812,8 @@ Grid.utils = {
7545
7812
  * @modified 2020-07-28 Changed the `delete` key code from 8 to 46.
7546
7813
  * @modified 2020-10-04 Changed `window` to `globalThis`.
7547
7814
  * @modified 2020-10-04 Added extended JSDoc.
7548
- * @version 1.0.4
7815
+ * @modified 2022-02-02 Added the `destroy` method.
7816
+ * @version 1.1.0
7549
7817
  *
7550
7818
  * @file KeyHandler
7551
7819
  * @public
@@ -7576,7 +7844,7 @@ class KeyHandler {
7576
7844
  * @memberof KeyHandler
7577
7845
  * @param {HTMLElement} options.element (optional) The HTML element to listen on; if null then 'window' will be used.
7578
7846
  * @param {boolean} options.trackAll (optional) Set to true if you want to keep track of _all_ keys (keyStatus).
7579
- **/
7847
+ **/
7580
7848
  constructor(options) {
7581
7849
  this.downListeners = [];
7582
7850
  this.pressListeners = [];
@@ -7595,7 +7863,6 @@ class KeyHandler {
7595
7863
  // Install the listeners
7596
7864
  this.installListeners();
7597
7865
  }
7598
- ;
7599
7866
  /**
7600
7867
  * A helper function to fire key events from this KeyHandler.
7601
7868
  *
@@ -7613,7 +7880,6 @@ class KeyHandler {
7613
7880
  }
7614
7881
  return hasListener;
7615
7882
  }
7616
- ;
7617
7883
  /**
7618
7884
  * Internal function to fire a new keydown event to all listeners.
7619
7885
  * You should not call this function on your own unless you know what you do.
@@ -7629,10 +7895,9 @@ class KeyHandler {
7629
7895
  fireDownEvent(e, handler) {
7630
7896
  if (handler.fireEvent(e, handler.downListeners) || handler.trackAllKeys) {
7631
7897
  // Down event has listeners. Update key state.
7632
- handler.keyStates[e.keyCode] = 'down';
7898
+ handler.keyStates[e.keyCode] = "down";
7633
7899
  }
7634
7900
  }
7635
- ;
7636
7901
  /**
7637
7902
  * Internal function to fire a new keypress event to all listeners.
7638
7903
  * You should not call this function on your own unless you know what you do.
@@ -7648,7 +7913,6 @@ class KeyHandler {
7648
7913
  firePressEvent(e, handler) {
7649
7914
  handler.fireEvent(e, handler.pressListeners);
7650
7915
  }
7651
- ;
7652
7916
  /**
7653
7917
  * Internal function to fire a new keyup event to all listeners.
7654
7918
  * You should not call this function on your own unless you know what you do.
@@ -7667,20 +7931,18 @@ class KeyHandler {
7667
7931
  delete handler.keyStates[e.keyCode];
7668
7932
  }
7669
7933
  }
7670
- ;
7671
7934
  /**
7672
7935
  * Resolve the key/name code.
7673
7936
  */
7674
7937
  static key2code(key) {
7675
- if (typeof key == 'number')
7938
+ if (typeof key == "number")
7676
7939
  return key;
7677
- if (typeof key != 'string')
7940
+ if (typeof key != "string")
7678
7941
  throw "Unknown key name or key type (should be a string or integer): " + key;
7679
7942
  if (KeyHandler.KEY_CODES[key])
7680
7943
  return KeyHandler.KEY_CODES[key];
7681
7944
  throw "Unknown key (cannot resolve key code): " + key;
7682
7945
  }
7683
- ;
7684
7946
  /**
7685
7947
  * Install the required listeners into the initially passed element.
7686
7948
  *
@@ -7689,20 +7951,24 @@ class KeyHandler {
7689
7951
  */
7690
7952
  installListeners() {
7691
7953
  var _self = this;
7692
- this.element.addEventListener('keydown', this._keyDownListener = (e) => { _self.fireDownEvent(e, _self); });
7693
- this.element.addEventListener('keypress', this._keyPressListener = (e) => { _self.firePressEvent(e, _self); });
7694
- this.element.addEventListener('keyup', this._keyUpListener = (e) => { _self.fireUpEvent(e, _self); });
7954
+ this.element.addEventListener("keydown", (this._keyDownListener = (e) => {
7955
+ _self.fireDownEvent(e, _self);
7956
+ }));
7957
+ this.element.addEventListener("keypress", (this._keyPressListener = (e) => {
7958
+ _self.firePressEvent(e, _self);
7959
+ }));
7960
+ this.element.addEventListener("keyup", (this._keyUpListener = (e) => {
7961
+ _self.fireUpEvent(e, _self);
7962
+ }));
7695
7963
  }
7696
- ;
7697
7964
  /**
7698
7965
  * Remove all installed event listeners from the underlying element.
7699
7966
  */
7700
7967
  releaseListeners() {
7701
- this.element.removeEventListener('keydown', this._keyDownListener);
7702
- this.element.removeEventListener('keypress', this._keyPressListener);
7703
- this.element.removeEventListener('keyup', this._keyUpListener);
7968
+ this.element.removeEventListener("keydown", this._keyDownListener);
7969
+ this.element.removeEventListener("keypress", this._keyPressListener);
7970
+ this.element.removeEventListener("keyup", this._keyUpListener);
7704
7971
  }
7705
- ;
7706
7972
  /**
7707
7973
  * Listen for key down. This function allows chaining.
7708
7974
  *
@@ -7719,7 +7985,6 @@ class KeyHandler {
7719
7985
  this.downListeners.push({ key: key, keyCode: KeyHandler.key2code(key), listener: listener });
7720
7986
  return this;
7721
7987
  }
7722
- ;
7723
7988
  /**
7724
7989
  * Listen for key press.
7725
7990
  *
@@ -7736,7 +8001,6 @@ class KeyHandler {
7736
8001
  this.pressListeners.push({ key: key, keyCode: KeyHandler.key2code(key), listener: listener });
7737
8002
  return this;
7738
8003
  }
7739
- ;
7740
8004
  /**
7741
8005
  * Listen for key up.
7742
8006
  *
@@ -7753,23 +8017,31 @@ class KeyHandler {
7753
8017
  this.upListeners.push({ key: key, keyCode: KeyHandler.key2code(key), listener: listener });
7754
8018
  return this;
7755
8019
  }
7756
- ;
7757
8020
  /**
7758
8021
  * Check if a specific key is currently held pressed.
7759
8022
  *
7760
8023
  * @param {string|number} key - Any key identifier, key code or one from the KEY_CODES list.
7761
8024
  */
7762
8025
  isDown(key) {
7763
- if (typeof key == 'number')
8026
+ if (typeof key == "number")
7764
8027
  return this.keyStates[key] ? true : false;
7765
8028
  else
7766
8029
  return this.keyStates[KeyHandler.key2code(key)] ? true : false;
7767
8030
  }
8031
+ /**
8032
+ * This function should invalidate any installed listeners and invalidate this object.
8033
+ * After calling this function the object might not hold valid data any more and
8034
+ * should not be used any more.
8035
+ */
8036
+ destroy() {
8037
+ this.releaseListeners();
8038
+ }
7768
8039
  }
7769
8040
  /**
7770
8041
  * Source:
7771
8042
  * https://keycode.info/
7772
8043
  */
8044
+ // prettier-ignore
7773
8045
  KeyHandler.KEY_CODES = {
7774
8046
  'break': 3,
7775
8047
  'backspace': 8,
@@ -8086,41 +8358,41 @@ class MouseHandler {
8086
8358
  // | drag offset, ...) to the callbacks.
8087
8359
  // +-------------------------------------------------
8088
8360
  const _self = this;
8089
- this.handlers['mousemove'] = (e) => {
8361
+ this.handlers["mousemove"] = (e) => {
8090
8362
  if (_self.listeners.mousemove)
8091
- _self.listeners.mousemove(_self.mkParams(e, 'mousemove'));
8363
+ _self.listeners.mousemove(_self.mkParams(e, "mousemove"));
8092
8364
  if (_self.mouseDragPos && _self.listeners.drag)
8093
- _self.listeners.drag(_self.mkParams(e, 'drag'));
8365
+ _self.listeners.drag(_self.mkParams(e, "drag"));
8094
8366
  if (_self.mouseDownPos)
8095
8367
  _self.mouseDragPos = _self.relPos(e);
8096
8368
  };
8097
- this.handlers['mouseup'] = (e) => {
8369
+ this.handlers["mouseup"] = (e) => {
8098
8370
  if (_self.listeners.mouseup)
8099
- _self.listeners.mouseup(_self.mkParams(e, 'mouseup'));
8371
+ _self.listeners.mouseup(_self.mkParams(e, "mouseup"));
8100
8372
  _self.mouseDragPos = undefined;
8101
8373
  _self.mouseDownPos = undefined;
8102
8374
  _self.mouseButton = -1;
8103
8375
  };
8104
- this.handlers['mousedown'] = (e) => {
8376
+ this.handlers["mousedown"] = (e) => {
8105
8377
  _self.mouseDragPos = _self.relPos(e);
8106
8378
  _self.mouseDownPos = _self.relPos(e);
8107
8379
  _self.mouseButton = e.button;
8108
8380
  if (_self.listeners.mousedown)
8109
- _self.listeners.mousedown(_self.mkParams(e, 'mousedown'));
8381
+ _self.listeners.mousedown(_self.mkParams(e, "mousedown"));
8110
8382
  };
8111
- this.handlers['click'] = (e) => {
8383
+ this.handlers["click"] = (e) => {
8112
8384
  if (_self.listeners.click)
8113
- _self.listeners.click(_self.mkParams(e, 'click'));
8385
+ _self.listeners.click(_self.mkParams(e, "click"));
8114
8386
  };
8115
- this.handlers['wheel'] = (e) => {
8387
+ this.handlers["wheel"] = (e) => {
8116
8388
  if (_self.listeners.wheel)
8117
- _self.listeners.wheel(_self.mkParams(e, 'wheel'));
8389
+ _self.listeners.wheel(_self.mkParams(e, "wheel"));
8118
8390
  };
8119
- this.element.addEventListener('mousemove', this.handlers['mousemove']);
8120
- this.element.addEventListener('mouseup', this.handlers['mouseup']);
8121
- this.element.addEventListener('mousedown', this.handlers['mousedown']);
8122
- this.element.addEventListener('click', this.handlers['click']);
8123
- this.element.addEventListener('wheel', this.handlers['wheel']);
8391
+ this.element.addEventListener("mousemove", this.handlers["mousemove"]);
8392
+ this.element.addEventListener("mouseup", this.handlers["mouseup"]);
8393
+ this.element.addEventListener("mousedown", this.handlers["mousedown"]);
8394
+ this.element.addEventListener("click", this.handlers["click"]);
8395
+ this.element.addEventListener("wheel", this.handlers["wheel"]);
8124
8396
  }
8125
8397
  /**
8126
8398
  * Get relative position from the given MouseEvent.
@@ -8133,11 +8405,8 @@ class MouseHandler {
8133
8405
  * @return {XYCoords} The relative mouse coordinates.
8134
8406
  */
8135
8407
  relPos(e) {
8136
- return { x: e.offsetX,
8137
- y: e.offsetY
8138
- };
8408
+ return { x: e.offsetX, y: e.offsetY };
8139
8409
  }
8140
- ;
8141
8410
  /**
8142
8411
  * Build the extended event params.
8143
8412
  *
@@ -8163,8 +8432,8 @@ class MouseHandler {
8163
8432
  rightButton: this.mouseButton == 2,
8164
8433
  mouseDownPos: this.mouseDownPos,
8165
8434
  draggedFrom: this.mouseDragPos,
8166
- wasDragged: (this.mouseDownPos != null && (this.mouseDownPos.x != rel.x || this.mouseDownPos.y != rel.y)),
8167
- dragAmount: (this.mouseDownPos != null ? { x: rel.x - this.mouseDragPos.x, y: rel.y - this.mouseDragPos.y } : { x: 0, y: 0 })
8435
+ wasDragged: this.mouseDownPos != null && (this.mouseDownPos.x != rel.x || this.mouseDownPos.y != rel.y),
8436
+ dragAmount: this.mouseDownPos != null ? { x: rel.x - this.mouseDragPos.x, y: rel.y - this.mouseDragPos.y } : { x: 0, y: 0 }
8168
8437
  };
8169
8438
  return xEvent;
8170
8439
  }
@@ -8215,14 +8484,13 @@ class MouseHandler {
8215
8484
  */
8216
8485
  drag(callback) {
8217
8486
  if (this.listeners.drag)
8218
- this.throwAlreadyInstalled('drag');
8487
+ this.throwAlreadyInstalled("drag");
8219
8488
  this.listeners.drag = callback;
8220
- this.listenFor('mousedown');
8221
- this.listenFor('mousemove');
8222
- this.listenFor('mouseup');
8489
+ this.listenFor("mousedown");
8490
+ this.listenFor("mousemove");
8491
+ this.listenFor("mouseup");
8223
8492
  return this;
8224
8493
  }
8225
- ;
8226
8494
  /**
8227
8495
  * Installer function to listen for a specific event: mouse-move.
8228
8496
  * Pass your callbacks here.
@@ -8237,12 +8505,11 @@ class MouseHandler {
8237
8505
  */
8238
8506
  move(callback) {
8239
8507
  if (this.listeners.mousemove)
8240
- this.throwAlreadyInstalled('mousemove');
8241
- this.listenFor('mousemove');
8508
+ this.throwAlreadyInstalled("mousemove");
8509
+ this.listenFor("mousemove");
8242
8510
  this.listeners.mousemove = callback;
8243
8511
  return this;
8244
8512
  }
8245
- ;
8246
8513
  /**
8247
8514
  * Installer function to listen for a specific event: mouse-up.
8248
8515
  * Pass your callbacks here.
@@ -8257,12 +8524,11 @@ class MouseHandler {
8257
8524
  */
8258
8525
  up(callback) {
8259
8526
  if (this.listeners.mouseup)
8260
- this.throwAlreadyInstalled('mouseup');
8261
- this.listenFor('mouseup');
8527
+ this.throwAlreadyInstalled("mouseup");
8528
+ this.listenFor("mouseup");
8262
8529
  this.listeners.mouseup = callback;
8263
8530
  return this;
8264
8531
  }
8265
- ;
8266
8532
  /**
8267
8533
  * Installer function to listen for a specific event: mouse-down.
8268
8534
  * Pass your callbacks here.
@@ -8277,12 +8543,11 @@ class MouseHandler {
8277
8543
  */
8278
8544
  down(callback) {
8279
8545
  if (this.listeners.mousedown)
8280
- this.throwAlreadyInstalled('mousedown');
8281
- this.listenFor('mousedown');
8546
+ this.throwAlreadyInstalled("mousedown");
8547
+ this.listenFor("mousedown");
8282
8548
  this.listeners.mousedown = callback;
8283
8549
  return this;
8284
8550
  }
8285
- ;
8286
8551
  /**
8287
8552
  * Installer function to listen for a specific event: mouse-click.
8288
8553
  * Pass your callbacks here.
@@ -8297,12 +8562,11 @@ class MouseHandler {
8297
8562
  */
8298
8563
  click(callback) {
8299
8564
  if (this.listeners.click)
8300
- this.throwAlreadyInstalled('click');
8301
- this.listenFor('click');
8565
+ this.throwAlreadyInstalled("click");
8566
+ this.listenFor("click");
8302
8567
  this.listeners.click = callback;
8303
8568
  return this;
8304
8569
  }
8305
- ;
8306
8570
  /**
8307
8571
  * Installer function to listen for a specific event: mouse-wheel.
8308
8572
  * Pass your callbacks here.
@@ -8317,12 +8581,11 @@ class MouseHandler {
8317
8581
  */
8318
8582
  wheel(callback) {
8319
8583
  if (this.listeners.wheel)
8320
- this.throwAlreadyInstalled('wheel');
8321
- this.listenFor('wheel');
8584
+ this.throwAlreadyInstalled("wheel");
8585
+ this.listenFor("wheel");
8322
8586
  this.listeners.wheel = callback;
8323
8587
  return this;
8324
8588
  }
8325
- ;
8326
8589
  /**
8327
8590
  * An internal function to throw events.
8328
8591
  *
@@ -8336,7 +8599,6 @@ class MouseHandler {
8336
8599
  throwAlreadyInstalled(name) {
8337
8600
  throw `This MouseHandler already has a '${name}' callback. To keep the code simple there is only room for one.`;
8338
8601
  }
8339
- ;
8340
8602
  /**
8341
8603
  * Call this when your work is done.
8342
8604
  *
@@ -8349,16 +8611,16 @@ class MouseHandler {
8349
8611
  * @return {void}
8350
8612
  */
8351
8613
  destroy() {
8352
- this.unlistenFor('mousedown');
8353
- this.unlistenFor('mousemove');
8354
- this.unlistenFor('moseup');
8355
- this.unlistenFor('click');
8356
- this.unlistenFor('wheel');
8357
- this.element.removeEventListener('mousemove', this.handlers['mousemove']);
8358
- this.element.removeEventListener('mouseup', this.handlers['mousedown']);
8359
- this.element.removeEventListener('mousedown', this.handlers['mousedown']);
8360
- this.element.removeEventListener('click', this.handlers['click']);
8361
- this.element.removeEventListener('wheel', this.handlers['wheel']);
8614
+ this.unlistenFor("mousedown");
8615
+ this.unlistenFor("mousemove");
8616
+ this.unlistenFor("moseup");
8617
+ this.unlistenFor("click");
8618
+ this.unlistenFor("wheel");
8619
+ this.element.removeEventListener("mousemove", this.handlers["mousemove"]);
8620
+ this.element.removeEventListener("mouseup", this.handlers["mousedown"]);
8621
+ this.element.removeEventListener("mousedown", this.handlers["mousedown"]);
8622
+ this.element.removeEventListener("click", this.handlers["click"]);
8623
+ this.element.removeEventListener("wheel", this.handlers["wheel"]);
8362
8624
  }
8363
8625
  }
8364
8626
 
@@ -8368,7 +8630,9 @@ class MouseHandler {
8368
8630
  * @modified 2019-03-23 Added JSDoc tags.
8369
8631
  * @modified 2020-03-25 Ported this class from vanilla-JS to Typescript.
8370
8632
  * @modified 2021-01-20 Added UID.
8371
- * @version 1.1.0
8633
+ * @modified 2022-02-02 Added the `destroy` method.
8634
+ * @modified 2022-02-02 Cleared the `PBImage.toSVGString` function (deprecated). Use `drawutilssvg` instead.
8635
+ * @version 1.2.0
8372
8636
  *
8373
8637
  * @file PBImage
8374
8638
  * @fileoverview As native Image objects have only a position and with
@@ -8403,28 +8667,23 @@ class PBImage {
8403
8667
  this.upperLeft = upperLeft;
8404
8668
  this.lowerRight = lowerRight;
8405
8669
  }
8406
- ;
8407
8670
  /**
8408
- * Convert this vertex to SVG code.
8409
- *
8410
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
8411
- * @method toSVGString
8412
- * @param {object=} options - An optional set of options, like 'className'.
8413
- * @return {string} A string representing the SVG code for this vertex.
8414
- * @instance
8415
- * @memberof PBImage
8416
- **/
8417
- toSVGString(options) {
8418
- console.warn("PBImage is not yet SVG serializable. Returning empty SVG string.");
8419
- return "";
8671
+ * This function should invalidate any installed listeners and invalidate this object.
8672
+ * After calling this function the object might not hold valid data any more and
8673
+ * should not be used.
8674
+ */
8675
+ destroy() {
8676
+ this.upperLeft.destroy();
8677
+ this.lowerRight.destroy();
8678
+ this.isDestroyed = true;
8420
8679
  }
8421
- ;
8422
8680
  }
8423
8681
 
8424
8682
  /**
8425
8683
  * @author Ikaros Kappler
8426
8684
  * @date 2021-11-16
8427
- * @version 1.0.0
8685
+ * @modified 2022-02-02 Added the `destroy` method.
8686
+ * @version 1.1.0
8428
8687
  **/
8429
8688
  /**
8430
8689
  * @classdesc A simple text element: position, fontSize, fontFamily, color, textAlign, lineHeight and rotation.
@@ -8465,18 +8724,13 @@ class PBText {
8465
8724
  this.rotation = options.rotation;
8466
8725
  }
8467
8726
  /**
8468
- * Create an SVG representation of this circle.
8469
- *
8470
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
8471
- * @method toSVGString
8472
- * @param {object=} options - An optional set of options, like 'className'.
8473
- * @return {string} A string representing the SVG code for this vertex.
8474
- * @instance
8475
- * @memberof Circle
8727
+ * This function should invalidate any installed listeners and invalidate this object.
8728
+ * After calling this function the object might not hold valid data any more and
8729
+ * should not be used.
8476
8730
  */
8477
- toSVGString(options) {
8478
- console.warn("[PBText.toSVGString()] This function is not implemented as it defines a deprecated method. Use the 'drawutilssvg.text()' method instead.");
8479
- return "";
8731
+ destroy() {
8732
+ this.anchor.destroy();
8733
+ this.isDestroyed = true;
8480
8734
  }
8481
8735
  } // END class
8482
8736
 
@@ -8881,7 +9135,9 @@ class AlloyFinger {
8881
9135
  * @modified 2021-03-10 Added the `toCubicBezier` method.
8882
9136
  * @modified 2021-03-15 Added `VEllipse.quarterSegmentCount` and `VEllipse.scale` functions.
8883
9137
  * @modified 2021-03-19 Added the `VEllipse.rotate` function.
8884
- * @version 1.2.2
9138
+ * @modified 2022-02-02 Added the `destroy` method.
9139
+ * @modified 2022-02-02 Cleared the `VEllipse.toSVGString` function (deprecated). Use `drawutilssvg` instead.
9140
+ * @version 1.3.0
8885
9141
  *
8886
9142
  * @file VEllipse
8887
9143
  * @fileoverview Ellipses with a center and an x- and a y-axis (stored as a vertex).
@@ -9200,24 +9456,14 @@ class VEllipse {
9200
9456
  return curves;
9201
9457
  }
9202
9458
  /**
9203
- * Create an SVG representation of this ellipse.
9204
- *
9205
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
9206
- * @param {object} options { className?:string }
9207
- * @return string The SVG string
9459
+ * This function should invalidate any installed listeners and invalidate this object.
9460
+ * After calling this function the object might not hold valid data any more and
9461
+ * should not be used.
9208
9462
  */
9209
- toSVGString(options) {
9210
- options = options || {};
9211
- var buffer = [];
9212
- buffer.push("<ellipse");
9213
- if (options.className)
9214
- buffer.push(' class="' + options.className + '"');
9215
- buffer.push(' cx="' + this.center.x + '"');
9216
- buffer.push(' cy="' + this.center.y + '"');
9217
- buffer.push(' rx="' + this.axis.x + '"');
9218
- buffer.push(' ry="' + this.axis.y + '"');
9219
- buffer.push(" />");
9220
- return buffer.join("");
9463
+ destroy() {
9464
+ this.center.destroy();
9465
+ this.axis.destroy();
9466
+ this.isDestroyed = true;
9221
9467
  }
9222
9468
  }
9223
9469
  /**
@@ -9284,7 +9530,8 @@ VEllipse.utils = {
9284
9530
  *
9285
9531
  * @author Ikaros Kappler
9286
9532
  * @date 2021-02-26
9287
- * @version 1.0.0
9533
+ * @modified 2022-02-02 Added the `destroy` method.
9534
+ * @version 1.1.0
9288
9535
  */
9289
9536
  /**
9290
9537
  * @classdesc A class for elliptic sectors.
@@ -9370,6 +9617,15 @@ class VEllipseSector {
9370
9617
  }
9371
9618
  return curves;
9372
9619
  }
9620
+ /**
9621
+ * This function should invalidate any installed listeners and invalidate this object.
9622
+ * After calling this function the object might not hold valid data any more and
9623
+ * should not be used.
9624
+ */
9625
+ destroy() {
9626
+ this.ellipse.destroy();
9627
+ this.isDestroyed = true;
9628
+ }
9373
9629
  }
9374
9630
  VEllipseSector.ellipseSectorUtils = {
9375
9631
  /**
@@ -10220,7 +10476,7 @@ class PlotBoilerplate {
10220
10476
  }
10221
10477
  }
10222
10478
  for (var i = 0; i < this.drawables.length; i++) {
10223
- if (this.drawables[i] === drawable) {
10479
+ if (this.drawables[i] === drawable || this.drawables[i].uid === drawable.uid) {
10224
10480
  this.drawables.splice(i, 1);
10225
10481
  if (removeWithVertices) {
10226
10482
  // Check if some listeners need to be removed
@@ -10332,8 +10588,9 @@ class PlotBoilerplate {
10332
10588
  **/
10333
10589
  getVertexNear(pixelPosition, pixelTolerance) {
10334
10590
  var p = this.locatePointNear(this.transformMousePosition(pixelPosition.x, pixelPosition.y), pixelTolerance / Math.min(this.config.cssScaleX, this.config.cssScaleY));
10335
- if (p && p.typeName == "vertex")
10591
+ if (p && p.typeName == "vertex") {
10336
10592
  return this.vertices[p.vindex];
10593
+ }
10337
10594
  return undefined;
10338
10595
  }
10339
10596
  /**
@@ -11599,100 +11856,5 @@ PlotBoilerplate.utils = {
11599
11856
  }
11600
11857
  }; // END utils
11601
11858
 
11602
- /**
11603
- * Todos:
11604
- * + use a Drawable interface
11605
- * + use a SVGSerializable interface
11606
- *
11607
- * @require Vertex
11608
- *
11609
- * @deprecated THIS CLASS IS DEPRECATED. Please use the new `drawutilssvg` instead.
11610
- *
11611
- * @author Ikaros Kappler
11612
- * @date 2018-12-04
11613
- * @modified 2019-11-07 Added the 'Triangle' style class.
11614
- * @modified 2019-11-13 Added the <?xml ...?> tag.
11615
- * @modified 2020-03-25 Ported this class from vanilla-JS to Typescript.
11616
- * @modified 2020-12-17 Added Circle and CircleSection style classes.
11617
- * @modified 2021-01-26 DEPRECATION
11618
- * @version 1.0.5
11619
- **/
11620
- /**
11621
- * @classdesc A default SVG builder.
11622
- *
11623
- * @requires SVGSerializable
11624
- * @requires Vertex
11625
- */
11626
- class SVGBuilder {
11627
- /**
11628
- * @constructor
11629
- **/
11630
- constructor() {
11631
- console.warn("THIS CLASS IS DEPRECATED. Please use the new 'drawutilssvg' instead.");
11632
- }
11633
- ;
11634
- /**
11635
- * Builds the SVG code from the given list of drawables.
11636
- *
11637
- * @param {object[]} drawables - The drawable elements (should implement Drawable) to be converted (each must have a toSVGString-function).
11638
- * @param {object} options - { canvasSize, zoom, offset }
11639
- * @return {string}
11640
- **/
11641
- build(drawables, options) {
11642
- var nl = '\n';
11643
- var indent = ' ';
11644
- var buffer = [];
11645
- buffer.push('<?xml version="1.0" encoding="UTF-8"?>' + nl);
11646
- buffer.push('<svg width="' + options.canvasSize.width + '" height="' + options.canvasSize.height + '"');
11647
- buffer.push(' viewBox="');
11648
- buffer.push('0');
11649
- buffer.push(' ');
11650
- buffer.push('0');
11651
- buffer.push(' ');
11652
- buffer.push(options.canvasSize.width.toString());
11653
- buffer.push(' ');
11654
- buffer.push(options.canvasSize.height.toString());
11655
- buffer.push('"');
11656
- buffer.push(' xmlns="http://www.w3.org/2000/svg">' + nl);
11657
- buffer.push(indent + '<defs>' + nl);
11658
- buffer.push(indent + '<style>' + nl);
11659
- buffer.push(indent + indent + ' .Vertex { fill : blue; stroke : none; } ' + nl);
11660
- buffer.push(indent + indent + ' .Triangle { fill : none; stroke : turquoise; stroke-width : 1px; } ' + nl);
11661
- buffer.push(indent + indent + ' .Polygon { fill : none; stroke : green; stroke-width : 2px; } ' + nl);
11662
- buffer.push(indent + indent + ' .BezierPath { fill : none; stroke : blue; stroke-width : 2px; } ' + nl);
11663
- buffer.push(indent + indent + ' .VEllipse { fill : none; stroke : black; stroke-width : 1px; } ' + nl);
11664
- buffer.push(indent + indent + ' .Line { fill : none; stroke : purple; stroke-width : 1px; } ' + nl);
11665
- buffer.push(indent + indent + ' .Circle { fill : none; stroke : purple; stroke-width : 1px; } ' + nl);
11666
- buffer.push(indent + indent + ' .CircleSector { fill : none; stroke : purple; stroke-width : 1px; } ' + nl);
11667
- buffer.push(indent + '</style>' + nl);
11668
- buffer.push(indent + '</defs>' + nl);
11669
- buffer.push(indent + '<g class="main-g"');
11670
- if (options.zoom || options.offset) {
11671
- buffer.push(' transform="');
11672
- if (options.zoom)
11673
- buffer.push('scale(' + options.zoom.x + ',' + options.zoom.y + ')');
11674
- if (options.offset)
11675
- buffer.push(' translate(' + options.offset.x + ',' + options.offset.y + ')');
11676
- buffer.push('"');
11677
- }
11678
- buffer.push('>' + nl);
11679
- for (var i in drawables) {
11680
- var d = drawables[i];
11681
- if (typeof d.toSVGString == 'function') {
11682
- buffer.push(indent + indent);
11683
- buffer.push(d.toSVGString({ 'className': d.className }));
11684
- buffer.push(nl);
11685
- }
11686
- else {
11687
- console.warn('Unrecognized drawable type has no toSVGString()-function. Ignoring: ' + d.className);
11688
- }
11689
- }
11690
- buffer.push(indent + '</g>' + nl);
11691
- buffer.push('</svg>' + nl);
11692
- return buffer.join('');
11693
- }
11694
- ;
11695
- }
11696
-
11697
- export { BezierPath, Bounds, Circle, CircleSector, CubicBezierCurve, Grid, KeyHandler, Line, MouseHandler, PBImage, PBText, PlotBoilerplate, Polygon, SVGBuilder, Triangle, UIDGenerator, VEllipse, VEllipseSector, Vector, VertTuple, Vertex, VertexAttr, VertexListeners, XMouseEvent, XWheelEvent, drawutils, drawutilsgl, drawutilssvg, geomutils };
11859
+ export { BezierPath, Bounds, Circle, CircleSector, CubicBezierCurve, Grid, KeyHandler, Line, MouseHandler, PBImage, PBText, PlotBoilerplate, Polygon, Triangle, UIDGenerator, VEllipse, VEllipseSector, Vector, VertTuple, Vertex, VertexAttr, VertexListeners, XMouseEvent, XWheelEvent, drawutils, drawutilsgl, drawutilssvg, geomutils };
11698
11860
  //# sourceMappingURL=index.esm.js.map