plotboilerplate 1.15.0 → 1.17.1

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 (237) hide show
  1. package/README.md +1 -0
  2. package/changelog.md +65 -0
  3. package/dist/index.esm.js +760 -667
  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 +765 -571
  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 +33 -1
  16. package/src/cjs/Bounds.js +38 -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.d.ts +3 -1
  42. package/src/cjs/PlotBoilerplate.js +9 -2
  43. package/src/cjs/PlotBoilerplate.js.map +1 -1
  44. package/src/cjs/Polygon.d.ts +23 -14
  45. package/src/cjs/Polygon.js +22 -35
  46. package/src/cjs/Polygon.js.map +1 -1
  47. package/src/cjs/Triangle.d.ts +15 -13
  48. package/src/cjs/Triangle.js +23 -64
  49. package/src/cjs/Triangle.js.map +1 -1
  50. package/src/cjs/VEllipse.d.ts +14 -9
  51. package/src/cjs/VEllipse.js +10 -18
  52. package/src/cjs/VEllipse.js.map +1 -1
  53. package/src/cjs/VEllipseSector.d.ts +15 -1
  54. package/src/cjs/VEllipseSector.js +11 -1
  55. package/src/cjs/VEllipseSector.js.map +1 -1
  56. package/src/cjs/Vector.d.ts +3 -15
  57. package/src/cjs/Vector.js +9 -49
  58. package/src/cjs/Vector.js.map +1 -1
  59. package/src/cjs/VertTuple.d.ts +15 -1
  60. package/src/cjs/VertTuple.js +14 -19
  61. package/src/cjs/VertTuple.js.map +1 -1
  62. package/src/cjs/Vertex.d.ts +23 -13
  63. package/src/cjs/Vertex.js +24 -22
  64. package/src/cjs/Vertex.js.map +1 -1
  65. package/src/cjs/VertexListeners.d.ts +12 -8
  66. package/src/cjs/VertexListeners.js +18 -25
  67. package/src/cjs/VertexListeners.js.map +1 -1
  68. package/src/cjs/draw.d.ts +45 -3
  69. package/src/cjs/draw.js +149 -6
  70. package/src/cjs/draw.js.map +1 -1
  71. package/src/cjs/drawgl.d.ts +41 -3
  72. package/src/cjs/drawgl.js +45 -3
  73. package/src/cjs/drawgl.js.map +1 -1
  74. package/src/cjs/drawutilssvg.d.ts +69 -4
  75. package/src/cjs/drawutilssvg.js +147 -16
  76. package/src/cjs/drawutilssvg.js.map +1 -1
  77. package/src/cjs/index.d.ts +0 -1
  78. package/src/cjs/index.js +0 -1
  79. package/src/cjs/index.js.map +1 -1
  80. package/src/cjs/interfaces/DrawLib.d.ts +64 -27
  81. package/src/cjs/interfaces/DrawLib.js +3 -0
  82. package/src/cjs/interfaces/DrawLib.js.map +1 -1
  83. package/src/cjs/interfaces/core.d.ts +2 -12
  84. package/src/cjs/interfaces/core.js +1 -0
  85. package/src/cjs/interfaces/core.js.map +1 -1
  86. package/src/cjs/module.d.ts +1 -3
  87. package/src/cjs/module.js +2 -5
  88. package/src/cjs/module.js.map +1 -1
  89. package/src/cjs/utils/creategui.js +16 -2
  90. package/src/cjs/utils/datastructures/Color.d.ts +3 -1
  91. package/src/cjs/utils/datastructures/Color.js +17 -6
  92. package/src/cjs/utils/datastructures/Color.js.map +1 -1
  93. package/src/cjs/utils/datastructures/Girih.d.ts +5 -0
  94. package/src/cjs/utils/datastructures/Girih.js +18 -14
  95. package/src/cjs/utils/datastructures/Girih.js.map +1 -1
  96. package/src/cjs/utils/datastructures/GirihPenroseRhombus.js +42 -25
  97. package/src/cjs/utils/datastructures/GirihPenroseRhombus.js.map +1 -1
  98. package/src/cjs/utils/datastructures/GirihTile.js +2 -13
  99. package/src/cjs/utils/datastructures/GirihTile.js.map +1 -1
  100. package/src/cjs/utils/helpers/BezierPathInteractionHelper.d.ts +17 -1
  101. package/src/cjs/utils/helpers/BezierPathInteractionHelper.js +50 -32
  102. package/src/cjs/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
  103. package/src/cjs/utils/io/DndFileHandler.d.ts +63 -0
  104. package/src/cjs/utils/io/DndFileHandler.js +112 -0
  105. package/src/cjs/utils/io/DndFileHandler.js.map +1 -0
  106. package/src/cjs/utils/io/FileDrop.d.ts +98 -0
  107. package/src/cjs/utils/io/FileDrop.js +142 -0
  108. package/src/cjs/utils/io/FileDrop.js.map +1 -0
  109. package/src/esm/BezierPath.d.ts +32 -14
  110. package/src/esm/BezierPath.js +65 -24
  111. package/src/esm/BezierPath.js.map +1 -1
  112. package/src/esm/Bounds.d.ts +33 -1
  113. package/src/esm/Bounds.js +38 -1
  114. package/src/esm/Bounds.js.map +1 -1
  115. package/src/esm/Circle.d.ts +15 -13
  116. package/src/esm/Circle.js +16 -34
  117. package/src/esm/Circle.js.map +1 -1
  118. package/src/esm/CircleSector.d.ts +17 -16
  119. package/src/esm/CircleSector.js +12 -24
  120. package/src/esm/CircleSector.js.map +1 -1
  121. package/src/esm/CubicBezierCurve.d.ts +16 -15
  122. package/src/esm/CubicBezierCurve.js +57 -94
  123. package/src/esm/CubicBezierCurve.js.map +1 -1
  124. package/src/esm/KeyHandler.d.ts +10 -3
  125. package/src/esm/KeyHandler.js +28 -23
  126. package/src/esm/KeyHandler.js.map +1 -1
  127. package/src/esm/Line.d.ts +2 -15
  128. package/src/esm/Line.js +6 -31
  129. package/src/esm/Line.js.map +1 -1
  130. package/src/esm/MouseHandler.js +43 -53
  131. package/src/esm/MouseHandler.js.map +1 -1
  132. package/src/esm/PBImage.d.ts +15 -13
  133. package/src/esm/PBImage.js +11 -15
  134. package/src/esm/PBImage.js.map +1 -1
  135. package/src/esm/PBText.d.ts +13 -12
  136. package/src/esm/PBText.js +8 -12
  137. package/src/esm/PBText.js.map +1 -1
  138. package/src/esm/PlotBoilerplate.d.ts +3 -1
  139. package/src/esm/PlotBoilerplate.js +9 -2
  140. package/src/esm/PlotBoilerplate.js.map +1 -1
  141. package/src/esm/Polygon.d.ts +23 -14
  142. package/src/esm/Polygon.js +22 -35
  143. package/src/esm/Polygon.js.map +1 -1
  144. package/src/esm/Triangle.d.ts +15 -13
  145. package/src/esm/Triangle.js +23 -64
  146. package/src/esm/Triangle.js.map +1 -1
  147. package/src/esm/VEllipse.d.ts +14 -9
  148. package/src/esm/VEllipse.js +10 -18
  149. package/src/esm/VEllipse.js.map +1 -1
  150. package/src/esm/VEllipseSector.d.ts +15 -1
  151. package/src/esm/VEllipseSector.js +11 -1
  152. package/src/esm/VEllipseSector.js.map +1 -1
  153. package/src/esm/Vector.d.ts +3 -15
  154. package/src/esm/Vector.js +9 -49
  155. package/src/esm/Vector.js.map +1 -1
  156. package/src/esm/VertTuple.d.ts +15 -1
  157. package/src/esm/VertTuple.js +14 -19
  158. package/src/esm/VertTuple.js.map +1 -1
  159. package/src/esm/Vertex.d.ts +23 -13
  160. package/src/esm/Vertex.js +24 -22
  161. package/src/esm/Vertex.js.map +1 -1
  162. package/src/esm/VertexListeners.d.ts +12 -8
  163. package/src/esm/VertexListeners.js +18 -25
  164. package/src/esm/VertexListeners.js.map +1 -1
  165. package/src/esm/draw.d.ts +45 -3
  166. package/src/esm/draw.js +147 -6
  167. package/src/esm/draw.js.map +1 -1
  168. package/src/esm/drawgl.d.ts +41 -3
  169. package/src/esm/drawgl.js +44 -3
  170. package/src/esm/drawgl.js.map +1 -1
  171. package/src/esm/drawutilssvg.d.ts +69 -4
  172. package/src/esm/drawutilssvg.js +146 -16
  173. package/src/esm/drawutilssvg.js.map +1 -1
  174. package/src/esm/index.d.ts +0 -1
  175. package/src/esm/index.js +0 -1
  176. package/src/esm/index.js.map +1 -1
  177. package/src/esm/interfaces/DrawLib.d.ts +64 -27
  178. package/src/esm/interfaces/DrawLib.js +3 -0
  179. package/src/esm/interfaces/DrawLib.js.map +1 -1
  180. package/src/esm/interfaces/core.d.ts +2 -12
  181. package/src/esm/interfaces/core.js +1 -0
  182. package/src/esm/interfaces/core.js.map +1 -1
  183. package/src/esm/module.d.ts +1 -3
  184. package/src/esm/module.js +5 -4
  185. package/src/esm/module.js.map +1 -1
  186. package/src/esm/utils/datastructures/Color.d.ts +3 -1
  187. package/src/esm/utils/datastructures/Color.js +17 -6
  188. package/src/esm/utils/datastructures/Color.js.map +1 -1
  189. package/src/esm/utils/datastructures/Girih.d.ts +5 -0
  190. package/src/esm/utils/datastructures/Girih.js +18 -14
  191. package/src/esm/utils/datastructures/Girih.js.map +1 -1
  192. package/src/esm/utils/datastructures/GirihPenroseRhombus.js +42 -25
  193. package/src/esm/utils/datastructures/GirihPenroseRhombus.js.map +1 -1
  194. package/src/esm/utils/datastructures/GirihTile.js +2 -13
  195. package/src/esm/utils/datastructures/GirihTile.js.map +1 -1
  196. package/src/esm/utils/helpers/BezierPathInteractionHelper.d.ts +17 -1
  197. package/src/esm/utils/helpers/BezierPathInteractionHelper.js +49 -32
  198. package/src/esm/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
  199. package/src/esm/utils/io/DndFileHandler.d.ts +63 -0
  200. package/src/esm/utils/io/DndFileHandler.js +106 -0
  201. package/src/esm/utils/io/DndFileHandler.js.map +1 -0
  202. package/src/esm/utils/io/FileDrop.d.ts +98 -0
  203. package/src/esm/utils/io/FileDrop.js +136 -0
  204. package/src/esm/utils/io/FileDrop.js.map +1 -0
  205. package/src/ts/BezierPath.ts +78 -22
  206. package/src/ts/Bounds.ts +40 -1
  207. package/src/ts/Circle.ts +187 -200
  208. package/src/ts/CircleSector.ts +141 -141
  209. package/src/ts/CubicBezierCurve.ts +738 -810
  210. package/src/ts/KeyHandler.ts +221 -212
  211. package/src/ts/Line.ts +48 -80
  212. package/src/ts/MouseHandler.ts +356 -368
  213. package/src/ts/PBImage.ts +67 -69
  214. package/src/ts/PBText.ts +16 -14
  215. package/src/ts/PlotBoilerplate.ts +9 -2
  216. package/src/ts/Polygon.ts +34 -34
  217. package/src/ts/Triangle.ts +444 -489
  218. package/src/ts/VEllipse.ts +18 -17
  219. package/src/ts/VEllipseSector.ts +20 -1
  220. package/src/ts/Vector.ts +124 -160
  221. package/src/ts/VertTuple.ts +333 -338
  222. package/src/ts/Vertex.ts +35 -21
  223. package/src/ts/VertexListeners.ts +248 -266
  224. package/src/ts/draw.ts +201 -6
  225. package/src/ts/drawgl.ts +47 -3
  226. package/src/ts/drawutilssvg.ts +187 -16
  227. package/src/ts/index.ts +0 -1
  228. package/src/ts/interfaces/DrawLib.ts +72 -27
  229. package/src/ts/interfaces/core.ts +3 -13
  230. package/src/ts/module.ts +2 -4
  231. package/src/ts/utils/datastructures/Color.ts +17 -6
  232. package/src/ts/utils/datastructures/Girih.ts +204 -209
  233. package/src/ts/utils/datastructures/GirihPenroseRhombus.ts +170 -152
  234. package/src/ts/utils/datastructures/GirihTile.ts +394 -419
  235. package/src/ts/utils/helpers/BezierPathInteractionHelper.ts +56 -34
  236. package/src/ts/utils/io/FileDrop.ts +178 -0
  237. package/src/ts/SVGBuilder.ts +0 -109
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
  /**
@@ -361,7 +354,10 @@ class VertexListeners {
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
356
  * @modified 2021-12-17 Added the functions `lerp` and `lerpAbs` for linear interpolations.
364
- * @version 2.6.0
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
365
361
  *
366
362
  * @file Vertex
367
363
  * @public
@@ -848,28 +844,14 @@ class Vertex {
848
844
  return "(" + this.x + "," + this.y + ")";
849
845
  }
850
846
  /**
851
- * Convert this vertex to SVG code.
852
- *
853
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
854
- * @method toSVGString
855
- * @param {object=} options - An optional set of options, like 'className'.
856
- * @return {string} A string representing the SVG code for this vertex.
857
- * @instance
858
- * @memberof Vertex
859
- **/
860
- toSVGString(options) {
861
- options = options || {};
862
- var buffer = [];
863
- buffer.push("<circle");
864
- if (options.className)
865
- buffer.push(' class="' + options.className + '"');
866
- buffer.push(' cx="' + this.x + '"');
867
- buffer.push(' cy="' + this.y + '"');
868
- buffer.push(' r="2"');
869
- buffer.push(" />");
870
- 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;
871
854
  }
872
- // END Vertex
873
855
  /**
874
856
  * Create a new random vertex inside the given viewport.
875
857
  *
@@ -924,6 +906,19 @@ Vertex.utils = {
924
906
  vertices.push(new Vertex(zB.x * scaleX, zB.y * scaleY));
925
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)));
926
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
+ }));
927
922
  }
928
923
  };
929
924
 
@@ -950,7 +945,10 @@ Vertex.utils = {
950
945
  * @modified 2021-01-29 Changed the param type for `containsVert` from Vertex to XYCoords.
951
946
  * @modified 2021-12-14 Added the `perimeter()` function.
952
947
  * @modified 2021-12-16 Added the `getEvenDistributionPolygon()` function.
953
- * @version 1.8.0
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
954
952
  *
955
953
  * @file Polygon
956
954
  * @public
@@ -1028,9 +1026,9 @@ class Polygon {
1028
1026
  * @memberof Polygon
1029
1027
  * @return {Polygon} this for chaining
1030
1028
  **/
1031
- move(vert) {
1029
+ move(amount) {
1032
1030
  for (var i in this.vertices) {
1033
- this.vertices[i].add(vert);
1031
+ this.vertices[i].add(amount);
1034
1032
  }
1035
1033
  return this;
1036
1034
  }
@@ -1209,6 +1207,14 @@ class Polygon {
1209
1207
  getBounds() {
1210
1208
  return Bounds.computeFromVertices(this.vertices);
1211
1209
  }
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
+ }
1212
1218
  /**
1213
1219
  * Convert this polygon to a sequence of quadratic Bézier curves.<br>
1214
1220
  * <br>
@@ -1346,39 +1352,15 @@ class Polygon {
1346
1352
  return BezierPath.fromArray(pathdata);
1347
1353
  }
1348
1354
  /**
1349
- * Create an SVG representation of this polygon.
1350
- *
1351
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
1352
- * @method toSVGString
1353
- * @param {object=} options - An optional set of options, like 'className'.
1354
- * @return {string} The SVG string.
1355
- * @instance
1356
- * @memberof Polygon
1357
- **/
1358
- toSVGString(options) {
1359
- options = options || {};
1360
- var buffer = [];
1361
- buffer.push("<path");
1362
- if (options.className)
1363
- buffer.push(' class="' + options.className + '"');
1364
- buffer.push(' d="');
1365
- if (this.vertices.length > 0) {
1366
- buffer.push("M ");
1367
- buffer.push(this.vertices[0].x.toString());
1368
- buffer.push(" ");
1369
- buffer.push(this.vertices[0].y.toString());
1370
- for (var i = 1; i < this.vertices.length; i++) {
1371
- buffer.push(" L ");
1372
- buffer.push(this.vertices[i].x.toString());
1373
- buffer.push(" ");
1374
- buffer.push(this.vertices[i].y.toString());
1375
- }
1376
- if (!this.isOpen) {
1377
- buffer.push(" Z");
1378
- }
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();
1379
1362
  }
1380
- buffer.push('" />');
1381
- return buffer.join("");
1363
+ this.isDestroyed = true;
1382
1364
  }
1383
1365
  }
1384
1366
  Polygon.utils = {
@@ -1429,7 +1411,8 @@ Polygon.utils = {
1429
1411
  * @modified 2020-11-19 Set min, max, width and height to private.
1430
1412
  * @modified 2021-02-02 Added the `toPolygon` method.
1431
1413
  * @modified 2021-06-21 (mid-summer) Added `getCenter` method.
1432
- * @version 1.3.0
1414
+ * @modified 2022-02-01 Added the `toString` function.
1415
+ * @version 1.4.0
1433
1416
  **/
1434
1417
  /**
1435
1418
  * @classdesc A bounds class with min and max values. Implementing IBounds.
@@ -1464,9 +1447,45 @@ class Bounds {
1464
1447
  toPolygon() {
1465
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);
1466
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
+ */
1467
1458
  getCenter() {
1468
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);
1469
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
+ }
1475
+ /**
1476
+ * Clone this bounds object (create a deep clone).
1477
+ *
1478
+ * Note: the returned format might change in the future, so please do not
1479
+ * rely on the returned string format.
1480
+ *
1481
+ * @method clone
1482
+ * @instance
1483
+ * @memberof Bounds
1484
+ * @returns {string} Creates a deep clone of this bounds object. The returned object's `min` and `max` instances are `Vertex` instances.
1485
+ */
1486
+ // clone() {
1487
+ // return new Bounds(new Vertex(this.min.x, this.min.y), new Vertex(this.max.x, this.max.y));
1488
+ // }
1470
1489
  /**
1471
1490
  * Compute the minimal bounding box for a given set of vertices.
1472
1491
  *
@@ -1507,7 +1526,8 @@ class Bounds {
1507
1526
  * @modified 2020-12-04 Changed `getClosestT` param from `Vertex` to `XYCoords` (generalized).
1508
1527
  * @modified 2020-12-04 Added the `hasPoint(XYCoords)` function.
1509
1528
  * @modified 2021-01-20 Added UID.
1510
- * @version 1.1.0
1529
+ * @modified 2022-02-02 Added the `destroy` method.
1530
+ * @version 1.2.0
1511
1531
  */
1512
1532
  /**
1513
1533
  * @classdesc An abstract base classes for vertex tuple constructs, like Lines or Vectors.
@@ -1541,7 +1561,6 @@ class VertTuple {
1541
1561
  length() {
1542
1562
  return Math.sqrt(Math.pow(this.b.x - this.a.x, 2) + Math.pow(this.b.y - this.a.y, 2));
1543
1563
  }
1544
- ;
1545
1564
  /**
1546
1565
  * Set the length of this vector to the given amount. This only works if this
1547
1566
  * vector is not a null vector.
@@ -1554,7 +1573,6 @@ class VertTuple {
1554
1573
  setLength(length) {
1555
1574
  return this.scale(length / this.length());
1556
1575
  }
1557
- ;
1558
1576
  /**
1559
1577
  * Substract the given vertex from this line's end points.
1560
1578
  *
@@ -1569,7 +1587,6 @@ class VertTuple {
1569
1587
  this.b.sub(amount);
1570
1588
  return this;
1571
1589
  }
1572
- ;
1573
1590
  /**
1574
1591
  * Add the given vertex to this line's end points.
1575
1592
  *
@@ -1584,7 +1601,6 @@ class VertTuple {
1584
1601
  this.b.add(amount);
1585
1602
  return this;
1586
1603
  }
1587
- ;
1588
1604
  /**
1589
1605
  * Normalize this line (set to length 1).
1590
1606
  *
@@ -1597,7 +1613,6 @@ class VertTuple {
1597
1613
  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());
1598
1614
  return this;
1599
1615
  }
1600
- ;
1601
1616
  /**
1602
1617
  * Scale this line by the given factor.
1603
1618
  *
@@ -1611,7 +1626,6 @@ class VertTuple {
1611
1626
  this.b.set(this.a.x + (this.b.x - this.a.x) * factor, this.a.y + (this.b.y - this.a.y) * factor);
1612
1627
  return this;
1613
1628
  }
1614
- ;
1615
1629
  /**
1616
1630
  * Move this line to a new location.
1617
1631
  *
@@ -1627,7 +1641,6 @@ class VertTuple {
1627
1641
  this.b.add(diff);
1628
1642
  return this;
1629
1643
  }
1630
- ;
1631
1644
  /**
1632
1645
  * Get the angle between this and the passed line (in radians).
1633
1646
  *
@@ -1638,7 +1651,7 @@ class VertTuple {
1638
1651
  * @memberof VertTuple
1639
1652
  **/
1640
1653
  angle(line) {
1641
- if (line == null || typeof line == 'undefined') {
1654
+ if (line == null || typeof line == "undefined") {
1642
1655
  line = this.factory(new Vertex(0, 0), new Vertex(100, 0));
1643
1656
  }
1644
1657
  // Compute the angle from x axis and the return the difference :)
@@ -1648,7 +1661,6 @@ class VertTuple {
1648
1661
  // The result might be negative, but isn't it usually nicer to determine angles in positive values only?
1649
1662
  return Math.atan2(v1.x, v1.y) - Math.atan2(v0.x, v0.y);
1650
1663
  }
1651
- ;
1652
1664
  /**
1653
1665
  * Get line point at position t in [0 ... 1]:<br>
1654
1666
  * <pre>[P(0)]=[A]--------------------[P(t)]------[B]=[P(1)]</pre><br>
@@ -1664,7 +1676,6 @@ class VertTuple {
1664
1676
  vertAt(t) {
1665
1677
  return new Vertex(this.a.x + (this.b.x - this.a.x) * t, this.a.y + (this.b.y - this.a.y) * t);
1666
1678
  }
1667
- ;
1668
1679
  /**
1669
1680
  * Get the denominator of this and the given line.
1670
1681
  *
@@ -1678,9 +1689,8 @@ class VertTuple {
1678
1689
  **/
1679
1690
  denominator(line) {
1680
1691
  // http://jsfiddle.net/justin_c_rounds/Gd2S2/
1681
- 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));
1692
+ 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);
1682
1693
  }
1683
- ;
1684
1694
  /**
1685
1695
  * Checks if this and the given line are co-linear.
1686
1696
  *
@@ -1695,7 +1705,6 @@ class VertTuple {
1695
1705
  colinear(line) {
1696
1706
  return Math.abs(this.denominator(line)) < Vertex.EPSILON;
1697
1707
  }
1698
- ;
1699
1708
  /**
1700
1709
  * Get the closest position T from this line to the specified point.
1701
1710
  *
@@ -1718,7 +1727,6 @@ class VertTuple {
1718
1727
  // t = Math.max(0, Math.min(1, t));
1719
1728
  return t;
1720
1729
  }
1721
- ;
1722
1730
  /**
1723
1731
  * Check if the given point is located on this line. Optionally also check if
1724
1732
  * that point is located between point `a` and `b`.
@@ -1754,7 +1762,6 @@ class VertTuple {
1754
1762
  var t = this.getClosestT(p);
1755
1763
  return this.vertAt(t);
1756
1764
  }
1757
- ;
1758
1765
  /**
1759
1766
  * The the minimal distance between this line and the specified point.
1760
1767
  *
@@ -1769,7 +1776,6 @@ class VertTuple {
1769
1776
  // https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
1770
1777
  return Math.sqrt(VertTuple.vtutils.dist2(p, this.vertAt(this.getClosestT(p))));
1771
1778
  }
1772
- ;
1773
1779
  /**
1774
1780
  * Create a deep clone of this instance.
1775
1781
  *
@@ -1781,7 +1787,6 @@ class VertTuple {
1781
1787
  clone() {
1782
1788
  return this.factory(this.a.clone(), this.b.clone());
1783
1789
  }
1784
- ;
1785
1790
  /**
1786
1791
  * Create a string representation of this line.
1787
1792
  *
@@ -1793,7 +1798,16 @@ class VertTuple {
1793
1798
  toString() {
1794
1799
  return "{ a : " + this.a.toString() + ", b : " + this.b.toString() + " }";
1795
1800
  }
1796
- ;
1801
+ /**
1802
+ * This function should invalidate any installed listeners and invalidate this object.
1803
+ * After calling this function the object might not hold valid data any more and
1804
+ * should not be used.
1805
+ */
1806
+ destroy() {
1807
+ this.a.destroy();
1808
+ this.b.destroy();
1809
+ this.isDestroyed = true;
1810
+ }
1797
1811
  }
1798
1812
  /**
1799
1813
  * @private
@@ -1815,7 +1829,9 @@ VertTuple.vtutils = {
1815
1829
  * @modified 2019-12-04 Added the Vector.inv() function.
1816
1830
  * @modified 2020-03-23 Ported to Typescript from JS.
1817
1831
  * @modified 2021-01-20 Added UID.
1818
- * @version 1.3.0
1832
+ * @modified 2022-02-02 Added the `destroy` method.
1833
+ * @modified 2022-02-02 Cleared the `Vector.toSVGString` function (deprecated). Use `drawutilssvg` instead.
1834
+ * @version 1.4.0
1819
1835
  *
1820
1836
  * @file Vector
1821
1837
  * @public
@@ -1846,7 +1862,6 @@ class Vector extends VertTuple {
1846
1862
  **/
1847
1863
  this.className = "Vector";
1848
1864
  }
1849
- ;
1850
1865
  /**
1851
1866
  * Get the perpendicular of this vector which is located at a.
1852
1867
  *
@@ -1861,7 +1876,6 @@ class Vector extends VertTuple {
1861
1876
  v.b.add(this.a);
1862
1877
  return v;
1863
1878
  }
1864
- ;
1865
1879
  /**
1866
1880
  * The inverse of a vector is a vector witht the same magnitude but oppose direction.
1867
1881
  *
@@ -1875,7 +1889,6 @@ class Vector extends VertTuple {
1875
1889
  this.b = tmp;
1876
1890
  return this;
1877
1891
  }
1878
- ;
1879
1892
  /**
1880
1893
  * This function computes the inverse of the vector, which means 'a' stays untouched.
1881
1894
  *
@@ -1886,7 +1899,6 @@ class Vector extends VertTuple {
1886
1899
  this.b.y = this.a.y - (this.b.y - this.a.y);
1887
1900
  return this;
1888
1901
  }
1889
- ;
1890
1902
  /**
1891
1903
  * Get the intersection if this vector and the specified vector.
1892
1904
  *
@@ -1902,53 +1914,15 @@ class Vector extends VertTuple {
1902
1914
  return null;
1903
1915
  var a = this.a.y - line.a.y;
1904
1916
  var b = this.a.x - line.a.x;
1905
- var numerator1 = ((line.b.x - line.a.x) * a) - ((line.b.y - line.a.y) * b);
1906
- var numerator2 = ((this.b.x - this.a.x) * a) - ((this.b.y - this.a.y) * b);
1917
+ var numerator1 = (line.b.x - line.a.x) * a - (line.b.y - line.a.y) * b;
1918
+ var numerator2 = (this.b.x - this.a.x) * a - (this.b.y - this.a.y) * b;
1907
1919
  a = numerator1 / denominator; // NaN if parallel lines
1908
1920
  b = numerator2 / denominator;
1909
1921
  // TODO:
1910
1922
  // FOR A VECTOR THE LINE-INTERSECTION MUST BE ON BOTH VECTORS
1911
1923
  // if we cast these lines infinitely in both directions, they intersect here:
1912
- return new Vertex(this.a.x + (a * (this.b.x - this.a.x)), this.a.y + (a * (this.b.y - this.a.y)));
1913
- }
1914
- ;
1915
- /**
1916
- * Create an SVG representation of this line.
1917
- *
1918
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
1919
- * @method toSVGString
1920
- * @override
1921
- * @param {object=} options - A set of options, like 'className'.
1922
- * @return {string} The SVG string representation.
1923
- * @instance
1924
- * @memberof Vector
1925
- **/
1926
- toSVGString(options) {
1927
- options = options || {};
1928
- var buffer = [];
1929
- var vertices = Vector.utils.buildArrowHead(this.a, this.b, 8, 1.0, 1.0);
1930
- buffer.push('<g');
1931
- if (options.className)
1932
- buffer.push(' class="' + options.className + '"');
1933
- buffer.push('>');
1934
- buffer.push(' <line');
1935
- buffer.push(' x1="' + this.a.x + '"');
1936
- buffer.push(' y1="' + this.a.y + '"');
1937
- buffer.push(' x2="' + vertices[0].x + '"');
1938
- buffer.push(' y2="' + vertices[0].y + '"');
1939
- buffer.push(' />');
1940
- // Add arrow head
1941
- buffer.push(' <polygon points="');
1942
- for (var i = 0; i < vertices.length; i++) {
1943
- if (i > 0)
1944
- buffer.push(' ');
1945
- buffer.push('' + vertices[i].x + ',' + vertices[i].y);
1946
- }
1947
- buffer.push('"/>');
1948
- buffer.push('</g>');
1949
- return buffer.join('');
1924
+ return new Vertex(this.a.x + a * (this.b.x - this.a.x), this.a.y + a * (this.b.y - this.a.y));
1950
1925
  }
1951
- ;
1952
1926
  }
1953
1927
  Vector.utils = {
1954
1928
  /**
@@ -1979,10 +1953,10 @@ Vector.utils = {
1979
1953
  buildArrowHead: (zA, zB, headlen, scaleX, scaleY) => {
1980
1954
  var angle = Math.atan2((zB.y - zA.y) * scaleY, (zB.x - zA.x) * scaleX);
1981
1955
  var vertices = [];
1982
- vertices.push(new Vertex(zB.x * scaleX - (headlen) * Math.cos(angle), zB.y * scaleY - (headlen) * Math.sin(angle)));
1983
- 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)));
1956
+ vertices.push(new Vertex(zB.x * scaleX - headlen * Math.cos(angle), zB.y * scaleY - headlen * Math.sin(angle)));
1957
+ 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)));
1984
1958
  vertices.push(new Vertex(zB.x * scaleX, zB.y * scaleY));
1985
- 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)));
1959
+ 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)));
1986
1960
  return vertices;
1987
1961
  }
1988
1962
  };
@@ -2007,7 +1981,9 @@ Vector.utils = {
2007
1981
  * @modified 2020-07-14 Changed the moveCurvePoint(...,Vertex) to moveCurvePoint(...,XYCoords), which is more generic.
2008
1982
  * @modified 2020-07-24 Added the getClosestT function and the helper function locateIntervalByDistance(...).
2009
1983
  * @modified 2021-01-20 Added UID.
2010
- * @version 2.5.0
1984
+ * @modified 2022-02-02 Added the `destroy` method.
1985
+ * @modified 2022-02-02 Cleared the `toSVGPathData` function (deprecated). Use `drawutilssvg` instead.
1986
+ * @version 2.6.0
2011
1987
  *
2012
1988
  * @file CubicBezierCurve
2013
1989
  * @public
@@ -2056,7 +2032,6 @@ class CubicBezierCurve {
2056
2032
  this.arcLength = null;
2057
2033
  this.updateArcLengths();
2058
2034
  }
2059
- ;
2060
2035
  /**
2061
2036
  * Move the given curve point (the start point, end point or one of the two
2062
2037
  * control points).
@@ -2093,7 +2068,6 @@ class CubicBezierCurve {
2093
2068
  if (updateArcLengths)
2094
2069
  this.updateArcLengths();
2095
2070
  }
2096
- ;
2097
2071
  /**
2098
2072
  * Translate the whole curve by the given {x,y} amount: moves all four points.
2099
2073
  *
@@ -2110,7 +2084,6 @@ class CubicBezierCurve {
2110
2084
  this.endPoint.add(amount);
2111
2085
  return this;
2112
2086
  }
2113
- ;
2114
2087
  /**
2115
2088
  * Reverse this curve, means swapping start- and end-point and swapping
2116
2089
  * start-control- and end-control-point.
@@ -2129,7 +2102,6 @@ class CubicBezierCurve {
2129
2102
  this.endControlPoint = tmp;
2130
2103
  return this;
2131
2104
  }
2132
- ;
2133
2105
  /**
2134
2106
  * Get the total curve length.<br>
2135
2107
  * <br>
@@ -2148,7 +2120,6 @@ class CubicBezierCurve {
2148
2120
  getLength() {
2149
2121
  return this.arcLength;
2150
2122
  }
2151
- ;
2152
2123
  /**
2153
2124
  * Uptate the internal arc segment buffer and their lengths.<br>
2154
2125
  * <br>
@@ -2186,7 +2157,6 @@ class CubicBezierCurve {
2186
2157
  }
2187
2158
  this.arcLength = newLength;
2188
2159
  }
2189
- ;
2190
2160
  /**
2191
2161
  * Get a 't' (relative position on curve) with the closest distance to point 'p'.
2192
2162
  *
@@ -2209,7 +2179,6 @@ class CubicBezierCurve {
2209
2179
  } while (iteration < 4 && this.getPointAt(result.tPrev).distance(this.getPointAt(result.tNext)) > desiredEpsilon);
2210
2180
  return result.t;
2211
2181
  }
2212
- ;
2213
2182
  /**
2214
2183
  * This helper function locates the 't' on a fixed step interval with the minimal distance
2215
2184
  * between the curve (at 't') and the given point.
@@ -2238,12 +2207,12 @@ class CubicBezierCurve {
2238
2207
  minDist = dist;
2239
2208
  }
2240
2209
  }
2241
- return { t: tStart + tDiff * (minIndex / stepCount),
2210
+ return {
2211
+ t: tStart + tDiff * (minIndex / stepCount),
2242
2212
  tPrev: tStart + tDiff * (Math.max(0, minIndex - 1) / stepCount),
2243
2213
  tNext: tStart + tDiff * (Math.min(stepCount, minIndex + 1) / stepCount)
2244
2214
  };
2245
2215
  }
2246
- ;
2247
2216
  /**
2248
2217
  * Get the bounds of this bezier curve.
2249
2218
  *
@@ -2265,7 +2234,6 @@ class CubicBezierCurve {
2265
2234
  }
2266
2235
  return new Bounds(min, max);
2267
2236
  }
2268
- ;
2269
2237
  /**
2270
2238
  * Get the start point of the curve.<br>
2271
2239
  * <br>
@@ -2279,7 +2247,6 @@ class CubicBezierCurve {
2279
2247
  getStartPoint() {
2280
2248
  return this.startPoint;
2281
2249
  }
2282
- ;
2283
2250
  /**
2284
2251
  * Get the end point of the curve.<br>
2285
2252
  * <br>
@@ -2293,7 +2260,6 @@ class CubicBezierCurve {
2293
2260
  getEndPoint() {
2294
2261
  return this.endPoint;
2295
2262
  }
2296
- ;
2297
2263
  /**
2298
2264
  * Get the start control point of the curve.<br>
2299
2265
  * <br>
@@ -2307,7 +2273,6 @@ class CubicBezierCurve {
2307
2273
  getStartControlPoint() {
2308
2274
  return this.startControlPoint;
2309
2275
  }
2310
- ;
2311
2276
  /**
2312
2277
  * Get the end control point of the curve.<br>
2313
2278
  * <br>
@@ -2321,7 +2286,6 @@ class CubicBezierCurve {
2321
2286
  getEndControlPoint() {
2322
2287
  return this.endControlPoint;
2323
2288
  }
2324
- ;
2325
2289
  /**
2326
2290
  * Get one of the four curve points specified by the passt point ID.
2327
2291
  *
@@ -2342,7 +2306,6 @@ class CubicBezierCurve {
2342
2306
  return this.endControlPoint;
2343
2307
  throw new Error(`Invalid point ID '${id}'.`);
2344
2308
  }
2345
- ;
2346
2309
  /**
2347
2310
  * Get the curve point at a given position t, where t is in [0,1].<br>
2348
2311
  * <br>
@@ -2357,13 +2320,16 @@ class CubicBezierCurve {
2357
2320
  **/
2358
2321
  getPointAt(t) {
2359
2322
  // Perform some powerful math magic
2360
- const x = this.startPoint.x * Math.pow(1.0 - t, 3) + this.startControlPoint.x * 3 * t * Math.pow(1.0 - t, 2)
2361
- + this.endControlPoint.x * 3 * Math.pow(t, 2) * (1.0 - t) + this.endPoint.x * Math.pow(t, 3);
2362
- const y = this.startPoint.y * Math.pow(1.0 - t, 3) + this.startControlPoint.y * 3 * t * Math.pow(1.0 - t, 2)
2363
- + this.endControlPoint.y * 3 * Math.pow(t, 2) * (1.0 - t) + this.endPoint.y * Math.pow(t, 3);
2323
+ const x = this.startPoint.x * Math.pow(1.0 - t, 3) +
2324
+ this.startControlPoint.x * 3 * t * Math.pow(1.0 - t, 2) +
2325
+ this.endControlPoint.x * 3 * Math.pow(t, 2) * (1.0 - t) +
2326
+ this.endPoint.x * Math.pow(t, 3);
2327
+ const y = this.startPoint.y * Math.pow(1.0 - t, 3) +
2328
+ this.startControlPoint.y * 3 * t * Math.pow(1.0 - t, 2) +
2329
+ this.endControlPoint.y * 3 * Math.pow(t, 2) * (1.0 - t) +
2330
+ this.endPoint.y * Math.pow(t, 3);
2364
2331
  return new Vertex(x, y);
2365
2332
  }
2366
- ;
2367
2333
  /**
2368
2334
  * Get the curve point at a given position u, where u is in [0,arcLength].<br>
2369
2335
  * <br>
@@ -2379,7 +2345,6 @@ class CubicBezierCurve {
2379
2345
  getPoint(u) {
2380
2346
  return this.getPointAt(u / this.arcLength);
2381
2347
  }
2382
- ;
2383
2348
  /**
2384
2349
  * Get the curve tangent vector at a given absolute curve position t in [0,1].<br>
2385
2350
  * <br>
@@ -2400,18 +2365,11 @@ class CubicBezierCurve {
2400
2365
  const t2 = t * t;
2401
2366
  // (1 - t)^2 = (1-t)*(1-t) = 1 - t - t + t^2 = 1 - 2*t + t^2
2402
2367
  const nt2 = 1 - 2 * t + t2;
2403
- const tX = -3 * a.x * nt2 +
2404
- b.x * (3 * nt2 - 6 * (t - t2)) +
2405
- c.x * (6 * (t - t2) - 3 * t2) +
2406
- 3 * d.x * t2;
2407
- const tY = -3 * a.y * nt2 +
2408
- b.y * (3 * nt2 - 6 * (t - t2)) +
2409
- c.y * (6 * (t - t2) - 3 * t2) +
2410
- 3 * d.y * t2;
2368
+ const tX = -3 * a.x * nt2 + b.x * (3 * nt2 - 6 * (t - t2)) + c.x * (6 * (t - t2) - 3 * t2) + 3 * d.x * t2;
2369
+ const tY = -3 * a.y * nt2 + b.y * (3 * nt2 - 6 * (t - t2)) + c.y * (6 * (t - t2) - 3 * t2) + 3 * d.y * t2;
2411
2370
  // Note: my implementation does NOT normalize tangent vectors!
2412
2371
  return new Vertex(tX, tY);
2413
2372
  }
2414
- ;
2415
2373
  /**
2416
2374
  * Get a sub curve at the given start end end offsets (values between 0.0 and 1.0).
2417
2375
  *
@@ -2437,7 +2395,6 @@ class CubicBezierCurve {
2437
2395
  // pb.draw.cubicBezier( startVec.a, endVec.a, startVec.b, endVec.b, '#8800ff', 2 );
2438
2396
  return new CubicBezierCurve(startVec.a, endVec.a, startVec.b, endVec.b);
2439
2397
  }
2440
- ;
2441
2398
  /**
2442
2399
  * Convert a relative curve position u to the absolute curve position t.
2443
2400
  *
@@ -2448,9 +2405,8 @@ class CubicBezierCurve {
2448
2405
  * @return {number}
2449
2406
  **/
2450
2407
  convertU2T(u) {
2451
- return Math.max(0.0, Math.min(1.0, (u / this.arcLength)));
2408
+ return Math.max(0.0, Math.min(1.0, u / this.arcLength));
2452
2409
  }
2453
- ;
2454
2410
  /**
2455
2411
  * Get the curve tangent vector at a given relative position u in [0,arcLength].<br>
2456
2412
  * <br>
@@ -2465,7 +2421,6 @@ class CubicBezierCurve {
2465
2421
  getTangent(u) {
2466
2422
  return this.getTangentAt(this.convertU2T(u));
2467
2423
  }
2468
- ;
2469
2424
  /**
2470
2425
  * Get the curve perpendicular at a given relative position u in [0,arcLength] as a vector.<br>
2471
2426
  * <br>
@@ -2480,7 +2435,6 @@ class CubicBezierCurve {
2480
2435
  getPerpendicular(u) {
2481
2436
  return this.getPerpendicularAt(this.convertU2T(u));
2482
2437
  }
2483
- ;
2484
2438
  /**
2485
2439
  * Get the curve perpendicular at a given absolute position t in [0,1] as a vector.<br>
2486
2440
  * <br>
@@ -2496,7 +2450,6 @@ class CubicBezierCurve {
2496
2450
  const tangentVector = this.getTangentAt(t);
2497
2451
  return new Vertex(tangentVector.y, -tangentVector.x);
2498
2452
  }
2499
- ;
2500
2453
  /**
2501
2454
  * Clone this Bézier curve (deep clone).
2502
2455
  *
@@ -2508,7 +2461,6 @@ class CubicBezierCurve {
2508
2461
  clone() {
2509
2462
  return new CubicBezierCurve(this.getStartPoint().clone(), this.getEndPoint().clone(), this.getStartControlPoint().clone(), this.getEndControlPoint().clone());
2510
2463
  }
2511
- ;
2512
2464
  /**
2513
2465
  * Check if this and the specified curve are equal.<br>
2514
2466
  * <br>
@@ -2527,17 +2479,25 @@ class CubicBezierCurve {
2527
2479
  // Let's see if this restricted version works out.
2528
2480
  if (!curve)
2529
2481
  return false;
2530
- if (!curve.startPoint ||
2531
- !curve.endPoint ||
2532
- !curve.startControlPoint ||
2533
- !curve.endControlPoint)
2482
+ if (!curve.startPoint || !curve.endPoint || !curve.startControlPoint || !curve.endControlPoint)
2534
2483
  return false;
2535
- return this.startPoint.equals(curve.startPoint)
2536
- && this.endPoint.equals(curve.endPoint)
2537
- && this.startControlPoint.equals(curve.startControlPoint)
2538
- && this.endControlPoint.equals(curve.endControlPoint);
2484
+ return (this.startPoint.equals(curve.startPoint) &&
2485
+ this.endPoint.equals(curve.endPoint) &&
2486
+ this.startControlPoint.equals(curve.startControlPoint) &&
2487
+ this.endControlPoint.equals(curve.endControlPoint));
2488
+ }
2489
+ /**
2490
+ * This function should invalidate any installed listeners and invalidate this object.
2491
+ * After calling this function the object might not hold valid data any more and
2492
+ * should not be used.
2493
+ */
2494
+ destroy() {
2495
+ this.startPoint.destroy();
2496
+ this.endPoint.destroy();
2497
+ this.startControlPoint.destroy();
2498
+ this.endControlPoint.destroy();
2499
+ this.isDestroyed = true;
2539
2500
  }
2540
- ;
2541
2501
  /**
2542
2502
  * Quick check for class instance.
2543
2503
  * Is there a better way?
@@ -2563,41 +2523,6 @@ class CubicBezierCurve {
2563
2523
  */
2564
2524
  return obj instanceof CubicBezierCurve;
2565
2525
  }
2566
- ;
2567
- /**
2568
- * Create an SVG path data representation of this bézier curve.
2569
- *
2570
- * Path data string format is:<br>
2571
- * <pre>'M x0 y1 C dx0 dy1 dx1 dy1 x1 x2'</pre><br>
2572
- * or in other words<br>
2573
- * <pre>'M startoint.x startPoint.y C startControlPoint.x startControlPoint.y endControlPoint.x endControlPoint.y endPoint.x endPoint.y'</pre>
2574
- *
2575
- * @method toSVGPathData
2576
- * @instance
2577
- * @memberof CubicBezierCurve
2578
- * @return {string} The SVG path data string.
2579
- **/
2580
- toSVGPathData() {
2581
- var buffer = [];
2582
- buffer.push('M ');
2583
- buffer.push(this.startPoint.x.toString());
2584
- buffer.push(' ');
2585
- buffer.push(this.startPoint.y.toString());
2586
- buffer.push(' C ');
2587
- buffer.push(this.startControlPoint.x.toString());
2588
- buffer.push(' ');
2589
- buffer.push(this.startControlPoint.y.toString());
2590
- buffer.push(' ');
2591
- buffer.push(this.endControlPoint.x.toString());
2592
- buffer.push(' ');
2593
- buffer.push(this.endControlPoint.y.toString());
2594
- buffer.push(' ');
2595
- buffer.push(this.endPoint.x.toString());
2596
- buffer.push(' ');
2597
- buffer.push(this.endPoint.y.toString());
2598
- return buffer.join('');
2599
- }
2600
- ;
2601
2526
  /**
2602
2527
  * Convert this curve to a JSON string.
2603
2528
  *
@@ -2610,18 +2535,33 @@ class CubicBezierCurve {
2610
2535
  toJSON(prettyFormat) {
2611
2536
  var jsonString = "{ " + // begin object
2612
2537
  (prettyFormat ? "\n\t" : "") +
2613
- "\"startPoint\" : [" + this.getStartPoint().x + "," + this.getStartPoint().y + "], " +
2538
+ '"startPoint" : [' +
2539
+ this.getStartPoint().x +
2540
+ "," +
2541
+ this.getStartPoint().y +
2542
+ "], " +
2614
2543
  (prettyFormat ? "\n\t" : "") +
2615
- "\"endPoint\" : [" + this.getEndPoint().x + "," + this.getEndPoint().y + "], " +
2544
+ '"endPoint" : [' +
2545
+ this.getEndPoint().x +
2546
+ "," +
2547
+ this.getEndPoint().y +
2548
+ "], " +
2616
2549
  (prettyFormat ? "\n\t" : "") +
2617
- "\"startControlPoint\": [" + this.getStartControlPoint().x + "," + this.getStartControlPoint().y + "], " +
2550
+ '"startControlPoint": [' +
2551
+ this.getStartControlPoint().x +
2552
+ "," +
2553
+ this.getStartControlPoint().y +
2554
+ "], " +
2618
2555
  (prettyFormat ? "\n\t" : "") +
2619
- "\"endControlPoint\" : [" + this.getEndControlPoint().x + "," + this.getEndControlPoint().y + "]" +
2556
+ '"endControlPoint" : [' +
2557
+ this.getEndControlPoint().x +
2558
+ "," +
2559
+ this.getEndControlPoint().y +
2560
+ "]" +
2620
2561
  (prettyFormat ? "\n\t" : "") +
2621
2562
  " }"; // end object
2622
2563
  return jsonString;
2623
2564
  }
2624
- ;
2625
2565
  /**
2626
2566
  * Parse a Bézier curve from the given JSON string.
2627
2567
  *
@@ -2636,7 +2576,6 @@ class CubicBezierCurve {
2636
2576
  var obj = JSON.parse(jsonString);
2637
2577
  return CubicBezierCurve.fromObject(obj);
2638
2578
  }
2639
- ;
2640
2579
  /**
2641
2580
  * Try to convert the passed object to a CubicBezierCurve.
2642
2581
  *
@@ -2651,16 +2590,15 @@ class CubicBezierCurve {
2651
2590
  if (typeof obj !== "object")
2652
2591
  throw "Can only build from object.";
2653
2592
  if (!obj.startPoint)
2654
- throw "Object member \"startPoint\" missing.";
2593
+ throw 'Object member "startPoint" missing.';
2655
2594
  if (!obj.endPoint)
2656
- throw "Object member \"endPoint\" missing.";
2595
+ throw 'Object member "endPoint" missing.';
2657
2596
  if (!obj.startControlPoint)
2658
- throw "Object member \"startControlPoint\" missing.";
2597
+ throw 'Object member "startControlPoint" missing.';
2659
2598
  if (!obj.endControlPoint)
2660
- throw "Object member \"endControlPoint\" missing.";
2599
+ throw 'Object member "endControlPoint" missing.';
2661
2600
  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]));
2662
2601
  }
2663
- ;
2664
2602
  /**
2665
2603
  * Convert a 4-element array of vertices to a cubic bézier curve.
2666
2604
  *
@@ -2677,7 +2615,6 @@ class CubicBezierCurve {
2677
2615
  throw "Can only build from array with four elements.";
2678
2616
  return new CubicBezierCurve(arr[0], arr[1], arr[2], arr[3]);
2679
2617
  }
2680
- ;
2681
2618
  }
2682
2619
  /** @constant {number} */
2683
2620
  CubicBezierCurve.START_POINT = 0;
@@ -2710,7 +2647,10 @@ CubicBezierCurve.END_POINT = 3;
2710
2647
  * @modified 2020-07-24 Added the getClosestT(Vertex) function.
2711
2648
  * @modified 2020-12-29 Constructor is now private (no explicit use intended).
2712
2649
  * @modified 2021-05-25 Added BezierPath.fromReducedList( Array<number> ).
2713
- * @version 2.3.1
2650
+ * @modified 2022-01-31 Added `BezierPath.getEvenDistributionVertices(number)`.
2651
+ * @modified 2022-02-02 Added the `destroy` method.
2652
+ * @modified 2022-02-02 Cleared the `toSVGString` function (deprecated). Use `drawutilssvg` instead.
2653
+ * @version 2.5.0
2714
2654
  *
2715
2655
  * @file BezierPath
2716
2656
  * @public
@@ -3599,6 +3539,59 @@ class BezierPath {
3599
3539
  }
3600
3540
  return new Bounds(min, max);
3601
3541
  }
3542
+ /**
3543
+ * Get n 'equally' distributed vertices along this Bézier path.
3544
+ *
3545
+ * As the changing curvature of the B slines makes prediction of distances difficult, the
3546
+ * returned vertices' distances are only relatively equal:
3547
+ * - the distance grows where curvature is large.
3548
+ * - the distance shrinks where curvature is small.
3549
+ *
3550
+ * Only the distance mean of all consecutive is 1/n-th of the total arc length.
3551
+ *
3552
+ * Usually this approximation is good enough for most use cases.
3553
+ *
3554
+ * @param {number} pointCount - (must be at least 2) The number of desired points (start and end point included).
3555
+ * @return {Array<Vertex>}
3556
+ */
3557
+ getEvenDistributionVertices(pointCount) {
3558
+ if (pointCount < 2) {
3559
+ throw new Error("pointCount must be larger than one; is " + pointCount + ".");
3560
+ }
3561
+ const result = [];
3562
+ if (this.bezierCurves.length === 0) {
3563
+ return result;
3564
+ }
3565
+ // Fetch and add the start point from the source polygon
3566
+ var polygonPoint = new Vertex(this.bezierCurves[0].startPoint);
3567
+ result.push(polygonPoint);
3568
+ // if (this.bezierCurves.length === 1) {
3569
+ // return result;
3570
+ // }
3571
+ const perimeter = this.totalArcLength;
3572
+ const stepSize = perimeter / (pointCount - 1);
3573
+ const n = this.bezierCurves.length;
3574
+ let curveIndex = 0;
3575
+ let segmentLength = this.bezierCurves[0].arcLength;
3576
+ let curSegmentU = stepSize;
3577
+ let i = 1;
3578
+ while (i < pointCount && curveIndex < n) {
3579
+ // Check if next eq point is inside this segment
3580
+ if (curSegmentU < segmentLength) {
3581
+ var newPoint = this.bezierCurves[curveIndex].getPoint(curSegmentU);
3582
+ result.push(newPoint);
3583
+ curSegmentU += stepSize;
3584
+ i++;
3585
+ }
3586
+ else {
3587
+ curveIndex++;
3588
+ curSegmentU = curSegmentU - segmentLength;
3589
+ segmentLength = curveIndex < n ? this.bezierCurves[curveIndex].arcLength : 0;
3590
+ }
3591
+ }
3592
+ result.push(new Vertex(this.bezierCurves[n - 1].endPoint));
3593
+ return result;
3594
+ }
3602
3595
  /**
3603
3596
  * Clone this BezierPath (deep clone).
3604
3597
  *
@@ -3645,30 +3638,15 @@ class BezierPath {
3645
3638
  return true;
3646
3639
  }
3647
3640
  /**
3648
- * Create a <pre>&lt;path&gt;</pre> SVG representation of this bézier curve.
3649
- *
3650
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
3651
- * @method toSVGString
3652
- * @param {object=} [options={}] - Like options.className
3653
- * @param {string=} [options.className] - The classname to use for the SVG item.
3654
- * @instance
3655
- * @memberof BezierPath
3656
- * @return {string} The SVG string.
3657
- **/
3658
- toSVGString(options) {
3659
- options = options || {};
3660
- var buffer = [];
3661
- buffer.push("<path");
3662
- if (options.className)
3663
- buffer.push(' class="' + options.className + '"');
3664
- buffer.push(' d="');
3665
- for (var c = 0; c < this.bezierCurves.length; c++) {
3666
- if (c > 0)
3667
- buffer.push(" ");
3668
- buffer.push(this.bezierCurves[c].toSVGPathData());
3641
+ * This function should invalidate any installed listeners and invalidate this object.
3642
+ * After calling this function the object might not hold valid data any more and
3643
+ * should not be used.
3644
+ */
3645
+ destroy() {
3646
+ for (var i = 0; i < this.bezierCurves.length; i++) {
3647
+ this.bezierCurves[i].destroy();
3669
3648
  }
3670
- buffer.push('" />');
3671
- return buffer.join("");
3649
+ this.isDestroyed = true;
3672
3650
  }
3673
3651
  /**
3674
3652
  * Create a JSON string representation of this bézier curve.
@@ -3895,7 +3873,8 @@ BezierPath.END_POINT = 3;
3895
3873
  * @modified 2020-03-16 The Line.angle(Line) parameter is now optional. The baseline (x-axis) will be used if not defined.
3896
3874
  * @modified 2020-03-23 Ported to Typescript from JS.
3897
3875
  * @modified 2020-12-04 The `intersection` function returns undefined if both lines are parallel.
3898
- * @version 2.1.3
3876
+ * @modified 2022-02-02 Added the `destroy` method.
3877
+ * @version 2.2.0
3899
3878
  *
3900
3879
  * @file Line
3901
3880
  * @public
@@ -3940,45 +3919,19 @@ class Line extends VertTuple {
3940
3919
  return null;
3941
3920
  let a = this.a.y - line.a.y;
3942
3921
  let b = this.a.x - line.a.x;
3943
- const numerator1 = ((line.b.x - line.a.x) * a) - ((line.b.y - line.a.y) * b);
3944
- const numerator2 = ((this.b.x - this.a.x) * a) - ((this.b.y - this.a.y) * b);
3922
+ const numerator1 = (line.b.x - line.a.x) * a - (line.b.y - line.a.y) * b;
3923
+ const numerator2 = (this.b.x - this.a.x) * a - (this.b.y - this.a.y) * b;
3945
3924
  a = numerator1 / denominator; // NaN if parallel lines
3946
3925
  b = numerator2 / denominator;
3947
3926
  // Catch NaN?
3948
- const x = this.a.x + (a * (this.b.x - this.a.x));
3949
- const y = this.a.y + (a * (this.b.y - this.a.y));
3927
+ const x = this.a.x + a * (this.b.x - this.a.x);
3928
+ const y = this.a.y + a * (this.b.y - this.a.y);
3950
3929
  if (isNaN(a) || isNaN(x) || isNaN(y)) {
3951
3930
  return undefined;
3952
3931
  }
3953
3932
  // if we cast these lines infinitely in both directions, they intersect here:
3954
3933
  return new Vertex(x, y);
3955
3934
  }
3956
- ;
3957
- /**
3958
- * Create an SVG representation of this line.
3959
- *
3960
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
3961
- * @method toSVGString
3962
- * @param {options} p - A set of options, like the 'classname' to use
3963
- * for the line object.
3964
- * @return {string} The SVG string representing this line.
3965
- * @instance
3966
- * @memberof Line
3967
- **/
3968
- toSVGString(options) {
3969
- options = options || {};
3970
- var buffer = [];
3971
- buffer.push('<line');
3972
- if (options.className)
3973
- buffer.push(' class="' + options.className + '"');
3974
- buffer.push(' x1="' + this.a.x + '"');
3975
- buffer.push(' y1="' + this.a.y + '"');
3976
- buffer.push(' x2="' + this.b.x + '"');
3977
- buffer.push(' y2="' + this.b.y + '"');
3978
- buffer.push(' />');
3979
- return buffer.join('');
3980
- }
3981
- ;
3982
3935
  }
3983
3936
 
3984
3937
  /**
@@ -3990,7 +3943,9 @@ class Line extends VertTuple {
3990
3943
  * @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.
3991
3944
  * @modified 2020-10-16 Added the containsCircle(...) function.
3992
3945
  * @modified 2021-01-20 Added UID.
3993
- * @version 1.2.0
3946
+ * @modified 2022-02-02 Added the `destroy` method.
3947
+ * @modified 2022-02-02 Cleared the `toSVGString` function (deprecated). Use `drawutilssvg` instead.
3948
+ * @version 1.3.0
3994
3949
  **/
3995
3950
  /**
3996
3951
  * @classdesc A simple circle: center point and radius.
@@ -4021,7 +3976,6 @@ class Circle {
4021
3976
  this.center = center;
4022
3977
  this.radius = radius;
4023
3978
  }
4024
- ;
4025
3979
  /**
4026
3980
  * Check if the given circle is fully contained inside this circle.
4027
3981
  *
@@ -4034,7 +3988,6 @@ class Circle {
4034
3988
  containsCircle(circle) {
4035
3989
  return this.center.distance(circle.center) + circle.radius < this.radius;
4036
3990
  }
4037
- ;
4038
3991
  /**
4039
3992
  * Calculate the distance from this circle to the given line.
4040
3993
  *
@@ -4053,7 +4006,6 @@ class Circle {
4053
4006
  const closestPointOnLine = line.getClosestPoint(this.center);
4054
4007
  return closestPointOnLine.distance(this.center) - this.radius;
4055
4008
  }
4056
- ;
4057
4009
  /**
4058
4010
  * Get the vertex on the this circle for the given angle.
4059
4011
  *
@@ -4067,7 +4019,6 @@ class Circle {
4067
4019
  // Find the point on the circle respective the angle. Then move relative to center.
4068
4020
  return Circle.circleUtils.vertAt(angle, this.radius).add(this.center);
4069
4021
  }
4070
- ;
4071
4022
  /**
4072
4023
  * Get a tangent line of this circle for a given angle.
4073
4024
  *
@@ -4084,7 +4035,6 @@ class Circle {
4084
4035
  // Construct the perpendicular of the line in point a. Then move relative to center.
4085
4036
  return new Vector(pointA, new Vertex(0, 0)).add(this.center).perp();
4086
4037
  }
4087
- ;
4088
4038
  /**
4089
4039
  * Calculate the intersection points (if exists) with the given circle.
4090
4040
  *
@@ -4124,48 +4074,33 @@ class Circle {
4124
4074
  // x4 = P2.x - h*(P1.y - P0.y)/d;
4125
4075
  // y4 = P2.y + h*(P1.x - P0.x)/d;
4126
4076
  // return pair<Point, Point>(Point(x3, y3), Point(x4, y4));
4127
- // }
4077
+ // }
4128
4078
  var p0 = this.center;
4129
4079
  var p1 = circle.center;
4130
4080
  var d = p0.distance(p1);
4131
4081
  var a = (this.radius * this.radius - circle.radius * circle.radius + d * d) / (2 * d);
4132
4082
  var h = Math.sqrt(this.radius * this.radius - a * a);
4133
4083
  var p2 = p1.clone().scale(a / d, p0);
4134
- var x3 = p2.x + h * (p1.y - p0.y) / d;
4135
- var y3 = p2.y - h * (p1.x - p0.x) / d;
4136
- var x4 = p2.x - h * (p1.y - p0.y) / d;
4137
- var y4 = p2.y + h * (p1.x - p0.x) / d;
4084
+ var x3 = p2.x + (h * (p1.y - p0.y)) / d;
4085
+ var y3 = p2.y - (h * (p1.x - p0.x)) / d;
4086
+ var x4 = p2.x - (h * (p1.y - p0.y)) / d;
4087
+ var y4 = p2.y + (h * (p1.x - p0.x)) / d;
4138
4088
  return new Line(new Vertex(x3, y3), new Vertex(x4, y4));
4139
4089
  }
4140
- ;
4141
4090
  /**
4142
- * Create an SVG representation of this circle.
4143
- *
4144
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
4145
- * @method toSVGString
4146
- * @param {object=} options - An optional set of options, like 'className'.
4147
- * @return {string} A string representing the SVG code for this vertex.
4148
- * @instance
4149
- * @memberof Circle
4150
- */
4151
- toSVGString(options) {
4152
- options = options || {};
4153
- var buffer = [];
4154
- buffer.push('<circle');
4155
- if (options.className)
4156
- buffer.push(' class="' + options.className + '"');
4157
- buffer.push(' cx="' + this.center.x + '"');
4158
- buffer.push(' cy="' + this.center.y + '"');
4159
- buffer.push(' r="' + this.radius + '"');
4160
- buffer.push(' />');
4161
- return buffer.join('');
4091
+ * This function should invalidate any installed listeners and invalidate this object.
4092
+ * After calling this function the object might not hold valid data any more and
4093
+ * should not be used.
4094
+ */
4095
+ destroy() {
4096
+ this.center.destroy();
4097
+ this.isDestroyed = true;
4162
4098
  }
4163
- ;
4164
4099
  } // END class
4165
4100
  Circle.circleUtils = {
4166
4101
  vertAt: (angle, radius) => {
4167
4102
  /* return new Vertex( Math.sin(angle) * radius,
4168
- Math.cos(angle) * radius ); */
4103
+ Math.cos(angle) * radius ); */
4169
4104
  return new Vertex(Math.cos(angle) * radius, Math.sin(angle) * radius);
4170
4105
  }
4171
4106
  };
@@ -4206,27 +4141,15 @@ class CircleSector {
4206
4141
  this.startAngle = startAngle;
4207
4142
  this.endAngle = endAngle;
4208
4143
  }
4209
- ;
4210
4144
  /**
4211
- * Create an SVG representation of this circle.
4212
- *
4213
- * @method toSVGString
4214
- * @param {object=} options - An optional set of options, like 'className'.
4215
- * @return {string} A string representing the SVG code for this vertex.
4216
- * @instance
4217
- * @memberof Circle
4218
- */
4219
- toSVGString(options) {
4220
- options = options || {};
4221
- var buffer = [];
4222
- buffer.push('<path ');
4223
- if (options.className)
4224
- buffer.push(' class="' + options.className + '"');
4225
- const data = CircleSector.circleSectorUtils.describeSVGArc(this.circle.center.x, this.circle.center.y, this.circle.radius, this.startAngle, this.endAngle);
4226
- buffer.push(' d="' + data.join(" ") + '" />');
4227
- return buffer.join('');
4145
+ * This function should invalidate any installed listeners and invalidate this object.
4146
+ * After calling this function the object might not hold valid data any more and
4147
+ * should not be used.
4148
+ */
4149
+ destroy() {
4150
+ this.circle.destroy();
4151
+ this.isDestroyed = true;
4228
4152
  }
4229
- ;
4230
4153
  } // END class
4231
4154
  CircleSector.circleSectorUtils = {
4232
4155
  /**
@@ -4235,11 +4158,11 @@ CircleSector.circleSectorUtils = {
4235
4158
  * TODO: generalize for ellipses (two radii).
4236
4159
  *
4237
4160
  * @param {number} angle - The angle in radians.
4238
- */
4161
+ */
4239
4162
  polarToCartesian: (centerX, centerY, radius, angle) => {
4240
4163
  return {
4241
- x: centerX + (radius * Math.cos(angle)),
4242
- y: centerY + (radius * Math.sin(angle))
4164
+ x: centerX + radius * Math.cos(angle),
4165
+ y: centerY + radius * Math.sin(angle)
4243
4166
  };
4244
4167
  },
4245
4168
  /**
@@ -4252,7 +4175,7 @@ CircleSector.circleSectorUtils = {
4252
4175
  * @return [ 'A', radiusx, radiusy, rotation=0, largeArcFlag=1|0, sweepFlag=0, endx, endy ]
4253
4176
  */
4254
4177
  describeSVGArc: (x, y, radius, startAngle, endAngle, options) => {
4255
- if (typeof options === 'undefined')
4178
+ if (typeof options === "undefined")
4256
4179
  options = { moveToStart: true };
4257
4180
  const end = CircleSector.circleSectorUtils.polarToCartesian(x, y, radius, endAngle);
4258
4181
  const start = CircleSector.circleSectorUtils.polarToCartesian(x, y, radius, startAngle);
@@ -4277,7 +4200,7 @@ CircleSector.circleSectorUtils = {
4277
4200
  }
4278
4201
  const pathData = [];
4279
4202
  if (options.moveToStart) {
4280
- pathData.push('M', start.x, start.y);
4203
+ pathData.push("M", start.x, start.y);
4281
4204
  }
4282
4205
  pathData.push("A", radius, radius, 0, largeArcFlag, sweepFlag, end.x, end.y);
4283
4206
  return pathData;
@@ -4315,7 +4238,12 @@ CircleSector.circleSectorUtils = {
4315
4238
  * @modified 2021-11-15 Adding more parameters tot the `text()` function: fontSize, textAlign, fontFamily, lineHeight.
4316
4239
  * @modified 2021-11-19 Fixing the `label(text,x,y)` position.
4317
4240
  * @modified 2021-11-19 Added the `color` param to the `label(...)` function.
4318
- * @version 1.4.0
4241
+ * @modified 2022-02-03 Added the `lineWidth` param to the `crosshair` function.
4242
+ * @modified 2022-02-03 Added the `cross(...)` function.
4243
+ * @modified 2022-03-26 Added the private `nodeDefs` and `bufferedNodeDefs` attributes.
4244
+ * @modified 2022-03-26 Added the `texturedPoly` function to draw textures polygons.
4245
+ * @modified 2022-07-26 Adding `alpha` to the `image(...)` function.
4246
+ * @version 1.6.1
4319
4247
  **/
4320
4248
  const RAD_TO_DEG = 180 / Math.PI;
4321
4249
  /**
@@ -4342,7 +4270,7 @@ class drawutilssvg {
4342
4270
  * @param {boolean=} isSecondary - (optional) Indicates if this is the primary or secondary instance. Only primary instances manage child nodes.
4343
4271
  * @param {SVGGElement=} gNode - (optional) Primary and seconday instances share the same &lt;g> node.
4344
4272
  **/
4345
- constructor(svgNode, offset, scale, canvasSize, fillShapes, drawConfig, isSecondary, gNode, bufferGNode) {
4273
+ constructor(svgNode, offset, scale, canvasSize, fillShapes, drawConfig, isSecondary, gNode, bufferGNode, nodeDefs, bufferNodeDefs) {
4346
4274
  this.svgNode = svgNode;
4347
4275
  this.offset = new Vertex(0, 0).set(offset);
4348
4276
  this.scale = new Vertex(1, 1).set(scale);
@@ -4354,14 +4282,23 @@ class drawutilssvg {
4354
4282
  if (isSecondary) {
4355
4283
  this.gNode = gNode;
4356
4284
  this.bufferGNode = bufferGNode;
4285
+ this.nodeDefs = nodeDefs;
4286
+ this.bufferedNodeDefs = bufferNodeDefs;
4357
4287
  }
4358
4288
  else {
4359
4289
  this.addStyleDefs(drawConfig);
4290
+ this.addDefsNode();
4360
4291
  this.gNode = this.createSVGNode("g");
4361
4292
  this.bufferGNode = this.createSVGNode("g");
4362
4293
  this.svgNode.appendChild(this.gNode);
4363
4294
  }
4364
4295
  }
4296
+ /**
4297
+ * Adds a default style defintion based on the passed DrawConfig.
4298
+ * Twaek the draw config to change default colors or line thicknesses.
4299
+ *
4300
+ * @param {DrawConfig} drawConfig
4301
+ */
4365
4302
  addStyleDefs(drawConfig) {
4366
4303
  this.nodeStyle = this.createSVGNode("style");
4367
4304
  this.svgNode.appendChild(this.nodeStyle);
@@ -4394,6 +4331,15 @@ class drawutilssvg {
4394
4331
  }
4395
4332
  this.nodeStyle.innerHTML = rules.join("\n");
4396
4333
  }
4334
+ /**
4335
+ * Adds the internal <defs> node.
4336
+ */
4337
+ addDefsNode() {
4338
+ this.nodeDefs = this.createSVGNode("defs");
4339
+ // this.svgNode.appendChild(this.nodeDefs);
4340
+ this.bufferedNodeDefs = this.createSVGNode("defs");
4341
+ this.svgNode.appendChild(this.nodeDefs);
4342
+ }
4397
4343
  /**
4398
4344
  * This is a simple way to include custom CSS class mappings to the style defs of the generated SVG.
4399
4345
  *
@@ -4531,7 +4477,7 @@ class drawutilssvg {
4531
4477
  copyInstance(fillShapes) {
4532
4478
  var copy = new drawutilssvg(this.svgNode, this.offset, this.scale, this.canvasSize, fillShapes, null, // no DrawConfig
4533
4479
  true, // isSecondary
4534
- this.gNode, this.bufferGNode);
4480
+ this.gNode, this.bufferGNode, this.nodeDefs, this.bufferedNodeDefs);
4535
4481
  return copy;
4536
4482
  }
4537
4483
  /**
@@ -4608,11 +4554,15 @@ class drawutilssvg {
4608
4554
  // layout updates.
4609
4555
  // Replace the old <g>-node with the buffer node.
4610
4556
  // https://stackoverflow.com/questions/27442464/how-to-update-a-svg-image-without-seeing-a-blinking
4557
+ this.svgNode.replaceChild(this.bufferedNodeDefs, this.nodeDefs);
4611
4558
  this.svgNode.replaceChild(this.bufferGNode, this.gNode);
4612
4559
  }
4613
- let tmp = this.gNode;
4560
+ const tmpGNode = this.gNode;
4614
4561
  this.gNode = this.bufferGNode;
4615
- this.bufferGNode = tmp;
4562
+ this.bufferGNode = tmpGNode;
4563
+ const tmpDefsNode = this.nodeDefs;
4564
+ this.nodeDefs = this.bufferedNodeDefs;
4565
+ this.bufferedNodeDefs = tmpDefsNode;
4616
4566
  }
4617
4567
  _x(x) {
4618
4568
  return this.offset.x + this.scale.x * x;
@@ -4675,11 +4625,12 @@ class drawutilssvg {
4675
4625
  * @param {Image} image - The image object to draw.
4676
4626
  * @param {Vertex} position - The position to draw the the upper left corner at.
4677
4627
  * @param {Vertex} size - The x/y-size to draw the image with.
4628
+ * @param {number=0.0} alpha - (optional, default=0.0) The transparency (1.0=opaque, 0.0=transparent).
4678
4629
  * @return {void}
4679
4630
  * @instance
4680
4631
  * @memberof drawutilssvg
4681
4632
  **/
4682
- image(image, position, size) {
4633
+ image(image, position, size, alpha = 1.0) {
4683
4634
  const node = this.makeNode("image");
4684
4635
  // We need to re-adjust the image if it was not yet fully loaded before.
4685
4636
  const setImageSize = (image) => {
@@ -4689,6 +4640,9 @@ class drawutilssvg {
4689
4640
  node.setAttribute("width", `${image.naturalWidth * this.scale.x}`);
4690
4641
  node.setAttribute("height", `${image.naturalHeight * this.scale.y}`);
4691
4642
  node.setAttribute("display", null); // Dislay when loaded
4643
+ // if (alpha) {
4644
+ node.setAttribute("opacity", `${alpha}`);
4645
+ // }
4692
4646
  node.setAttribute("transform", `translate(${this._x(position.x)} ${this._y(position.y)}) scale(${ratioX} ${ratioY})`);
4693
4647
  }
4694
4648
  };
@@ -4704,6 +4658,74 @@ class drawutilssvg {
4704
4658
  node.setAttribute("href", image.src);
4705
4659
  return this._bindFillDraw(node, "image", null, null);
4706
4660
  }
4661
+ /**
4662
+ * Draw an image at the given position with the given size.<br>
4663
+ * <br>
4664
+ * 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.
4665
+ *
4666
+ * @method texturedPoly
4667
+ * @param {Image} textureImage - The image object to draw.
4668
+ * @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
4669
+ * @param {Polygon} polygon - The polygon to use as clip path.
4670
+ * @param {Vertex} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
4671
+ * @param {number} rotation - The rotation to use for the polygon (and for the texture).
4672
+ * @return {void}
4673
+ * @instance
4674
+ * @memberof drawutilssvg
4675
+ **/
4676
+ texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation) {
4677
+ polygon.getBounds();
4678
+ const rotatedScalingOrigin = new Vertex(textureSize.min).clone().rotate(rotation, polygonPosition);
4679
+ polygonPosition.clone().add(rotatedScalingOrigin.difference(textureSize.min).inv());
4680
+ // Create something like this
4681
+ // ...
4682
+ // <defs>
4683
+ // <clipPath id="shape">
4684
+ // <path fill="none" d="..."/>
4685
+ // </clipPath>
4686
+ // </defs>
4687
+ // ...
4688
+ // <g clip-path="url(#shape)">
4689
+ // <g transform="scale(...)">
4690
+ // <image width="643" height="643" transform="rotate(...)" xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/beagle400.jpg" >
4691
+ // </g>
4692
+ // </g>
4693
+ // </image>
4694
+ // ...
4695
+ const clipPathNode = this.makeNode("clipPath");
4696
+ const clipPathId = `clippath_${UIDGenerator.next()}`; // TODO: use a better UUID generator here?
4697
+ clipPathNode.setAttribute("id", clipPathId);
4698
+ const gNode = this.makeNode("g");
4699
+ const imageNode = this.makeNode("image");
4700
+ imageNode.setAttribute("x", `${this._x(rotatedScalingOrigin.x)}`);
4701
+ imageNode.setAttribute("y", `${this._y(rotatedScalingOrigin.y)}`);
4702
+ imageNode.setAttribute("width", `${textureSize.width}`);
4703
+ imageNode.setAttribute("height", `${textureSize.height}`);
4704
+ imageNode.setAttribute("href", textureImage.src);
4705
+ // imageNode.setAttribute("opacity", "0.5");
4706
+ // SVG rotations in degrees
4707
+ imageNode.setAttribute("transform", `rotate(${rotation * RAD_TO_DEG}, ${this._x(rotatedScalingOrigin.x)}, ${this._y(rotatedScalingOrigin.y)})`);
4708
+ const pathNode = this.makeNode("path");
4709
+ const pathData = [];
4710
+ if (polygon.vertices.length > 0) {
4711
+ pathData.push("M", `${this._x(polygon.vertices[0].x)}`, `${this._y(polygon.vertices[0].y)}`);
4712
+ for (var i = 1; i < polygon.vertices.length; i++) {
4713
+ pathData.push("L", `${this._x(polygon.vertices[i].x)}`, `${this._y(polygon.vertices[i].y)}`);
4714
+ }
4715
+ }
4716
+ pathNode.setAttribute("d", pathData.join(" "));
4717
+ clipPathNode.appendChild(pathNode);
4718
+ this.bufferedNodeDefs.appendChild(clipPathNode);
4719
+ gNode.appendChild(imageNode);
4720
+ gNode.setAttribute("transform-origin", `${this._x(rotatedScalingOrigin.x)} ${this._y(rotatedScalingOrigin.y)}`);
4721
+ gNode.setAttribute("transform", `scale(${this.scale.x}, ${this.scale.y})`);
4722
+ const clipNode = this.makeNode("g");
4723
+ clipNode.appendChild(gNode);
4724
+ clipNode.setAttribute("clip-path", `url(#${clipPathId})`);
4725
+ // TODO: check if the image class is correct here or if we should use a 'clippedImage' class here
4726
+ this._bindFillDraw(clipNode, "image", null, null); // No color, no lineWidth
4727
+ return clipNode;
4728
+ }
4707
4729
  /**
4708
4730
  * Draw the given (cubic) bézier curve.
4709
4731
  *
@@ -5096,11 +5118,12 @@ class drawutilssvg {
5096
5118
  * @param {XYCoords} center - The center of the crosshair.
5097
5119
  * @param {number} radius - The radius of the crosshair.
5098
5120
  * @param {string} color - The CSS color to draw the crosshair with.
5121
+ * @param {number=0.5} lineWidth - (optional, default=0.5) The line width to use.
5099
5122
  * @return {void}
5100
5123
  * @instance
5101
5124
  * @memberof drawutilssvg
5102
5125
  */
5103
- crosshair(center, radius, color) {
5126
+ crosshair(center, radius, color, lineWidth) {
5104
5127
  const node = this.makeNode("path");
5105
5128
  const d = [
5106
5129
  "M",
@@ -5117,7 +5140,40 @@ class drawutilssvg {
5117
5140
  this._y(center.y) + radius
5118
5141
  ];
5119
5142
  node.setAttribute("d", d.join(" "));
5120
- return this._bindFillDraw(node, "crosshair", color, 0.5);
5143
+ return this._bindFillDraw(node, "crosshair", color, lineWidth || 0.5);
5144
+ }
5145
+ /**
5146
+ * Draw a cross with diagonal axes with given radius, color and lineWidth at the given position.<br>
5147
+ * <br>
5148
+ * Note that the x's radius will not be affected by scaling.
5149
+ *
5150
+ * @method crosshair
5151
+ * @param {XYCoords} center - The center of the crosshair.
5152
+ * @param {number} radius - The radius of the crosshair.
5153
+ * @param {string} color - The CSS color to draw the crosshair with.
5154
+ * @param {number=1} lineWidth - (optional, default=1.0) The line width to use.
5155
+ * @return {void}
5156
+ * @instance
5157
+ * @memberof drawutils
5158
+ */
5159
+ cross(center, radius, color, lineWidth) {
5160
+ const node = this.makeNode("path");
5161
+ const d = [
5162
+ "M",
5163
+ this._x(center.x) - radius,
5164
+ this._y(center.y) - radius,
5165
+ "L",
5166
+ this._x(center.x) + radius,
5167
+ this._y(center.y) + radius,
5168
+ "M",
5169
+ this._x(center.x) - radius,
5170
+ this._y(center.y) + radius,
5171
+ "L",
5172
+ this._x(center.x) + radius,
5173
+ this._y(center.y) - radius
5174
+ ];
5175
+ node.setAttribute("d", d.join(" "));
5176
+ return this._bindFillDraw(node, "cross", color, lineWidth || 1.0);
5121
5177
  }
5122
5178
  /**
5123
5179
  * Draw a polygon.
@@ -5280,14 +5336,6 @@ class drawutilssvg {
5280
5336
  if (this.isSecondary) {
5281
5337
  return;
5282
5338
  }
5283
- // // Clearing an SVG is equivalent to removing all its child elements.
5284
- // for (var i = 0; i < this.gNode.childNodes.length; i++) {
5285
- // // Hide all nodes here. Don't throw them away.
5286
- // // We can probably re-use them in the next draw cycle.
5287
- // var child: SVGElement = this.gNode.childNodes[i] as SVGElement;
5288
- // this.cache.set(child.getAttribute("id"), child);
5289
- // }
5290
- // this.removeAllChildNodes();
5291
5339
  // Add a covering rect with the given background color
5292
5340
  this.curId = "background";
5293
5341
  this.curClassName = undefined;
@@ -5313,6 +5361,9 @@ class drawutilssvg {
5313
5361
  while (this.bufferGNode.lastChild) {
5314
5362
  this.bufferGNode.removeChild(this.bufferGNode.lastChild);
5315
5363
  }
5364
+ while (this.bufferedNodeDefs.lastChild) {
5365
+ this.bufferedNodeDefs.removeChild(this.bufferedNodeDefs.lastChild);
5366
+ }
5316
5367
  }
5317
5368
  /**
5318
5369
  * Create a new and empty `SVGElement` &lt;svg&gt; in the svg-namespace.
@@ -5552,7 +5603,12 @@ drawutilssvg.HEAD_XML = [
5552
5603
  * @modified 2021-05-31 Added the `setConfiguration` function from `DrawLib`.
5553
5604
  * @modified 2021-11-12 Adding more parameters tot the `text()` function: fontSize, textAlign, fontFamily, lineHeight.
5554
5605
  * @modified 2021-11-19 Added the `color` param to the `label(...)` function.
5555
- * @version 1.10.0
5606
+ * @modified 2022-02-03 Added the `lineWidth` param to the `crosshair` function.
5607
+ * @modified 2022-02-03 Added the `cross(...)` function.
5608
+ * @modified 2022-03-27 Added the `texturedPoly` function.
5609
+ * @modified 2022-06-01 Tweaked the `polyline` function; lineWidth now scales with scale.x.
5610
+ * @modified 2022-07-26 Adding `alpha` to the `image(...)` function.
5611
+ * @version 1.12.2
5556
5612
  **/
5557
5613
  // Todo: rename this class to Drawutils?
5558
5614
  /**
@@ -5689,16 +5745,18 @@ class drawutils {
5689
5745
  * @param {Image} image - The image object to draw.
5690
5746
  * @param {Vertex} position - The position to draw the the upper left corner at.
5691
5747
  * @param {Vertex} size - The x/y-size to draw the image with.
5748
+ * @param {number=0.0} alpha - (optional, default=0.0) The transparency (1.0=opaque, 0.0=transparent).
5692
5749
  * @return {void}
5693
5750
  * @instance
5694
5751
  * @memberof drawutils
5695
5752
  **/
5696
- image(image, position, size) {
5753
+ image(image, position, size, alpha = 1.0) {
5697
5754
  if (!image.complete || !image.naturalWidth) {
5698
5755
  // Avoid drawing un-unloaded or broken images
5699
5756
  return;
5700
5757
  }
5701
5758
  this.ctx.save();
5759
+ this.ctx.globalAlpha = alpha;
5702
5760
  // Note that there is a Safari bug with the 3 or 5 params variant.
5703
5761
  // Only the 9-param varaint works.
5704
5762
  this.ctx.drawImage(image, 0, 0, image.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
@@ -5706,6 +5764,96 @@ class drawutils {
5706
5764
  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);
5707
5765
  this.ctx.restore();
5708
5766
  }
5767
+ /**
5768
+ * Draw an image at the given position with the given size.<br>
5769
+ * <br>
5770
+ * 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.
5771
+ *
5772
+ * @method texturedPoly
5773
+ * @param {Image} textureImage - The image object to draw.
5774
+ * @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
5775
+ * @param {Polygon} polygon - The polygon to use as clip path.
5776
+ * @param {Vertex} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
5777
+ * @param {number} rotation - The rotation to use for the polygon (and for the texture).
5778
+ * @param {XYCoords={x:0,y:0}} rotationCenter - (optional) The rotational center; default is center of bounding box.
5779
+ * @return {void}
5780
+ * @instance
5781
+ * @memberof drawutils
5782
+ **/
5783
+ texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation) {
5784
+ var basePolygonBounds = polygon.getBounds();
5785
+ var targetCenterDifference = polygonPosition.clone().difference(basePolygonBounds.getCenter());
5786
+ // var rotationalOffset = rotationCenter ? polygonPosition.difference(rotationCenter) : { x: 0, y: 0 };
5787
+ // var rotationalOffset = { x: 0, y: 0 };
5788
+ basePolygonBounds.getCenter().sub(targetCenterDifference);
5789
+ // Get the position offset of the polygon
5790
+ var targetTextureSize = new Vertex(textureSize.width, textureSize.height);
5791
+ // var targetTextureOffset = new Vertex(-textureSize.width / 2, -textureSize.height / 2).sub(targetCenterDifference);
5792
+ var targetTextureOffset = new Vertex(textureSize.min.x, textureSize.min.y).sub(polygonPosition);
5793
+ this.ctx.save();
5794
+ // this.ctx.translate(this.offset.x + rotationCenter.x * this.scale.x, this.offset.y + rotationCenter.y * this.scale.y);
5795
+ this.ctx.translate(this.offset.x + polygonPosition.x * this.scale.x, this.offset.y + polygonPosition.y * this.scale.y);
5796
+ drawutils.helpers.clipPoly(this.ctx, {
5797
+ x: -polygonPosition.x * this.scale.x,
5798
+ y: -polygonPosition.y * this.scale.y
5799
+ }, this.scale, polygon.vertices);
5800
+ this.ctx.scale(this.scale.x, this.scale.y);
5801
+ this.ctx.rotate(rotation);
5802
+ this.ctx.drawImage(textureImage, 0, 0, textureImage.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
5803
+ textureImage.naturalHeight - 1, // To avoid errors substract 1 here.
5804
+ targetTextureOffset.x, // * this.scale.x,
5805
+ targetTextureOffset.y, // * this.scale.y,
5806
+ targetTextureSize.x, // * this.scale.x,
5807
+ targetTextureSize.y // * this.scale.y
5808
+ );
5809
+ this.ctx.restore();
5810
+ }
5811
+ _texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation, rotationCenter = { x: 0, y: 0 }) {
5812
+ var basePolygonBounds = polygon.getBounds();
5813
+ var targetCenterDifference = polygonPosition.clone().difference(basePolygonBounds.getCenter());
5814
+ var rotationalOffset = rotationCenter ? polygonPosition.difference(rotationCenter) : { x: 0, y: 0 };
5815
+ // var rotationalOffset = { x: 0, y: 0 };
5816
+ var tileCenter = basePolygonBounds.getCenter().sub(targetCenterDifference);
5817
+ // Get the position offset of the polygon
5818
+ var targetTextureSize = new Vertex(textureSize.width, textureSize.height);
5819
+ var targetTextureOffset = new Vertex(-textureSize.width / 2, -textureSize.height / 2).sub(targetCenterDifference);
5820
+ this.ctx.save();
5821
+ // this.ctx.translate(
5822
+ // this.offset.x + (tileCenter.x - rotationalOffset.x * 0 + targetTextureOffset.x * 0.0) * this.scale.x,
5823
+ // this.offset.y + (tileCenter.y - rotationalOffset.y * 0 + targetTextureOffset.y * 0.0) * this.scale.y
5824
+ // );
5825
+ 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);
5826
+ this.ctx.rotate(rotation);
5827
+ drawutils.helpers.clipPoly(this.ctx, {
5828
+ x: (-targetCenterDifference.x * 1 - tileCenter.x - rotationalOffset.x) * this.scale.x,
5829
+ y: (-targetCenterDifference.y * 1 - tileCenter.y - rotationalOffset.y) * this.scale.y
5830
+ }, this.scale, polygon.vertices);
5831
+ this.ctx.drawImage(textureImage, 0, 0, textureImage.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
5832
+ textureImage.naturalHeight - 1, // To avoid errors substract 1 here.
5833
+ (-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);
5834
+ // const scaledTextureSize = new Bounds(
5835
+ // new Vertex(
5836
+ // -polygonPosition.x + targetTextureOffset.x - rotationalOffset.x,
5837
+ // -polygonPosition.y + targetTextureOffset.y - rotationalOffset.y
5838
+ // ).scaleXY(this.scale, rotationCenter),
5839
+ // new Vertex(
5840
+ // -polygonPosition.x + targetTextureOffset.x - rotationalOffset.x + targetTextureSize.x,
5841
+ // -polygonPosition.y + targetTextureOffset.y - rotationalOffset.y + targetTextureSize.y
5842
+ // ).scaleXY(this.scale, rotationCenter)
5843
+ // );
5844
+ // this.ctx.drawImage(
5845
+ // textureImage,
5846
+ // 0,
5847
+ // 0,
5848
+ // textureImage.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
5849
+ // textureImage.naturalHeight - 1, // To avoid errors substract 1 here.
5850
+ // scaledTextureSize.min.x,
5851
+ // scaledTextureSize.min.y,
5852
+ // scaledTextureSize.width,
5853
+ // scaledTextureSize.height
5854
+ // );
5855
+ this.ctx.restore();
5856
+ }
5709
5857
  /**
5710
5858
  * Draw a rectangle.
5711
5859
  *
@@ -6146,11 +6294,12 @@ class drawutils {
6146
6294
  * @param {XYCoords} center - The center of the crosshair.
6147
6295
  * @param {number} radius - The radius of the crosshair.
6148
6296
  * @param {string} color - The CSS color to draw the crosshair with.
6297
+ * @param {number=0.5} lineWidth - (optional, default=0.5) The line width to use.
6149
6298
  * @return {void}
6150
6299
  * @instance
6151
6300
  * @memberof drawutils
6152
6301
  */
6153
- crosshair(center, radius, color) {
6302
+ crosshair(center, radius, color, lineWidth) {
6154
6303
  this.ctx.save();
6155
6304
  this.ctx.beginPath();
6156
6305
  this.ctx.moveTo(this.offset.x + center.x * this.scale.x - radius, this.offset.y + center.y * this.scale.y);
@@ -6158,7 +6307,34 @@ class drawutils {
6158
6307
  this.ctx.moveTo(this.offset.x + center.x * this.scale.x, this.offset.y + center.y * this.scale.y - radius);
6159
6308
  this.ctx.lineTo(this.offset.x + center.x * this.scale.x, this.offset.y + center.y * this.scale.y + radius);
6160
6309
  this.ctx.strokeStyle = color;
6161
- this.ctx.lineWidth = 0.5;
6310
+ this.ctx.lineWidth = lineWidth || 0.5;
6311
+ this.ctx.stroke();
6312
+ this.ctx.closePath();
6313
+ this.ctx.restore();
6314
+ }
6315
+ /**
6316
+ * Draw a cross with diagonal axes with given radius, color and lineWidth at the given position.<br>
6317
+ * <br>
6318
+ * Note that the x's radius will not be affected by scaling.
6319
+ *
6320
+ * @method crosshair
6321
+ * @param {XYCoords} center - The center of the crosshair.
6322
+ * @param {number} radius - The radius of the crosshair.
6323
+ * @param {string} color - The CSS color to draw the crosshair with.
6324
+ * @param {number=1} lineWidth - (optional, default=1.0) The line width to use.
6325
+ * @return {void}
6326
+ * @instance
6327
+ * @memberof drawutils
6328
+ */
6329
+ cross(center, radius, color, lineWidth) {
6330
+ this.ctx.save();
6331
+ this.ctx.beginPath();
6332
+ this.ctx.moveTo(this.offset.x + center.x * this.scale.x - radius, this.offset.y + center.y * this.scale.y - radius);
6333
+ this.ctx.lineTo(this.offset.x + center.x * this.scale.x + radius, this.offset.y + center.y * this.scale.y + radius);
6334
+ this.ctx.moveTo(this.offset.x + center.x * this.scale.x - radius, this.offset.y + center.y * this.scale.y + radius);
6335
+ this.ctx.lineTo(this.offset.x + center.x * this.scale.x + radius, this.offset.y + center.y * this.scale.y - radius);
6336
+ this.ctx.strokeStyle = color;
6337
+ this.ctx.lineWidth = lineWidth || 1.0;
6162
6338
  this.ctx.stroke();
6163
6339
  this.ctx.closePath();
6164
6340
  this.ctx.restore();
@@ -6190,11 +6366,12 @@ class drawutils {
6190
6366
  * @memberof drawutils
6191
6367
  */
6192
6368
  polyline(vertices, isOpen, color, lineWidth) {
6193
- if (vertices.length <= 1)
6369
+ if (vertices.length <= 1) {
6194
6370
  return;
6371
+ }
6195
6372
  this.ctx.save();
6196
6373
  this.ctx.beginPath();
6197
- this.ctx.lineWidth = lineWidth || 1.0;
6374
+ this.ctx.lineWidth = lineWidth * this.scale.x || 1.0;
6198
6375
  this.ctx.moveTo(this.offset.x + vertices[0].x * this.scale.x, this.offset.y + vertices[0].y * this.scale.y);
6199
6376
  for (var i = 0; i < vertices.length; i++) {
6200
6377
  this.ctx.lineTo(this.offset.x + vertices[i].x * this.scale.x, this.offset.y + vertices[i].y * this.scale.y);
@@ -6336,6 +6513,21 @@ class drawutils {
6336
6513
  this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
6337
6514
  }
6338
6515
  }
6516
+ drawutils.helpers = {
6517
+ // A helper function to define the clipping path.
6518
+ // This could be a candidate for the draw library.
6519
+ clipPoly: (ctx, offset, scale, vertices) => {
6520
+ ctx.beginPath();
6521
+ // Set clip mask
6522
+ ctx.moveTo(offset.x + vertices[0].x * scale.x, offset.y + vertices[0].y * scale.y);
6523
+ for (var i = 1; i < vertices.length; i++) {
6524
+ const vert = vertices[i];
6525
+ ctx.lineTo(offset.x + vert.x * scale.x, offset.y + vert.y * scale.y);
6526
+ }
6527
+ ctx.closePath();
6528
+ ctx.clip();
6529
+ }
6530
+ };
6339
6531
 
6340
6532
  /**
6341
6533
  * @author Ikaros Kappler
@@ -6345,7 +6537,11 @@ class drawutils {
6345
6537
  * @modified 2020-10-15 Re-added the text() function.
6346
6538
  * @modified 2021-01-24 Added the `setCurrentId` function.
6347
6539
  * @modified 2021-05-31 Added the `setConfiguration` function from `DrawLib`.
6348
- * @version 0.0.5
6540
+ * @modified 2022-02-03 Added the `lineWidth` param to the `crosshair` function.
6541
+ * @modified 2022-02-03 Added the `cross(...)` function.
6542
+ * @modified 2022-03-27 Added the `texturedPoly` function.
6543
+ * @modified 2022-07-26 Adding `alpha` to the `image(...)` function.
6544
+ * @version 0.0.8
6349
6545
  **/
6350
6546
  /**
6351
6547
  * @classdesc A wrapper class for basic drawing operations. This is the WebGL
@@ -6535,11 +6731,30 @@ class drawutilsgl {
6535
6731
  * @param {Image} image - The image object to draw.
6536
6732
  * @param {Vertex} position - The position to draw the the upper left corner at.
6537
6733
  * @param {Vertex} size - The x/y-size to draw the image with.
6734
+ * @param {number=0.0} alpha - (optional, default=0.0) The transparency (0.0=opaque, 1.0=transparent).
6538
6735
  * @return {void}
6539
6736
  * @instance
6540
6737
  * @memberof drawutils
6541
6738
  **/
6542
- image(image, position, size) {
6739
+ image(image, position, size, alpha = 0.0) {
6740
+ // NOT YET IMPLEMENTED
6741
+ }
6742
+ /**
6743
+ * Draw an image at the given position with the given size.<br>
6744
+ * <br>
6745
+ * 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.
6746
+ *
6747
+ * @method texturedPoly
6748
+ * @param {Image} textureImage - The image object to draw.
6749
+ * @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
6750
+ * @param {Polygon} polygon - The polygon to use as clip path.
6751
+ * @param {Vertex} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
6752
+ * @param {number} rotation - The rotation to use for the polygon (and for the texture).
6753
+ * @return {void}
6754
+ * @instance
6755
+ * @memberof drawutilsgl
6756
+ **/
6757
+ texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation) {
6543
6758
  // NOT YET IMPLEMENTED
6544
6759
  }
6545
6760
  // +---------------------------------------------------------------------------------
@@ -6823,11 +7038,29 @@ class drawutilsgl {
6823
7038
  * @param {XYCoords} center - The center of the crosshair.
6824
7039
  * @param {number} radius - The radius of the crosshair.
6825
7040
  * @param {string} color - The CSS color to draw the crosshair with.
7041
+ * @param {number=0.5} lineWidth - (optional, default=0.5) The line width to use.
6826
7042
  * @return {void}
6827
7043
  * @instance
6828
7044
  * @memberof drawutils
6829
7045
  */
6830
- crosshair(center, radius, color) {
7046
+ crosshair(center, radius, color, lineWidth) {
7047
+ // NOT YET IMPLEMENTED
7048
+ }
7049
+ /**
7050
+ * Draw a cross with diagonal axes with given radius, color and lineWidth at the given position.<br>
7051
+ * <br>
7052
+ * Note that the x's radius will not be affected by scaling.
7053
+ *
7054
+ * @method crosshair
7055
+ * @param {XYCoords} center - The center of the crosshair.
7056
+ * @param {number} radius - The radius of the crosshair.
7057
+ * @param {string} color - The CSS color to draw the crosshair with.
7058
+ * @param {number=1} lineWidth - (optional, default=1.0) The line width to use.
7059
+ * @return {void}
7060
+ * @instance
7061
+ * @memberof drawutils
7062
+ */
7063
+ cross(center, radius, color, lineWidth) {
6831
7064
  // NOT YET IMPLEMENTED
6832
7065
  }
6833
7066
  /**
@@ -7067,7 +7300,9 @@ class GLU {
7067
7300
  * @modified 2020-12-28 Added the `getArea` function.
7068
7301
  * @modified 2021-01-20 Added UID.
7069
7302
  * @modified 2021-01-22 Always updating circumcircle when retieving it.
7070
- * @version 2.5.1
7303
+ * @modified 2022-02-02 Added the `destroy` method.
7304
+ * @modified 2022-02-02 Cleared the `Triangle.toSVGString` function (deprecated). Use `drawutilssvg` instead.
7305
+ * @version 2.6.0
7071
7306
  *
7072
7307
  * @file Triangle
7073
7308
  * @fileoverview A simple triangle class: three vertices.
@@ -7128,7 +7363,6 @@ class Triangle {
7128
7363
  throw `Cannot create triangle from array with less than three vertices (${arr.length})`;
7129
7364
  return new Triangle(arr[0], arr[1], arr[2]);
7130
7365
  }
7131
- ;
7132
7366
  /**
7133
7367
  * Get the area of this triangle. The returned area is never negative.
7134
7368
  *
@@ -7144,7 +7378,6 @@ class Triangle {
7144
7378
  getArea() {
7145
7379
  return Math.abs(Triangle.utils.signedArea(this.a.x, this.a.y, this.b.x, this.b.y, this.c.x, this.c.y));
7146
7380
  }
7147
- ;
7148
7381
  /**
7149
7382
  * Get the centroid of this triangle.
7150
7383
  *
@@ -7158,7 +7391,6 @@ class Triangle {
7158
7391
  getCentroid() {
7159
7392
  return new Vertex((this.a.x + this.b.x + this.c.x) / 3, (this.a.y + this.b.y + this.c.y) / 3);
7160
7393
  }
7161
- ;
7162
7394
  /**
7163
7395
  * Scale the triangle towards its centroid.
7164
7396
  *
@@ -7175,7 +7407,6 @@ class Triangle {
7175
7407
  this.c.scale(factor, centroid);
7176
7408
  return this;
7177
7409
  }
7178
- ;
7179
7410
  /**
7180
7411
  * Get the circumcircle of this triangle.
7181
7412
  *
@@ -7192,11 +7423,10 @@ class Triangle {
7192
7423
  * @memberof Triangle
7193
7424
  */
7194
7425
  getCircumcircle() {
7195
- // if( !this.center || !this.radius )
7426
+ // if( !this.center || !this.radius )
7196
7427
  this.calcCircumcircle();
7197
7428
  return new Circle(this.center.clone(), this.radius);
7198
7429
  }
7199
- ;
7200
7430
  /**
7201
7431
  * Check if this triangle and the passed triangle share an
7202
7432
  * adjacent edge.
@@ -7216,7 +7446,6 @@ class Triangle {
7216
7446
  var c = this.c.equals(tri.a) || this.c.equals(tri.b) || this.c.equals(tri.c);
7217
7447
  return (a && b) || (a && c) || (b && c);
7218
7448
  }
7219
- ;
7220
7449
  /**
7221
7450
  * Get that vertex of this triangle (a,b,c) that is not vert1 nor vert2 of
7222
7451
  * the passed two.
@@ -7229,14 +7458,13 @@ class Triangle {
7229
7458
  * @memberof Triangle
7230
7459
  */
7231
7460
  getThirdVertex(vert1, vert2) {
7232
- if (this.a.equals(vert1) && this.b.equals(vert2) || this.a.equals(vert2) && this.b.equals(vert1))
7461
+ if ((this.a.equals(vert1) && this.b.equals(vert2)) || (this.a.equals(vert2) && this.b.equals(vert1)))
7233
7462
  return this.c;
7234
- if (this.b.equals(vert1) && this.c.equals(vert2) || this.b.equals(vert2) && this.c.equals(vert1))
7463
+ if ((this.b.equals(vert1) && this.c.equals(vert2)) || (this.b.equals(vert2) && this.c.equals(vert1)))
7235
7464
  return this.a;
7236
7465
  //if( this.c.equals(vert1) && this.a.equals(vert2) || this.c.equals(vert2) && this.a.equals(vert1) )
7237
7466
  return this.b;
7238
7467
  }
7239
- ;
7240
7468
  /**
7241
7469
  * Re-compute the circumcircle of this triangle (if the vertices
7242
7470
  * have changed).
@@ -7276,8 +7504,7 @@ class Triangle {
7276
7504
  }
7277
7505
  this.radius_squared = dx * dx + dy * dy;
7278
7506
  this.radius = Math.sqrt(this.radius_squared);
7279
- }
7280
- ; // END calcCircumcircle
7507
+ } // END calcCircumcircle
7281
7508
  /**
7282
7509
  * Check if the passed vertex is inside this triangle's
7283
7510
  * circumcircle.
@@ -7292,9 +7519,8 @@ class Triangle {
7292
7519
  const dx = this.center.x - v.x;
7293
7520
  const dy = this.center.y - v.y;
7294
7521
  const dist_squared = dx * dx + dy * dy;
7295
- return (dist_squared <= this.radius_squared);
7522
+ return dist_squared <= this.radius_squared;
7296
7523
  }
7297
- ;
7298
7524
  /**
7299
7525
  * Get the rectangular bounds for this triangle.
7300
7526
  *
@@ -7306,7 +7532,6 @@ class Triangle {
7306
7532
  bounds() {
7307
7533
  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)));
7308
7534
  }
7309
- ;
7310
7535
  /**
7311
7536
  * Convert this triangle to a polygon instance.
7312
7537
  *
@@ -7320,7 +7545,6 @@ class Triangle {
7320
7545
  toPolygon() {
7321
7546
  return new Polygon([this.a, this.b, this.c]);
7322
7547
  }
7323
- ;
7324
7548
  /**
7325
7549
  * Get the determinant of this triangle.
7326
7550
  *
@@ -7333,7 +7557,6 @@ class Triangle {
7333
7557
  // (b.y - a.y)*(c.x - b.x) - (c.y - b.y)*(b.x - a.x);
7334
7558
  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);
7335
7559
  }
7336
- ;
7337
7560
  /**
7338
7561
  * Checks if the passed vertex (p) is inside this triangle.
7339
7562
  *
@@ -7348,7 +7571,6 @@ class Triangle {
7348
7571
  containsPoint(p) {
7349
7572
  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);
7350
7573
  }
7351
- ;
7352
7574
  /**
7353
7575
  * Get that inner triangle which defines the maximal incircle.
7354
7576
  *
@@ -7367,7 +7589,6 @@ class Triangle {
7367
7589
  const circleIntersC = lineC.getClosestPoint(intersection);
7368
7590
  return new Triangle(circleIntersA, circleIntersB, circleIntersC);
7369
7591
  }
7370
- ;
7371
7592
  /**
7372
7593
  * Get the incircle of this triangle. That is the circle that touches each side
7373
7594
  * of this triangle in exactly one point.
@@ -7379,7 +7600,6 @@ class Triangle {
7379
7600
  getIncircle() {
7380
7601
  return this.getIncircularTriangle().getCircumcircle();
7381
7602
  }
7382
- ;
7383
7603
  /**
7384
7604
  * Get the incenter of this triangle (which is the center of the circumcircle).
7385
7605
  *
@@ -7393,7 +7613,6 @@ class Triangle {
7393
7613
  this.calcCircumcircle();
7394
7614
  return this.center.clone();
7395
7615
  }
7396
- ;
7397
7616
  /**
7398
7617
  * Converts this triangle into a human-readable string.
7399
7618
  *
@@ -7403,46 +7622,19 @@ class Triangle {
7403
7622
  * @memberof Triangle
7404
7623
  */
7405
7624
  toString() {
7406
- return '{ a : ' + this.a.toString() + ', b : ' + this.b.toString() + ', c : ' + this.c.toString() + '}';
7625
+ return "{ a : " + this.a.toString() + ", b : " + this.b.toString() + ", c : " + this.c.toString() + "}";
7407
7626
  }
7408
- ;
7409
7627
  /**
7410
- * Create an SVG representation of this triangle.
7411
- *
7412
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
7413
- * @method toSVGString
7414
- * @param {object=} options - An optional set of options, like 'className'.
7415
- * @return {string} The SVG string.
7416
- * @instance
7417
- * @memberof Triangle
7418
- **/
7419
- toSVGString(options) {
7420
- options = options || {};
7421
- var buffer = [];
7422
- buffer.push('<path');
7423
- if (options.className)
7424
- buffer.push(' class="' + options.className + '"');
7425
- buffer.push(' d="');
7426
- var vertices = [this.a, this.b, this.c];
7427
- if (vertices.length > 0) {
7428
- buffer.push('M ');
7429
- buffer.push(vertices[0].x);
7430
- buffer.push(' ');
7431
- buffer.push(vertices[0].y);
7432
- for (var i = 1; i < vertices.length; i++) {
7433
- buffer.push(' L ');
7434
- buffer.push(vertices[i].x);
7435
- buffer.push(' ');
7436
- buffer.push(vertices[i].y);
7437
- }
7438
- //if( !this.isOpen ) {
7439
- buffer.push(' Z');
7440
- //}
7441
- }
7442
- buffer.push('" />');
7443
- return buffer.join('');
7628
+ * This function should invalidate any installed listeners and invalidate this object.
7629
+ * After calling this function the object might not hold valid data any more and
7630
+ * should not be used.
7631
+ */
7632
+ destroy() {
7633
+ this.a.destroy();
7634
+ this.b.destroy();
7635
+ this.c.destroy();
7636
+ this.isDestroyed = true;
7444
7637
  }
7445
- ;
7446
7638
  }
7447
7639
  /**
7448
7640
  * An epsilon for comparison.
@@ -7454,10 +7646,10 @@ Triangle.EPSILON = 1.0e-6;
7454
7646
  Triangle.utils = {
7455
7647
  // Used in the bounds() function.
7456
7648
  max3(a, b, c) {
7457
- return (a >= b && a >= c) ? a : (b >= a && b >= c) ? b : c;
7649
+ return a >= b && a >= c ? a : b >= a && b >= c ? b : c;
7458
7650
  },
7459
7651
  min3(a, b, c) {
7460
- return (a <= b && a <= c) ? a : (b <= a && b <= c) ? b : c;
7652
+ return a <= b && a <= c ? a : b <= a && b <= c ? b : c;
7461
7653
  },
7462
7654
  signedArea(p0x, p0y, p1x, p1y, p2x, p2y) {
7463
7655
  return 0.5 * (-p1y * p2x + p0y * (-p1x + p2x) + p0x * (p1y - p2y) + p1x * p2y);
@@ -7473,9 +7665,9 @@ Triangle.utils = {
7473
7665
  // http://stackoverflow.com/questions/2049582/how-to-determine-a-point-in-a-2d-triangle
7474
7666
  // var area : number = 1/2*(-p1y*p2x + p0y*(-p1x + p2x) + p0x*(p1y - p2y) + p1x*p2y);
7475
7667
  var area = Triangle.utils.signedArea(p0x, p0y, p1x, p1y, p2x, p2y);
7476
- var s = 1 / (2 * area) * (p0y * p2x - p0x * p2y + (p2y - p0y) * px + (p0x - p2x) * py);
7477
- var t = 1 / (2 * area) * (p0x * p1y - p0y * p1x + (p0y - p1y) * px + (p1x - p0x) * py);
7478
- return s > 0 && t > 0 && (1 - s - t) > 0;
7668
+ var s = (1 / (2 * area)) * (p0y * p2x - p0x * p2y + (p2y - p0y) * px + (p0x - p2x) * py);
7669
+ var t = (1 / (2 * area)) * (p0x * p1y - p0y * p1x + (p0y - p1y) * px + (p1x - p0x) * py);
7670
+ return s > 0 && t > 0 && 1 - s - t > 0;
7479
7671
  }
7480
7672
  };
7481
7673
 
@@ -7646,7 +7838,8 @@ Grid.utils = {
7646
7838
  * @modified 2020-07-28 Changed the `delete` key code from 8 to 46.
7647
7839
  * @modified 2020-10-04 Changed `window` to `globalThis`.
7648
7840
  * @modified 2020-10-04 Added extended JSDoc.
7649
- * @version 1.0.4
7841
+ * @modified 2022-02-02 Added the `destroy` method.
7842
+ * @version 1.1.0
7650
7843
  *
7651
7844
  * @file KeyHandler
7652
7845
  * @public
@@ -7677,7 +7870,7 @@ class KeyHandler {
7677
7870
  * @memberof KeyHandler
7678
7871
  * @param {HTMLElement} options.element (optional) The HTML element to listen on; if null then 'window' will be used.
7679
7872
  * @param {boolean} options.trackAll (optional) Set to true if you want to keep track of _all_ keys (keyStatus).
7680
- **/
7873
+ **/
7681
7874
  constructor(options) {
7682
7875
  this.downListeners = [];
7683
7876
  this.pressListeners = [];
@@ -7696,7 +7889,6 @@ class KeyHandler {
7696
7889
  // Install the listeners
7697
7890
  this.installListeners();
7698
7891
  }
7699
- ;
7700
7892
  /**
7701
7893
  * A helper function to fire key events from this KeyHandler.
7702
7894
  *
@@ -7714,7 +7906,6 @@ class KeyHandler {
7714
7906
  }
7715
7907
  return hasListener;
7716
7908
  }
7717
- ;
7718
7909
  /**
7719
7910
  * Internal function to fire a new keydown event to all listeners.
7720
7911
  * You should not call this function on your own unless you know what you do.
@@ -7730,10 +7921,9 @@ class KeyHandler {
7730
7921
  fireDownEvent(e, handler) {
7731
7922
  if (handler.fireEvent(e, handler.downListeners) || handler.trackAllKeys) {
7732
7923
  // Down event has listeners. Update key state.
7733
- handler.keyStates[e.keyCode] = 'down';
7924
+ handler.keyStates[e.keyCode] = "down";
7734
7925
  }
7735
7926
  }
7736
- ;
7737
7927
  /**
7738
7928
  * Internal function to fire a new keypress event to all listeners.
7739
7929
  * You should not call this function on your own unless you know what you do.
@@ -7749,7 +7939,6 @@ class KeyHandler {
7749
7939
  firePressEvent(e, handler) {
7750
7940
  handler.fireEvent(e, handler.pressListeners);
7751
7941
  }
7752
- ;
7753
7942
  /**
7754
7943
  * Internal function to fire a new keyup event to all listeners.
7755
7944
  * You should not call this function on your own unless you know what you do.
@@ -7768,20 +7957,18 @@ class KeyHandler {
7768
7957
  delete handler.keyStates[e.keyCode];
7769
7958
  }
7770
7959
  }
7771
- ;
7772
7960
  /**
7773
7961
  * Resolve the key/name code.
7774
7962
  */
7775
7963
  static key2code(key) {
7776
- if (typeof key == 'number')
7964
+ if (typeof key == "number")
7777
7965
  return key;
7778
- if (typeof key != 'string')
7966
+ if (typeof key != "string")
7779
7967
  throw "Unknown key name or key type (should be a string or integer): " + key;
7780
7968
  if (KeyHandler.KEY_CODES[key])
7781
7969
  return KeyHandler.KEY_CODES[key];
7782
7970
  throw "Unknown key (cannot resolve key code): " + key;
7783
7971
  }
7784
- ;
7785
7972
  /**
7786
7973
  * Install the required listeners into the initially passed element.
7787
7974
  *
@@ -7790,20 +7977,24 @@ class KeyHandler {
7790
7977
  */
7791
7978
  installListeners() {
7792
7979
  var _self = this;
7793
- this.element.addEventListener('keydown', this._keyDownListener = (e) => { _self.fireDownEvent(e, _self); });
7794
- this.element.addEventListener('keypress', this._keyPressListener = (e) => { _self.firePressEvent(e, _self); });
7795
- this.element.addEventListener('keyup', this._keyUpListener = (e) => { _self.fireUpEvent(e, _self); });
7980
+ this.element.addEventListener("keydown", (this._keyDownListener = (e) => {
7981
+ _self.fireDownEvent(e, _self);
7982
+ }));
7983
+ this.element.addEventListener("keypress", (this._keyPressListener = (e) => {
7984
+ _self.firePressEvent(e, _self);
7985
+ }));
7986
+ this.element.addEventListener("keyup", (this._keyUpListener = (e) => {
7987
+ _self.fireUpEvent(e, _self);
7988
+ }));
7796
7989
  }
7797
- ;
7798
7990
  /**
7799
7991
  * Remove all installed event listeners from the underlying element.
7800
7992
  */
7801
7993
  releaseListeners() {
7802
- this.element.removeEventListener('keydown', this._keyDownListener);
7803
- this.element.removeEventListener('keypress', this._keyPressListener);
7804
- this.element.removeEventListener('keyup', this._keyUpListener);
7994
+ this.element.removeEventListener("keydown", this._keyDownListener);
7995
+ this.element.removeEventListener("keypress", this._keyPressListener);
7996
+ this.element.removeEventListener("keyup", this._keyUpListener);
7805
7997
  }
7806
- ;
7807
7998
  /**
7808
7999
  * Listen for key down. This function allows chaining.
7809
8000
  *
@@ -7820,7 +8011,6 @@ class KeyHandler {
7820
8011
  this.downListeners.push({ key: key, keyCode: KeyHandler.key2code(key), listener: listener });
7821
8012
  return this;
7822
8013
  }
7823
- ;
7824
8014
  /**
7825
8015
  * Listen for key press.
7826
8016
  *
@@ -7837,7 +8027,6 @@ class KeyHandler {
7837
8027
  this.pressListeners.push({ key: key, keyCode: KeyHandler.key2code(key), listener: listener });
7838
8028
  return this;
7839
8029
  }
7840
- ;
7841
8030
  /**
7842
8031
  * Listen for key up.
7843
8032
  *
@@ -7854,23 +8043,31 @@ class KeyHandler {
7854
8043
  this.upListeners.push({ key: key, keyCode: KeyHandler.key2code(key), listener: listener });
7855
8044
  return this;
7856
8045
  }
7857
- ;
7858
8046
  /**
7859
8047
  * Check if a specific key is currently held pressed.
7860
8048
  *
7861
8049
  * @param {string|number} key - Any key identifier, key code or one from the KEY_CODES list.
7862
8050
  */
7863
8051
  isDown(key) {
7864
- if (typeof key == 'number')
8052
+ if (typeof key == "number")
7865
8053
  return this.keyStates[key] ? true : false;
7866
8054
  else
7867
8055
  return this.keyStates[KeyHandler.key2code(key)] ? true : false;
7868
8056
  }
8057
+ /**
8058
+ * This function should invalidate any installed listeners and invalidate this object.
8059
+ * After calling this function the object might not hold valid data any more and
8060
+ * should not be used any more.
8061
+ */
8062
+ destroy() {
8063
+ this.releaseListeners();
8064
+ }
7869
8065
  }
7870
8066
  /**
7871
8067
  * Source:
7872
8068
  * https://keycode.info/
7873
8069
  */
8070
+ // prettier-ignore
7874
8071
  KeyHandler.KEY_CODES = {
7875
8072
  'break': 3,
7876
8073
  'backspace': 8,
@@ -8187,41 +8384,41 @@ class MouseHandler {
8187
8384
  // | drag offset, ...) to the callbacks.
8188
8385
  // +-------------------------------------------------
8189
8386
  const _self = this;
8190
- this.handlers['mousemove'] = (e) => {
8387
+ this.handlers["mousemove"] = (e) => {
8191
8388
  if (_self.listeners.mousemove)
8192
- _self.listeners.mousemove(_self.mkParams(e, 'mousemove'));
8389
+ _self.listeners.mousemove(_self.mkParams(e, "mousemove"));
8193
8390
  if (_self.mouseDragPos && _self.listeners.drag)
8194
- _self.listeners.drag(_self.mkParams(e, 'drag'));
8391
+ _self.listeners.drag(_self.mkParams(e, "drag"));
8195
8392
  if (_self.mouseDownPos)
8196
8393
  _self.mouseDragPos = _self.relPos(e);
8197
8394
  };
8198
- this.handlers['mouseup'] = (e) => {
8395
+ this.handlers["mouseup"] = (e) => {
8199
8396
  if (_self.listeners.mouseup)
8200
- _self.listeners.mouseup(_self.mkParams(e, 'mouseup'));
8397
+ _self.listeners.mouseup(_self.mkParams(e, "mouseup"));
8201
8398
  _self.mouseDragPos = undefined;
8202
8399
  _self.mouseDownPos = undefined;
8203
8400
  _self.mouseButton = -1;
8204
8401
  };
8205
- this.handlers['mousedown'] = (e) => {
8402
+ this.handlers["mousedown"] = (e) => {
8206
8403
  _self.mouseDragPos = _self.relPos(e);
8207
8404
  _self.mouseDownPos = _self.relPos(e);
8208
8405
  _self.mouseButton = e.button;
8209
8406
  if (_self.listeners.mousedown)
8210
- _self.listeners.mousedown(_self.mkParams(e, 'mousedown'));
8407
+ _self.listeners.mousedown(_self.mkParams(e, "mousedown"));
8211
8408
  };
8212
- this.handlers['click'] = (e) => {
8409
+ this.handlers["click"] = (e) => {
8213
8410
  if (_self.listeners.click)
8214
- _self.listeners.click(_self.mkParams(e, 'click'));
8411
+ _self.listeners.click(_self.mkParams(e, "click"));
8215
8412
  };
8216
- this.handlers['wheel'] = (e) => {
8413
+ this.handlers["wheel"] = (e) => {
8217
8414
  if (_self.listeners.wheel)
8218
- _self.listeners.wheel(_self.mkParams(e, 'wheel'));
8415
+ _self.listeners.wheel(_self.mkParams(e, "wheel"));
8219
8416
  };
8220
- this.element.addEventListener('mousemove', this.handlers['mousemove']);
8221
- this.element.addEventListener('mouseup', this.handlers['mouseup']);
8222
- this.element.addEventListener('mousedown', this.handlers['mousedown']);
8223
- this.element.addEventListener('click', this.handlers['click']);
8224
- this.element.addEventListener('wheel', this.handlers['wheel']);
8417
+ this.element.addEventListener("mousemove", this.handlers["mousemove"]);
8418
+ this.element.addEventListener("mouseup", this.handlers["mouseup"]);
8419
+ this.element.addEventListener("mousedown", this.handlers["mousedown"]);
8420
+ this.element.addEventListener("click", this.handlers["click"]);
8421
+ this.element.addEventListener("wheel", this.handlers["wheel"]);
8225
8422
  }
8226
8423
  /**
8227
8424
  * Get relative position from the given MouseEvent.
@@ -8234,11 +8431,8 @@ class MouseHandler {
8234
8431
  * @return {XYCoords} The relative mouse coordinates.
8235
8432
  */
8236
8433
  relPos(e) {
8237
- return { x: e.offsetX,
8238
- y: e.offsetY
8239
- };
8434
+ return { x: e.offsetX, y: e.offsetY };
8240
8435
  }
8241
- ;
8242
8436
  /**
8243
8437
  * Build the extended event params.
8244
8438
  *
@@ -8264,8 +8458,8 @@ class MouseHandler {
8264
8458
  rightButton: this.mouseButton == 2,
8265
8459
  mouseDownPos: this.mouseDownPos,
8266
8460
  draggedFrom: this.mouseDragPos,
8267
- wasDragged: (this.mouseDownPos != null && (this.mouseDownPos.x != rel.x || this.mouseDownPos.y != rel.y)),
8268
- dragAmount: (this.mouseDownPos != null ? { x: rel.x - this.mouseDragPos.x, y: rel.y - this.mouseDragPos.y } : { x: 0, y: 0 })
8461
+ wasDragged: this.mouseDownPos != null && (this.mouseDownPos.x != rel.x || this.mouseDownPos.y != rel.y),
8462
+ dragAmount: this.mouseDownPos != null ? { x: rel.x - this.mouseDragPos.x, y: rel.y - this.mouseDragPos.y } : { x: 0, y: 0 }
8269
8463
  };
8270
8464
  return xEvent;
8271
8465
  }
@@ -8316,14 +8510,13 @@ class MouseHandler {
8316
8510
  */
8317
8511
  drag(callback) {
8318
8512
  if (this.listeners.drag)
8319
- this.throwAlreadyInstalled('drag');
8513
+ this.throwAlreadyInstalled("drag");
8320
8514
  this.listeners.drag = callback;
8321
- this.listenFor('mousedown');
8322
- this.listenFor('mousemove');
8323
- this.listenFor('mouseup');
8515
+ this.listenFor("mousedown");
8516
+ this.listenFor("mousemove");
8517
+ this.listenFor("mouseup");
8324
8518
  return this;
8325
8519
  }
8326
- ;
8327
8520
  /**
8328
8521
  * Installer function to listen for a specific event: mouse-move.
8329
8522
  * Pass your callbacks here.
@@ -8338,12 +8531,11 @@ class MouseHandler {
8338
8531
  */
8339
8532
  move(callback) {
8340
8533
  if (this.listeners.mousemove)
8341
- this.throwAlreadyInstalled('mousemove');
8342
- this.listenFor('mousemove');
8534
+ this.throwAlreadyInstalled("mousemove");
8535
+ this.listenFor("mousemove");
8343
8536
  this.listeners.mousemove = callback;
8344
8537
  return this;
8345
8538
  }
8346
- ;
8347
8539
  /**
8348
8540
  * Installer function to listen for a specific event: mouse-up.
8349
8541
  * Pass your callbacks here.
@@ -8358,12 +8550,11 @@ class MouseHandler {
8358
8550
  */
8359
8551
  up(callback) {
8360
8552
  if (this.listeners.mouseup)
8361
- this.throwAlreadyInstalled('mouseup');
8362
- this.listenFor('mouseup');
8553
+ this.throwAlreadyInstalled("mouseup");
8554
+ this.listenFor("mouseup");
8363
8555
  this.listeners.mouseup = callback;
8364
8556
  return this;
8365
8557
  }
8366
- ;
8367
8558
  /**
8368
8559
  * Installer function to listen for a specific event: mouse-down.
8369
8560
  * Pass your callbacks here.
@@ -8378,12 +8569,11 @@ class MouseHandler {
8378
8569
  */
8379
8570
  down(callback) {
8380
8571
  if (this.listeners.mousedown)
8381
- this.throwAlreadyInstalled('mousedown');
8382
- this.listenFor('mousedown');
8572
+ this.throwAlreadyInstalled("mousedown");
8573
+ this.listenFor("mousedown");
8383
8574
  this.listeners.mousedown = callback;
8384
8575
  return this;
8385
8576
  }
8386
- ;
8387
8577
  /**
8388
8578
  * Installer function to listen for a specific event: mouse-click.
8389
8579
  * Pass your callbacks here.
@@ -8398,12 +8588,11 @@ class MouseHandler {
8398
8588
  */
8399
8589
  click(callback) {
8400
8590
  if (this.listeners.click)
8401
- this.throwAlreadyInstalled('click');
8402
- this.listenFor('click');
8591
+ this.throwAlreadyInstalled("click");
8592
+ this.listenFor("click");
8403
8593
  this.listeners.click = callback;
8404
8594
  return this;
8405
8595
  }
8406
- ;
8407
8596
  /**
8408
8597
  * Installer function to listen for a specific event: mouse-wheel.
8409
8598
  * Pass your callbacks here.
@@ -8418,12 +8607,11 @@ class MouseHandler {
8418
8607
  */
8419
8608
  wheel(callback) {
8420
8609
  if (this.listeners.wheel)
8421
- this.throwAlreadyInstalled('wheel');
8422
- this.listenFor('wheel');
8610
+ this.throwAlreadyInstalled("wheel");
8611
+ this.listenFor("wheel");
8423
8612
  this.listeners.wheel = callback;
8424
8613
  return this;
8425
8614
  }
8426
- ;
8427
8615
  /**
8428
8616
  * An internal function to throw events.
8429
8617
  *
@@ -8437,7 +8625,6 @@ class MouseHandler {
8437
8625
  throwAlreadyInstalled(name) {
8438
8626
  throw `This MouseHandler already has a '${name}' callback. To keep the code simple there is only room for one.`;
8439
8627
  }
8440
- ;
8441
8628
  /**
8442
8629
  * Call this when your work is done.
8443
8630
  *
@@ -8450,16 +8637,16 @@ class MouseHandler {
8450
8637
  * @return {void}
8451
8638
  */
8452
8639
  destroy() {
8453
- this.unlistenFor('mousedown');
8454
- this.unlistenFor('mousemove');
8455
- this.unlistenFor('moseup');
8456
- this.unlistenFor('click');
8457
- this.unlistenFor('wheel');
8458
- this.element.removeEventListener('mousemove', this.handlers['mousemove']);
8459
- this.element.removeEventListener('mouseup', this.handlers['mousedown']);
8460
- this.element.removeEventListener('mousedown', this.handlers['mousedown']);
8461
- this.element.removeEventListener('click', this.handlers['click']);
8462
- this.element.removeEventListener('wheel', this.handlers['wheel']);
8640
+ this.unlistenFor("mousedown");
8641
+ this.unlistenFor("mousemove");
8642
+ this.unlistenFor("moseup");
8643
+ this.unlistenFor("click");
8644
+ this.unlistenFor("wheel");
8645
+ this.element.removeEventListener("mousemove", this.handlers["mousemove"]);
8646
+ this.element.removeEventListener("mouseup", this.handlers["mousedown"]);
8647
+ this.element.removeEventListener("mousedown", this.handlers["mousedown"]);
8648
+ this.element.removeEventListener("click", this.handlers["click"]);
8649
+ this.element.removeEventListener("wheel", this.handlers["wheel"]);
8463
8650
  }
8464
8651
  }
8465
8652
 
@@ -8469,7 +8656,9 @@ class MouseHandler {
8469
8656
  * @modified 2019-03-23 Added JSDoc tags.
8470
8657
  * @modified 2020-03-25 Ported this class from vanilla-JS to Typescript.
8471
8658
  * @modified 2021-01-20 Added UID.
8472
- * @version 1.1.0
8659
+ * @modified 2022-02-02 Added the `destroy` method.
8660
+ * @modified 2022-02-02 Cleared the `PBImage.toSVGString` function (deprecated). Use `drawutilssvg` instead.
8661
+ * @version 1.2.0
8473
8662
  *
8474
8663
  * @file PBImage
8475
8664
  * @fileoverview As native Image objects have only a position and with
@@ -8504,28 +8693,23 @@ class PBImage {
8504
8693
  this.upperLeft = upperLeft;
8505
8694
  this.lowerRight = lowerRight;
8506
8695
  }
8507
- ;
8508
8696
  /**
8509
- * Convert this vertex to SVG code.
8510
- *
8511
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
8512
- * @method toSVGString
8513
- * @param {object=} options - An optional set of options, like 'className'.
8514
- * @return {string} A string representing the SVG code for this vertex.
8515
- * @instance
8516
- * @memberof PBImage
8517
- **/
8518
- toSVGString(options) {
8519
- console.warn("PBImage is not yet SVG serializable. Returning empty SVG string.");
8520
- return "";
8697
+ * This function should invalidate any installed listeners and invalidate this object.
8698
+ * After calling this function the object might not hold valid data any more and
8699
+ * should not be used.
8700
+ */
8701
+ destroy() {
8702
+ this.upperLeft.destroy();
8703
+ this.lowerRight.destroy();
8704
+ this.isDestroyed = true;
8521
8705
  }
8522
- ;
8523
8706
  }
8524
8707
 
8525
8708
  /**
8526
8709
  * @author Ikaros Kappler
8527
8710
  * @date 2021-11-16
8528
- * @version 1.0.0
8711
+ * @modified 2022-02-02 Added the `destroy` method.
8712
+ * @version 1.1.0
8529
8713
  **/
8530
8714
  /**
8531
8715
  * @classdesc A simple text element: position, fontSize, fontFamily, color, textAlign, lineHeight and rotation.
@@ -8566,18 +8750,13 @@ class PBText {
8566
8750
  this.rotation = options.rotation;
8567
8751
  }
8568
8752
  /**
8569
- * Create an SVG representation of this circle.
8570
- *
8571
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
8572
- * @method toSVGString
8573
- * @param {object=} options - An optional set of options, like 'className'.
8574
- * @return {string} A string representing the SVG code for this vertex.
8575
- * @instance
8576
- * @memberof Circle
8753
+ * This function should invalidate any installed listeners and invalidate this object.
8754
+ * After calling this function the object might not hold valid data any more and
8755
+ * should not be used.
8577
8756
  */
8578
- toSVGString(options) {
8579
- console.warn("[PBText.toSVGString()] This function is not implemented as it defines a deprecated method. Use the 'drawutilssvg.text()' method instead.");
8580
- return "";
8757
+ destroy() {
8758
+ this.anchor.destroy();
8759
+ this.isDestroyed = true;
8581
8760
  }
8582
8761
  } // END class
8583
8762
 
@@ -8982,7 +9161,9 @@ class AlloyFinger {
8982
9161
  * @modified 2021-03-10 Added the `toCubicBezier` method.
8983
9162
  * @modified 2021-03-15 Added `VEllipse.quarterSegmentCount` and `VEllipse.scale` functions.
8984
9163
  * @modified 2021-03-19 Added the `VEllipse.rotate` function.
8985
- * @version 1.2.2
9164
+ * @modified 2022-02-02 Added the `destroy` method.
9165
+ * @modified 2022-02-02 Cleared the `VEllipse.toSVGString` function (deprecated). Use `drawutilssvg` instead.
9166
+ * @version 1.3.0
8986
9167
  *
8987
9168
  * @file VEllipse
8988
9169
  * @fileoverview Ellipses with a center and an x- and a y-axis (stored as a vertex).
@@ -9301,24 +9482,14 @@ class VEllipse {
9301
9482
  return curves;
9302
9483
  }
9303
9484
  /**
9304
- * Create an SVG representation of this ellipse.
9305
- *
9306
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
9307
- * @param {object} options { className?:string }
9308
- * @return string The SVG string
9485
+ * This function should invalidate any installed listeners and invalidate this object.
9486
+ * After calling this function the object might not hold valid data any more and
9487
+ * should not be used.
9309
9488
  */
9310
- toSVGString(options) {
9311
- options = options || {};
9312
- var buffer = [];
9313
- buffer.push("<ellipse");
9314
- if (options.className)
9315
- buffer.push(' class="' + options.className + '"');
9316
- buffer.push(' cx="' + this.center.x + '"');
9317
- buffer.push(' cy="' + this.center.y + '"');
9318
- buffer.push(' rx="' + this.axis.x + '"');
9319
- buffer.push(' ry="' + this.axis.y + '"');
9320
- buffer.push(" />");
9321
- return buffer.join("");
9489
+ destroy() {
9490
+ this.center.destroy();
9491
+ this.axis.destroy();
9492
+ this.isDestroyed = true;
9322
9493
  }
9323
9494
  }
9324
9495
  /**
@@ -9385,7 +9556,8 @@ VEllipse.utils = {
9385
9556
  *
9386
9557
  * @author Ikaros Kappler
9387
9558
  * @date 2021-02-26
9388
- * @version 1.0.0
9559
+ * @modified 2022-02-02 Added the `destroy` method.
9560
+ * @version 1.1.0
9389
9561
  */
9390
9562
  /**
9391
9563
  * @classdesc A class for elliptic sectors.
@@ -9471,6 +9643,15 @@ class VEllipseSector {
9471
9643
  }
9472
9644
  return curves;
9473
9645
  }
9646
+ /**
9647
+ * This function should invalidate any installed listeners and invalidate this object.
9648
+ * After calling this function the object might not hold valid data any more and
9649
+ * should not be used.
9650
+ */
9651
+ destroy() {
9652
+ this.ellipse.destroy();
9653
+ this.isDestroyed = true;
9654
+ }
9474
9655
  }
9475
9656
  VEllipseSector.ellipseSectorUtils = {
9476
9657
  /**
@@ -9711,7 +9892,8 @@ VEllipseSector.ellipseSectorUtils = {
9711
9892
  * @modified 2021-03-29 Clearing `currentClassName` and `currentId` after drawing each drawable.
9712
9893
  * @modified 2021-04-25 Extending `remove` to accept arrays of drawables.
9713
9894
  * @modified 2021-11-16 Adding the `PBText` drawable.
9714
- * @version 1.15.0
9895
+ * @modified 2022-08-01 Added `title` to the params.
9896
+ * @version 1.15.1
9715
9897
  *
9716
9898
  * @file PlotBoilerplate
9717
9899
  * @fileoverview The main class.
@@ -9804,6 +9986,7 @@ class PlotBoilerplate {
9804
9986
  * @param {boolean=} [config.enableGL=false] - Indicates if the application should use the experimental WebGL features (not recommended).
9805
9987
  * @param {boolean=} [config.enableSVGExport=true] - Indicates if the SVG export should be enabled (default is true).
9806
9988
  * Note that changes from the postDraw hook might not be visible in the export.
9989
+ * @param {string=} [config.title=null] - Specify any hover tile here. It will be attached as a `title` attribute to the most elevated element.
9807
9990
  */
9808
9991
  constructor(config) {
9809
9992
  /**
@@ -10019,6 +10202,11 @@ class PlotBoilerplate {
10019
10202
  else {
10020
10203
  throw "Element is neither a canvas nor an svg element.";
10021
10204
  }
10205
+ // At this point the event cacher element is deinfed and located at highest elevation.
10206
+ // Set `title` attribut?
10207
+ if (config.title) {
10208
+ this.eventCatcher.setAttribute("title", config.title);
10209
+ }
10022
10210
  this.draw.scale.set(this.config.scaleX, this.config.scaleY);
10023
10211
  this.fill.scale.set(this.config.scaleX, this.config.scaleY);
10024
10212
  this.vertices = [];
@@ -10321,7 +10509,7 @@ class PlotBoilerplate {
10321
10509
  }
10322
10510
  }
10323
10511
  for (var i = 0; i < this.drawables.length; i++) {
10324
- if (this.drawables[i] === drawable) {
10512
+ if (this.drawables[i] === drawable || this.drawables[i].uid === drawable.uid) {
10325
10513
  this.drawables.splice(i, 1);
10326
10514
  if (removeWithVertices) {
10327
10515
  // Check if some listeners need to be removed
@@ -11701,100 +11889,5 @@ PlotBoilerplate.utils = {
11701
11889
  }
11702
11890
  }; // END utils
11703
11891
 
11704
- /**
11705
- * Todos:
11706
- * + use a Drawable interface
11707
- * + use a SVGSerializable interface
11708
- *
11709
- * @require Vertex
11710
- *
11711
- * @deprecated THIS CLASS IS DEPRECATED. Please use the new `drawutilssvg` instead.
11712
- *
11713
- * @author Ikaros Kappler
11714
- * @date 2018-12-04
11715
- * @modified 2019-11-07 Added the 'Triangle' style class.
11716
- * @modified 2019-11-13 Added the <?xml ...?> tag.
11717
- * @modified 2020-03-25 Ported this class from vanilla-JS to Typescript.
11718
- * @modified 2020-12-17 Added Circle and CircleSection style classes.
11719
- * @modified 2021-01-26 DEPRECATION
11720
- * @version 1.0.5
11721
- **/
11722
- /**
11723
- * @classdesc A default SVG builder.
11724
- *
11725
- * @requires SVGSerializable
11726
- * @requires Vertex
11727
- */
11728
- class SVGBuilder {
11729
- /**
11730
- * @constructor
11731
- **/
11732
- constructor() {
11733
- console.warn("THIS CLASS IS DEPRECATED. Please use the new 'drawutilssvg' instead.");
11734
- }
11735
- ;
11736
- /**
11737
- * Builds the SVG code from the given list of drawables.
11738
- *
11739
- * @param {object[]} drawables - The drawable elements (should implement Drawable) to be converted (each must have a toSVGString-function).
11740
- * @param {object} options - { canvasSize, zoom, offset }
11741
- * @return {string}
11742
- **/
11743
- build(drawables, options) {
11744
- var nl = '\n';
11745
- var indent = ' ';
11746
- var buffer = [];
11747
- buffer.push('<?xml version="1.0" encoding="UTF-8"?>' + nl);
11748
- buffer.push('<svg width="' + options.canvasSize.width + '" height="' + options.canvasSize.height + '"');
11749
- buffer.push(' viewBox="');
11750
- buffer.push('0');
11751
- buffer.push(' ');
11752
- buffer.push('0');
11753
- buffer.push(' ');
11754
- buffer.push(options.canvasSize.width.toString());
11755
- buffer.push(' ');
11756
- buffer.push(options.canvasSize.height.toString());
11757
- buffer.push('"');
11758
- buffer.push(' xmlns="http://www.w3.org/2000/svg">' + nl);
11759
- buffer.push(indent + '<defs>' + nl);
11760
- buffer.push(indent + '<style>' + nl);
11761
- buffer.push(indent + indent + ' .Vertex { fill : blue; stroke : none; } ' + nl);
11762
- buffer.push(indent + indent + ' .Triangle { fill : none; stroke : turquoise; stroke-width : 1px; } ' + nl);
11763
- buffer.push(indent + indent + ' .Polygon { fill : none; stroke : green; stroke-width : 2px; } ' + nl);
11764
- buffer.push(indent + indent + ' .BezierPath { fill : none; stroke : blue; stroke-width : 2px; } ' + nl);
11765
- buffer.push(indent + indent + ' .VEllipse { fill : none; stroke : black; stroke-width : 1px; } ' + nl);
11766
- buffer.push(indent + indent + ' .Line { fill : none; stroke : purple; stroke-width : 1px; } ' + nl);
11767
- buffer.push(indent + indent + ' .Circle { fill : none; stroke : purple; stroke-width : 1px; } ' + nl);
11768
- buffer.push(indent + indent + ' .CircleSector { fill : none; stroke : purple; stroke-width : 1px; } ' + nl);
11769
- buffer.push(indent + '</style>' + nl);
11770
- buffer.push(indent + '</defs>' + nl);
11771
- buffer.push(indent + '<g class="main-g"');
11772
- if (options.zoom || options.offset) {
11773
- buffer.push(' transform="');
11774
- if (options.zoom)
11775
- buffer.push('scale(' + options.zoom.x + ',' + options.zoom.y + ')');
11776
- if (options.offset)
11777
- buffer.push(' translate(' + options.offset.x + ',' + options.offset.y + ')');
11778
- buffer.push('"');
11779
- }
11780
- buffer.push('>' + nl);
11781
- for (var i in drawables) {
11782
- var d = drawables[i];
11783
- if (typeof d.toSVGString == 'function') {
11784
- buffer.push(indent + indent);
11785
- buffer.push(d.toSVGString({ 'className': d.className }));
11786
- buffer.push(nl);
11787
- }
11788
- else {
11789
- console.warn('Unrecognized drawable type has no toSVGString()-function. Ignoring: ' + d.className);
11790
- }
11791
- }
11792
- buffer.push(indent + '</g>' + nl);
11793
- buffer.push('</svg>' + nl);
11794
- return buffer.join('');
11795
- }
11796
- ;
11797
- }
11798
-
11799
- 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 };
11892
+ 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 };
11800
11893
  //# sourceMappingURL=index.esm.js.map