plotboilerplate 1.12.10 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/README.md +5 -1
  2. package/changelog.md +50 -0
  3. package/dist/index.esm.js +999 -510
  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 +1013 -509
  10. package/dist/plotboilerplate.min.js +1 -1
  11. package/package.json +1 -1
  12. package/src/cjs/BezierPath.d.ts +45 -2
  13. package/src/cjs/BezierPath.js +114 -18
  14. package/src/cjs/BezierPath.js.map +1 -1
  15. package/src/cjs/Circle.d.ts +25 -10
  16. package/src/cjs/Circle.js +38 -33
  17. package/src/cjs/Circle.js.map +1 -1
  18. package/src/cjs/CircleSector.d.ts +27 -13
  19. package/src/cjs/CircleSector.js +38 -23
  20. package/src/cjs/CircleSector.js.map +1 -1
  21. package/src/cjs/CubicBezierCurve.d.ts +17 -1
  22. package/src/cjs/CubicBezierCurve.js +78 -79
  23. package/src/cjs/CubicBezierCurve.js.map +1 -1
  24. package/src/cjs/KeyHandler.d.ts +10 -3
  25. package/src/cjs/KeyHandler.js +28 -23
  26. package/src/cjs/KeyHandler.js.map +1 -1
  27. package/src/cjs/Line.d.ts +2 -1
  28. package/src/cjs/Line.js +19 -18
  29. package/src/cjs/Line.js.map +1 -1
  30. package/src/cjs/MouseHandler.js +43 -53
  31. package/src/cjs/MouseHandler.js.map +1 -1
  32. package/src/cjs/PBImage.d.ts +16 -1
  33. package/src/cjs/PBImage.js +13 -3
  34. package/src/cjs/PBImage.js.map +1 -1
  35. package/src/cjs/PBText.d.ts +130 -0
  36. package/src/cjs/PBText.js +76 -0
  37. package/src/cjs/PBText.js.map +1 -0
  38. package/src/cjs/PlotBoilerplate.d.ts +2 -1
  39. package/src/cjs/PlotBoilerplate.js +44 -16
  40. package/src/cjs/PlotBoilerplate.js.map +1 -1
  41. package/src/cjs/Polygon.d.ts +37 -1
  42. package/src/cjs/Polygon.js +131 -54
  43. package/src/cjs/Polygon.js.map +1 -1
  44. package/src/cjs/Triangle.d.ts +16 -1
  45. package/src/cjs/Triangle.js +50 -54
  46. package/src/cjs/Triangle.js.map +1 -1
  47. package/src/cjs/VEllipse.d.ts +16 -1
  48. package/src/cjs/VEllipse.js +25 -12
  49. package/src/cjs/VEllipse.js.map +1 -1
  50. package/src/cjs/VEllipseSector.d.ts +15 -1
  51. package/src/cjs/VEllipseSector.js +11 -1
  52. package/src/cjs/VEllipseSector.js.map +1 -1
  53. package/src/cjs/Vector.d.ts +3 -1
  54. package/src/cjs/Vector.js +32 -36
  55. package/src/cjs/Vector.js.map +1 -1
  56. package/src/cjs/VertTuple.d.ts +15 -1
  57. package/src/cjs/VertTuple.js +14 -19
  58. package/src/cjs/VertTuple.js.map +1 -1
  59. package/src/cjs/Vertex.d.ts +66 -4
  60. package/src/cjs/Vertex.js +99 -17
  61. package/src/cjs/Vertex.js.map +1 -1
  62. package/src/cjs/VertexListeners.d.ts +12 -8
  63. package/src/cjs/VertexListeners.js +18 -25
  64. package/src/cjs/VertexListeners.js.map +1 -1
  65. package/src/cjs/draw.d.ts +30 -2
  66. package/src/cjs/draw.js +51 -6
  67. package/src/cjs/draw.js.map +1 -1
  68. package/src/cjs/drawgl.d.ts +29 -2
  69. package/src/cjs/drawgl.js +21 -4
  70. package/src/cjs/drawgl.js.map +1 -1
  71. package/src/cjs/drawutilssvg.d.ts +25 -7
  72. package/src/cjs/drawutilssvg.js +62 -14
  73. package/src/cjs/drawutilssvg.js.map +1 -1
  74. package/src/cjs/entry.js +1 -0
  75. package/src/cjs/index.d.ts +1 -0
  76. package/src/cjs/index.js +1 -0
  77. package/src/cjs/index.js.map +1 -1
  78. package/src/cjs/interfaces/DrawLib.d.ts +27 -6
  79. package/src/cjs/interfaces/DrawLib.js +3 -0
  80. package/src/cjs/interfaces/DrawLib.js.map +1 -1
  81. package/src/cjs/interfaces/core.d.ts +9 -1
  82. package/src/cjs/interfaces/core.js +1 -0
  83. package/src/cjs/interfaces/core.js.map +1 -1
  84. package/src/cjs/utils/creategui.js +1 -1
  85. package/src/cjs/utils/findInVertexArray.d.ts +19 -0
  86. package/src/cjs/utils/findInVertexArray.js +29 -0
  87. package/src/cjs/utils/findInVertexArray.js.map +1 -0
  88. package/src/cjs/utils/helpers/BezierPathInteractionHelper.d.ts +15 -0
  89. package/src/cjs/utils/helpers/BezierPathInteractionHelper.js +55 -28
  90. package/src/cjs/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
  91. package/src/cjs/utils/io/DndFileHandler.d.ts +63 -0
  92. package/src/cjs/utils/io/DndFileHandler.js +112 -0
  93. package/src/cjs/utils/io/DndFileHandler.js.map +1 -0
  94. package/src/cjs/utils/io/FileDrop.d.ts +98 -0
  95. package/src/cjs/utils/io/FileDrop.js +142 -0
  96. package/src/cjs/utils/io/FileDrop.js.map +1 -0
  97. package/src/esm/BezierPath.d.ts +45 -2
  98. package/src/esm/BezierPath.js +114 -18
  99. package/src/esm/BezierPath.js.map +1 -1
  100. package/src/esm/Circle.d.ts +25 -10
  101. package/src/esm/Circle.js +38 -33
  102. package/src/esm/Circle.js.map +1 -1
  103. package/src/esm/CircleSector.d.ts +27 -13
  104. package/src/esm/CircleSector.js +38 -23
  105. package/src/esm/CircleSector.js.map +1 -1
  106. package/src/esm/CubicBezierCurve.d.ts +17 -1
  107. package/src/esm/CubicBezierCurve.js +78 -79
  108. package/src/esm/CubicBezierCurve.js.map +1 -1
  109. package/src/esm/KeyHandler.d.ts +10 -3
  110. package/src/esm/KeyHandler.js +28 -23
  111. package/src/esm/KeyHandler.js.map +1 -1
  112. package/src/esm/Line.d.ts +2 -1
  113. package/src/esm/Line.js +19 -18
  114. package/src/esm/Line.js.map +1 -1
  115. package/src/esm/MouseHandler.js +43 -53
  116. package/src/esm/MouseHandler.js.map +1 -1
  117. package/src/esm/PBImage.d.ts +16 -1
  118. package/src/esm/PBImage.js +13 -3
  119. package/src/esm/PBImage.js.map +1 -1
  120. package/src/esm/PBText.d.ts +130 -0
  121. package/src/esm/PBText.js +71 -0
  122. package/src/esm/PBText.js.map +1 -0
  123. package/src/esm/PlotBoilerplate.d.ts +2 -1
  124. package/src/esm/PlotBoilerplate.js +44 -16
  125. package/src/esm/PlotBoilerplate.js.map +1 -1
  126. package/src/esm/Polygon.d.ts +37 -1
  127. package/src/esm/Polygon.js +131 -54
  128. package/src/esm/Polygon.js.map +1 -1
  129. package/src/esm/Triangle.d.ts +16 -1
  130. package/src/esm/Triangle.js +50 -54
  131. package/src/esm/Triangle.js.map +1 -1
  132. package/src/esm/VEllipse.d.ts +16 -1
  133. package/src/esm/VEllipse.js +25 -12
  134. package/src/esm/VEllipse.js.map +1 -1
  135. package/src/esm/VEllipseSector.d.ts +15 -1
  136. package/src/esm/VEllipseSector.js +11 -1
  137. package/src/esm/VEllipseSector.js.map +1 -1
  138. package/src/esm/Vector.d.ts +3 -1
  139. package/src/esm/Vector.js +32 -36
  140. package/src/esm/Vector.js.map +1 -1
  141. package/src/esm/VertTuple.d.ts +15 -1
  142. package/src/esm/VertTuple.js +14 -19
  143. package/src/esm/VertTuple.js.map +1 -1
  144. package/src/esm/Vertex.d.ts +66 -4
  145. package/src/esm/Vertex.js +99 -17
  146. package/src/esm/Vertex.js.map +1 -1
  147. package/src/esm/VertexListeners.d.ts +12 -8
  148. package/src/esm/VertexListeners.js +18 -25
  149. package/src/esm/VertexListeners.js.map +1 -1
  150. package/src/esm/draw.d.ts +30 -2
  151. package/src/esm/draw.js +51 -6
  152. package/src/esm/draw.js.map +1 -1
  153. package/src/esm/drawgl.d.ts +29 -2
  154. package/src/esm/drawgl.js +21 -4
  155. package/src/esm/drawgl.js.map +1 -1
  156. package/src/esm/drawutilssvg.d.ts +25 -7
  157. package/src/esm/drawutilssvg.js +62 -14
  158. package/src/esm/drawutilssvg.js.map +1 -1
  159. package/src/esm/entry.js +1 -0
  160. package/src/esm/index.d.ts +1 -0
  161. package/src/esm/index.js +1 -0
  162. package/src/esm/index.js.map +1 -1
  163. package/src/esm/interfaces/DrawLib.d.ts +27 -6
  164. package/src/esm/interfaces/DrawLib.js +3 -0
  165. package/src/esm/interfaces/DrawLib.js.map +1 -1
  166. package/src/esm/interfaces/core.d.ts +9 -1
  167. package/src/esm/interfaces/core.js +1 -0
  168. package/src/esm/interfaces/core.js.map +1 -1
  169. package/src/esm/utils/findInVertexArray.d.ts +19 -0
  170. package/src/esm/utils/findInVertexArray.js +25 -0
  171. package/src/esm/utils/findInVertexArray.js.map +1 -0
  172. package/src/esm/utils/helpers/BezierPathInteractionHelper.d.ts +15 -0
  173. package/src/esm/utils/helpers/BezierPathInteractionHelper.js +54 -28
  174. package/src/esm/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
  175. package/src/esm/utils/io/DndFileHandler.d.ts +63 -0
  176. package/src/esm/utils/io/DndFileHandler.js +106 -0
  177. package/src/esm/utils/io/DndFileHandler.js.map +1 -0
  178. package/src/esm/utils/io/FileDrop.d.ts +98 -0
  179. package/src/esm/utils/io/FileDrop.js +136 -0
  180. package/src/esm/utils/io/FileDrop.js.map +1 -0
  181. package/src/ts/BezierPath.ts +133 -16
  182. package/src/ts/Circle.ts +213 -200
  183. package/src/ts/CircleSector.ts +171 -141
  184. package/src/ts/CubicBezierCurve.ts +777 -810
  185. package/src/ts/KeyHandler.ts +221 -212
  186. package/src/ts/Line.ts +77 -80
  187. package/src/ts/MouseHandler.ts +356 -368
  188. package/src/ts/PBImage.ts +81 -68
  189. package/src/ts/PBText.ts +166 -0
  190. package/src/ts/PlotBoilerplate.ts +48 -20
  191. package/src/ts/Polygon.ts +519 -451
  192. package/src/ts/Triangle.ts +484 -489
  193. package/src/ts/VEllipse.ts +36 -11
  194. package/src/ts/VEllipseSector.ts +20 -1
  195. package/src/ts/Vector.ts +164 -160
  196. package/src/ts/VertTuple.ts +333 -338
  197. package/src/ts/Vertex.ts +117 -16
  198. package/src/ts/VertexListeners.ts +248 -266
  199. package/src/ts/draw.ts +71 -8
  200. package/src/ts/drawgl.ts +48 -8
  201. package/src/ts/drawutilssvg.ts +94 -17
  202. package/src/ts/index.ts +1 -0
  203. package/src/ts/interfaces/DrawLib.ts +30 -4
  204. package/src/ts/interfaces/core.ts +9 -0
  205. package/src/ts/utils/findInVertexArray.ts +28 -0
  206. package/src/ts/utils/helpers/BezierPathInteractionHelper.ts +61 -30
  207. package/src/ts/utils/io/FileDrop.ts +178 -0
  208. package/dist/plotboilerplate.browser.min.js.LICENSE.txt +0 -8
  209. package/src/ts/utils/algorithms/clearPolygonDuplicateVertices.ts~ +0 -5
  210. package/src/ts/utils/algorithms/findPolygonSelfIntersections.ts~ +0 -45
  211. package/src/ts/utils/algorithms/sh-tmp.ts~ +0 -59
  212. package/src/ts/utils/algorithms/splitPolygonToNonIntersecting.ts~ +0 -113
  213. package/src/ts/utils/algorithms/sutherlandHodgman.ts~ +0 -88
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
  /**
@@ -358,7 +351,13 @@ class VertexListeners {
358
351
  * @modified 2020-05-26 Added functions addX(number) and addY(number).
359
352
  * @modified 2020-10-30 Changed the warnings in `sub(...)` and `add(...)` into real errors.
360
353
  * @modified 2021-03-01 Changed the second param `center` in the `rotate` function from Vertex to XYCoords.
361
- * @version 2.4.2
354
+ * @modified 2021-12-01 Changed the type of param of `scale` to XYCoords.
355
+ * @modified 2021-12-01 Added function `scaleXY` for non uniform scaling.
356
+ * @modified 2021-12-17 Added the functions `lerp` and `lerpAbs` for linear interpolations.
357
+ * @modified 2022-01-31 Added `Vertex.utils.arrayToJSON`.
358
+ * @modified 2022-02-02 Added the `destroy` method.
359
+ * @modified 2022-02-02 Cleared the `Vertex.toSVGString` function (deprecated). Use `drawutilssvg` instead.
360
+ * @version 2.7.0
362
361
  *
363
362
  * @file Vertex
364
363
  * @public
@@ -699,20 +698,72 @@ class Vertex {
699
698
  }
700
699
  /**
701
700
  * This is a vector-like behavior and 'scales' this vertex
702
- * towards/from a given center.
701
+ * towards/from a given center by one uniform scale factor.
703
702
  *
704
703
  * @method scale
705
704
  * @param {number} factor - The factor to 'scale' this vertex; 1.0 means no change.
706
- * @param {Vertex=} center - The origin of scaling; default is (0,0).
705
+ * @param {XYCoords=} center - The origin of scaling; default is (0,0).
707
706
  * @return {Vertex} this
708
707
  * @instance
709
708
  * @memberof Vertex
710
709
  **/
711
710
  scale(factor, center) {
712
- if (!center || typeof center === "undefined")
713
- center = new Vertex(0, 0);
714
- this.x = center.x + (this.x - center.x) * factor;
715
- this.y = center.y + (this.y - center.y) * factor;
711
+ return this.scaleXY({ x: factor, y: factor }, center);
712
+ }
713
+ /**
714
+ * Perform a linear interpolation towards the given target vertex.
715
+ * The amount value `t` is relative, `t=0.0` means no change, `t=1.0`
716
+ * means this point will be moved to the exact target position.
717
+ *
718
+ * `t=0.5` will move this point to the middle of the connecting
719
+ * linear segment.
720
+ *
721
+ * @param {XYCoords} target - The target position to lerp this vertex to.
722
+ * @param {number} t - The relative amount, usually in [0..1], but other values will work, too.
723
+ * @returns
724
+ */
725
+ lerp(target, t) {
726
+ var diff = this.difference(target);
727
+ // return new Vertex(this.x + diff.x * t, this.y + diff.y * t);
728
+ this.x += diff.x * t;
729
+ this.y += diff.y * t;
730
+ return this;
731
+ }
732
+ /**
733
+ * Perform a linear interpolation towards the given target vertex (absolute variant).
734
+ * The amount value `t` is absolute, which means the lerp amount is a direct distance
735
+ * value. This point will have move the amount of the passed distance `u`.
736
+ *
737
+ * @param {XYCoords} target - The target position to lerp this vertex to.
738
+ * @param {number} t - The absolute move amount to use to lerping.
739
+ * @returns
740
+ */
741
+ lerpAbs(target, u) {
742
+ var dist = this.distance(target);
743
+ var diff = this.difference(target);
744
+ var step = { x: diff.x / dist, y: diff.y / dist };
745
+ // return new Vertex(this.x + step.x * u, this.y + step.y * u);
746
+ this.x += step.x * u;
747
+ this.y += step.y * u;
748
+ return this;
749
+ }
750
+ /**
751
+ * This is a vector-like behavior and 'scales' this vertex
752
+ * towards/from a given center by two independent x- and y- scale factors.
753
+ *
754
+ * @method scale
755
+ * @param {number} factor - The factor to 'scale' this vertex; 1.0 means no change.
756
+ * @param {XYCoords=} center - The origin of scaling; default is (0,0).
757
+ * @return {Vertex} this
758
+ * @instance
759
+ * @memberof Vertex
760
+ **/
761
+ scaleXY(factors, center) {
762
+ if (!center || typeof center === "undefined") {
763
+ center = { x: 0, y: 0 };
764
+ }
765
+ this.x = center.x + (this.x - center.x) * factors.x;
766
+ this.y = center.y + (this.y - center.y) * factors.y;
716
767
  return this;
717
768
  }
718
769
  /**
@@ -801,20 +852,31 @@ class Vertex {
801
852
  * @return {string} A string representing the SVG code for this vertex.
802
853
  * @instance
803
854
  * @memberof Vertex
855
+ * @deprecated
804
856
  **/
805
857
  toSVGString(options) {
806
- options = options || {};
807
- var buffer = [];
808
- buffer.push("<circle");
809
- if (options.className)
810
- buffer.push(' class="' + options.className + '"');
811
- buffer.push(' cx="' + this.x + '"');
812
- buffer.push(' cy="' + this.y + '"');
813
- buffer.push(' r="2"');
814
- buffer.push(" />");
815
- return buffer.join("");
858
+ // options = options || {};
859
+ // var buffer = [];
860
+ // buffer.push("<circle");
861
+ // if (options.className) buffer.push(' class="' + options.className + '"');
862
+ // buffer.push(' cx="' + this.x + '"');
863
+ // buffer.push(' cy="' + this.y + '"');
864
+ // buffer.push(' r="2"');
865
+ // buffer.push(" />");
866
+ // return buffer.join("");
867
+ console.warn("[Deprecation] Warning: the Vertex.toSVGString method is deprecated and does not return and valid SVG data any more. Please use `drawutilssvg` instead.");
868
+ return "";
816
869
  }
817
870
  // END Vertex
871
+ /**
872
+ * This function should invalidate any installed listeners and invalidate this object.
873
+ * After calling this function the object might not hold valid data any more and
874
+ * should not be used.
875
+ */
876
+ destroy() {
877
+ this.listeners.removeAllListeners();
878
+ this.isDestroyed = true;
879
+ }
818
880
  /**
819
881
  * Create a new random vertex inside the given viewport.
820
882
  *
@@ -869,6 +931,19 @@ Vertex.utils = {
869
931
  vertices.push(new Vertex(zB.x * scaleX, zB.y * scaleY));
870
932
  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)));
871
933
  return vertices;
934
+ },
935
+ /**
936
+ * Convert the given vertices (array) to a JSON string.
937
+ *
938
+ * @param {number?} precision - (optional) The numeric precision to be used (number of precision digits).
939
+ * @returns {string}
940
+ */
941
+ arrayToJSON(vertices, precision) {
942
+ return JSON.stringify(vertices.map(function (vert) {
943
+ return typeof precision === undefined
944
+ ? { x: vert.x, y: vert.y }
945
+ : { x: Number(vert.x.toFixed(precision)), y: Number(vert.y.toFixed(precision)) };
946
+ }));
872
947
  }
873
948
  };
874
949
 
@@ -893,7 +968,11 @@ Vertex.utils = {
893
968
  * @modified 2021-01-29 Added the `isClockwise` function.
894
969
  * @modified 2021-01-29 Added the `area` function.
895
970
  * @modified 2021-01-29 Changed the param type for `containsVert` from Vertex to XYCoords.
896
- * @version 1.7.0
971
+ * @modified 2021-12-14 Added the `perimeter()` function.
972
+ * @modified 2021-12-16 Added the `getEvenDistributionPolygon()` function.
973
+ * @modified 2022-02-02 Added the `destroy` method.
974
+ * @modified 2022-02-02 Cleared the `Polygon.toSVGString` function (deprecated). Use `drawutilssvg` instead.
975
+ * @version 1.9.0
897
976
  *
898
977
  * @file Polygon
899
978
  * @public
@@ -924,12 +1003,11 @@ class Polygon {
924
1003
  **/
925
1004
  this.className = "Polygon";
926
1005
  this.uid = UIDGenerator.next();
927
- if (typeof vertices == 'undefined')
1006
+ if (typeof vertices == "undefined")
928
1007
  vertices = [];
929
1008
  this.vertices = vertices;
930
1009
  this.isOpen = isOpen;
931
1010
  }
932
- ;
933
1011
  /**
934
1012
  * Add a vertex to the end of the `vertices` array.
935
1013
  *
@@ -941,7 +1019,6 @@ class Polygon {
941
1019
  addVertex(vert) {
942
1020
  this.vertices.push(vert);
943
1021
  }
944
- ;
945
1022
  /**
946
1023
  * Get the polygon vertex at the given position (index).
947
1024
  *
@@ -964,7 +1041,6 @@ class Polygon {
964
1041
  else
965
1042
  return this.vertices[index % this.vertices.length];
966
1043
  }
967
- ;
968
1044
  /**
969
1045
  * Move the polygon's vertices by the given amount.
970
1046
  *
@@ -980,7 +1056,6 @@ class Polygon {
980
1056
  }
981
1057
  return this;
982
1058
  }
983
- ;
984
1059
  /**
985
1060
  * Check if the given vertex is inside this polygon.<br>
986
1061
  * <br>
@@ -1000,14 +1075,12 @@ class Polygon {
1000
1075
  for (var i = 0, j = this.vertices.length - 1; i < this.vertices.length; j = i++) {
1001
1076
  let xi = this.vertices[i].x, yi = this.vertices[i].y;
1002
1077
  let xj = this.vertices[j].x, yj = this.vertices[j].y;
1003
- var intersect = ((yi > vert.y) != (yj > vert.y))
1004
- && (vert.x < (xj - xi) * (vert.y - yi) / (yj - yi) + xi);
1078
+ var intersect = yi > vert.y != yj > vert.y && vert.x < ((xj - xi) * (vert.y - yi)) / (yj - yi) + xi;
1005
1079
  if (intersect)
1006
1080
  inside = !inside;
1007
1081
  }
1008
1082
  return inside;
1009
1083
  }
1010
- ;
1011
1084
  /**
1012
1085
  * Calculate the area of the given polygon (unsigned).
1013
1086
  *
@@ -1021,7 +1094,6 @@ class Polygon {
1021
1094
  area() {
1022
1095
  return Polygon.utils.area(this.vertices);
1023
1096
  }
1024
- ;
1025
1097
  /**
1026
1098
  * Calulate the signed polyon area by interpreting the polygon as a matrix
1027
1099
  * and calculating its determinant.
@@ -1034,7 +1106,6 @@ class Polygon {
1034
1106
  signedArea() {
1035
1107
  return Polygon.utils.signedArea(this.vertices);
1036
1108
  }
1037
- ;
1038
1109
  /**
1039
1110
  * Get the winding order of this polgon: clockwise or counterclockwise.
1040
1111
  *
@@ -1046,7 +1117,28 @@ class Polygon {
1046
1117
  isClockwise() {
1047
1118
  return Polygon.utils.signedArea(this.vertices) < 0;
1048
1119
  }
1049
- ;
1120
+ /**
1121
+ * Get the perimeter of this polygon.
1122
+ * The perimeter is the absolute length of the outline.
1123
+ *
1124
+ * If this polygon is open then the last segment (connecting the first and the
1125
+ * last vertex) will be skipped.
1126
+ *
1127
+ * @method perimeter
1128
+ * @instance
1129
+ * @memberof Polygon
1130
+ * @return {number}
1131
+ */
1132
+ perimeter() {
1133
+ let length = 0;
1134
+ for (var i = 1; i < this.vertices.length; i++) {
1135
+ length += this.vertices[i - 1].distance(this.vertices[i]);
1136
+ }
1137
+ if (!this.isOpen && this.vertices.length > 1) {
1138
+ length += this.vertices[0].distance(this.vertices[this.vertices.length - 1]);
1139
+ }
1140
+ return length;
1141
+ }
1050
1142
  /**
1051
1143
  * Scale the polygon relative to the given center.
1052
1144
  *
@@ -1059,14 +1151,13 @@ class Polygon {
1059
1151
  **/
1060
1152
  scale(factor, center) {
1061
1153
  for (var i in this.vertices) {
1062
- if (typeof this.vertices[i].scale == 'function')
1154
+ if (typeof this.vertices[i].scale == "function")
1063
1155
  this.vertices[i].scale(factor, center);
1064
1156
  else
1065
- console.log('There seems to be a null vertex!', this.vertices[i]);
1157
+ console.log("There seems to be a null vertex!", this.vertices[i]);
1066
1158
  }
1067
1159
  return this;
1068
1160
  }
1069
- ;
1070
1161
  /**
1071
1162
  * Rotate the polygon around the given center.
1072
1163
  *
@@ -1083,7 +1174,52 @@ class Polygon {
1083
1174
  }
1084
1175
  return this;
1085
1176
  }
1086
- ;
1177
+ /**
1178
+ * Convert this polygon into a new polygon with n evenly distributed vertices.
1179
+ *
1180
+ * @param {number} pointCount - Must not be negative.
1181
+ */
1182
+ getEvenDistributionPolygon(pointCount) {
1183
+ if (pointCount <= 0) {
1184
+ throw new Error("pointCount must be larger than zero; is " + pointCount + ".");
1185
+ }
1186
+ const result = new Polygon([], this.isOpen);
1187
+ if (this.vertices.length === 0) {
1188
+ return result;
1189
+ }
1190
+ // Fetch and add the start point from the source polygon
1191
+ let polygonPoint = new Vertex(this.vertices[0]);
1192
+ result.vertices.push(polygonPoint);
1193
+ if (this.vertices.length === 1) {
1194
+ return result;
1195
+ }
1196
+ const perimeter = this.perimeter();
1197
+ const stepSize = perimeter / pointCount;
1198
+ const n = this.vertices.length;
1199
+ let polygonIndex = 1;
1200
+ let nextPolygonPoint = new Vertex(this.vertices[1]);
1201
+ let segmentLength = polygonPoint.distance(nextPolygonPoint);
1202
+ let loopMax = this.isOpen ? n : n + 1;
1203
+ let curSegmentU = stepSize;
1204
+ var i = 1;
1205
+ while (i < pointCount && polygonIndex < loopMax) {
1206
+ // Check if next eq point is inside this segment
1207
+ if (curSegmentU < segmentLength) {
1208
+ let newPoint = polygonPoint.clone().lerpAbs(nextPolygonPoint, curSegmentU);
1209
+ result.vertices.push(newPoint);
1210
+ curSegmentU += stepSize;
1211
+ i++;
1212
+ }
1213
+ else {
1214
+ polygonIndex++;
1215
+ polygonPoint = nextPolygonPoint;
1216
+ nextPolygonPoint = new Vertex(this.vertices[polygonIndex % n]);
1217
+ curSegmentU = curSegmentU - segmentLength;
1218
+ segmentLength = polygonPoint.distance(nextPolygonPoint);
1219
+ }
1220
+ }
1221
+ return result;
1222
+ }
1087
1223
  /**
1088
1224
  * Get the bounding box (bounds) of this polygon.
1089
1225
  *
@@ -1095,7 +1231,6 @@ class Polygon {
1095
1231
  getBounds() {
1096
1232
  return Bounds.computeFromVertices(this.vertices);
1097
1233
  }
1098
- ;
1099
1234
  /**
1100
1235
  * Convert this polygon to a sequence of quadratic Bézier curves.<br>
1101
1236
  * <br>
@@ -1127,7 +1262,6 @@ class Polygon {
1127
1262
  }
1128
1263
  return qbezier;
1129
1264
  }
1130
- ;
1131
1265
  /**
1132
1266
  * Convert this polygon to a quadratic bezier curve, represented as an SVG data string.
1133
1267
  *
@@ -1140,13 +1274,12 @@ class Polygon {
1140
1274
  var qdata = this.toQuadraticBezierData();
1141
1275
  if (qdata.length == 0)
1142
1276
  return "";
1143
- var buffer = ['M ' + qdata[0].x + ' ' + qdata[0].y];
1277
+ var buffer = ["M " + qdata[0].x + " " + qdata[0].y];
1144
1278
  for (var i = 1; i < qdata.length; i += 2) {
1145
- buffer.push('Q ' + qdata[i].x + ' ' + qdata[i].y + ', ' + qdata[i + 1].x + ' ' + qdata[i + 1].y);
1279
+ buffer.push("Q " + qdata[i].x + " " + qdata[i].y + ", " + qdata[i + 1].x + " " + qdata[i + 1].y);
1146
1280
  }
1147
- return buffer.join(' ');
1281
+ return buffer.join(" ");
1148
1282
  }
1149
- ;
1150
1283
  /**
1151
1284
  * Convert this polygon to a sequence of cubic Bézier curves.<br>
1152
1285
  * <br>
@@ -1163,7 +1296,7 @@ class Polygon {
1163
1296
  * @memberof Polygon
1164
1297
  **/
1165
1298
  toCubicBezierData(threshold) {
1166
- if (typeof threshold == 'undefined')
1299
+ if (typeof threshold == "undefined")
1167
1300
  threshold = 1.0;
1168
1301
  if (this.vertices.length < 3)
1169
1302
  return [];
@@ -1187,7 +1320,6 @@ class Polygon {
1187
1320
  }
1188
1321
  return cbezier;
1189
1322
  }
1190
- ;
1191
1323
  /**
1192
1324
  * Convert this polygon to a cubic bezier curve, represented as an SVG data string.
1193
1325
  *
@@ -1200,13 +1332,23 @@ class Polygon {
1200
1332
  var qdata = this.toCubicBezierData(threshold);
1201
1333
  if (qdata.length == 0)
1202
1334
  return "";
1203
- var buffer = ['M ' + qdata[0].x + ' ' + qdata[0].y];
1335
+ var buffer = ["M " + qdata[0].x + " " + qdata[0].y];
1204
1336
  for (var i = 1; i < qdata.length; i += 3) {
1205
- buffer.push('C ' + qdata[i].x + ' ' + qdata[i].y + ', ' + qdata[i + 1].x + ' ' + qdata[i + 1].y + ', ' + qdata[i + 2].x + ' ' + qdata[i + 2].y);
1206
- }
1207
- return buffer.join(' ');
1337
+ buffer.push("C " +
1338
+ qdata[i].x +
1339
+ " " +
1340
+ qdata[i].y +
1341
+ ", " +
1342
+ qdata[i + 1].x +
1343
+ " " +
1344
+ qdata[i + 1].y +
1345
+ ", " +
1346
+ qdata[i + 2].x +
1347
+ " " +
1348
+ qdata[i + 2].y);
1349
+ }
1350
+ return buffer.join(" ");
1208
1351
  }
1209
- ;
1210
1352
  /**
1211
1353
  * Convert this polygon to a cubic bezier path instance.
1212
1354
  *
@@ -1225,7 +1367,6 @@ class Polygon {
1225
1367
  }
1226
1368
  return BezierPath.fromArray(pathdata);
1227
1369
  }
1228
- ;
1229
1370
  /**
1230
1371
  * Create an SVG representation of this polygon.
1231
1372
  *
@@ -1237,31 +1378,42 @@ class Polygon {
1237
1378
  * @memberof Polygon
1238
1379
  **/
1239
1380
  toSVGString(options) {
1240
- options = options || {};
1241
- var buffer = [];
1242
- buffer.push('<path');
1243
- if (options.className)
1244
- buffer.push(' class="' + options.className + '"');
1245
- buffer.push(' d="');
1246
- if (this.vertices.length > 0) {
1247
- buffer.push('M ');
1248
- buffer.push(this.vertices[0].x.toString());
1249
- buffer.push(' ');
1250
- buffer.push(this.vertices[0].y.toString());
1251
- for (var i = 1; i < this.vertices.length; i++) {
1252
- buffer.push(' L ');
1253
- buffer.push(this.vertices[i].x.toString());
1254
- buffer.push(' ');
1255
- buffer.push(this.vertices[i].y.toString());
1256
- }
1257
- if (!this.isOpen) {
1258
- buffer.push(' Z');
1259
- }
1381
+ // options = options || {};
1382
+ // var buffer: Array<string> = [];
1383
+ // buffer.push("<path");
1384
+ // if (options.className) buffer.push(' class="' + options.className + '"');
1385
+ // buffer.push(' d="');
1386
+ // if (this.vertices.length > 0) {
1387
+ // buffer.push("M ");
1388
+ // buffer.push(this.vertices[0].x.toString());
1389
+ // buffer.push(" ");
1390
+ // buffer.push(this.vertices[0].y.toString());
1391
+ // for (var i = 1; i < this.vertices.length; i++) {
1392
+ // buffer.push(" L ");
1393
+ // buffer.push(this.vertices[i].x.toString());
1394
+ // buffer.push(" ");
1395
+ // buffer.push(this.vertices[i].y.toString());
1396
+ // }
1397
+ // if (!this.isOpen) {
1398
+ // buffer.push(" Z");
1399
+ // }
1400
+ // }
1401
+ // buffer.push('" />');
1402
+ // return buffer.join("");
1403
+ console.warn("[Deprecation] Warning: the Polygon.toSVGString method is deprecated and does not return and valid SVG data any more. Please use `drawutilssvg` instead.");
1404
+ return "";
1405
+ }
1406
+ /**
1407
+ * This function should invalidate any installed listeners and invalidate this object.
1408
+ * After calling this function the object might not hold valid data any more and
1409
+ * should not be used.
1410
+ */
1411
+ destroy() {
1412
+ for (var i = 0; i < this.vertices.length; i++) {
1413
+ this.vertices[i].destroy();
1260
1414
  }
1261
- buffer.push('" />');
1262
- return buffer.join('');
1415
+ this.isDestroyed = true;
1263
1416
  }
1264
- ;
1265
1417
  }
1266
1418
  Polygon.utils = {
1267
1419
  /**
@@ -1281,8 +1433,8 @@ Polygon.utils = {
1281
1433
  const addY = vertices[(i + 1) % l].y;
1282
1434
  const subX = vertices[(i + 1) % l].x;
1283
1435
  const subY = vertices[i].y;
1284
- total += (addX * addY * 0.5);
1285
- total -= (subX * subY * 0.5);
1436
+ total += addX * addY * 0.5;
1437
+ total -= subX * subY * 0.5;
1286
1438
  }
1287
1439
  return Math.abs(total);
1288
1440
  },
@@ -1389,7 +1541,8 @@ class Bounds {
1389
1541
  * @modified 2020-12-04 Changed `getClosestT` param from `Vertex` to `XYCoords` (generalized).
1390
1542
  * @modified 2020-12-04 Added the `hasPoint(XYCoords)` function.
1391
1543
  * @modified 2021-01-20 Added UID.
1392
- * @version 1.1.0
1544
+ * @modified 2022-02-02 Added the `destroy` method.
1545
+ * @version 1.2.0
1393
1546
  */
1394
1547
  /**
1395
1548
  * @classdesc An abstract base classes for vertex tuple constructs, like Lines or Vectors.
@@ -1423,7 +1576,6 @@ class VertTuple {
1423
1576
  length() {
1424
1577
  return Math.sqrt(Math.pow(this.b.x - this.a.x, 2) + Math.pow(this.b.y - this.a.y, 2));
1425
1578
  }
1426
- ;
1427
1579
  /**
1428
1580
  * Set the length of this vector to the given amount. This only works if this
1429
1581
  * vector is not a null vector.
@@ -1436,7 +1588,6 @@ class VertTuple {
1436
1588
  setLength(length) {
1437
1589
  return this.scale(length / this.length());
1438
1590
  }
1439
- ;
1440
1591
  /**
1441
1592
  * Substract the given vertex from this line's end points.
1442
1593
  *
@@ -1451,7 +1602,6 @@ class VertTuple {
1451
1602
  this.b.sub(amount);
1452
1603
  return this;
1453
1604
  }
1454
- ;
1455
1605
  /**
1456
1606
  * Add the given vertex to this line's end points.
1457
1607
  *
@@ -1466,7 +1616,6 @@ class VertTuple {
1466
1616
  this.b.add(amount);
1467
1617
  return this;
1468
1618
  }
1469
- ;
1470
1619
  /**
1471
1620
  * Normalize this line (set to length 1).
1472
1621
  *
@@ -1479,7 +1628,6 @@ class VertTuple {
1479
1628
  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());
1480
1629
  return this;
1481
1630
  }
1482
- ;
1483
1631
  /**
1484
1632
  * Scale this line by the given factor.
1485
1633
  *
@@ -1493,7 +1641,6 @@ class VertTuple {
1493
1641
  this.b.set(this.a.x + (this.b.x - this.a.x) * factor, this.a.y + (this.b.y - this.a.y) * factor);
1494
1642
  return this;
1495
1643
  }
1496
- ;
1497
1644
  /**
1498
1645
  * Move this line to a new location.
1499
1646
  *
@@ -1509,7 +1656,6 @@ class VertTuple {
1509
1656
  this.b.add(diff);
1510
1657
  return this;
1511
1658
  }
1512
- ;
1513
1659
  /**
1514
1660
  * Get the angle between this and the passed line (in radians).
1515
1661
  *
@@ -1520,7 +1666,7 @@ class VertTuple {
1520
1666
  * @memberof VertTuple
1521
1667
  **/
1522
1668
  angle(line) {
1523
- if (line == null || typeof line == 'undefined') {
1669
+ if (line == null || typeof line == "undefined") {
1524
1670
  line = this.factory(new Vertex(0, 0), new Vertex(100, 0));
1525
1671
  }
1526
1672
  // Compute the angle from x axis and the return the difference :)
@@ -1530,7 +1676,6 @@ class VertTuple {
1530
1676
  // The result might be negative, but isn't it usually nicer to determine angles in positive values only?
1531
1677
  return Math.atan2(v1.x, v1.y) - Math.atan2(v0.x, v0.y);
1532
1678
  }
1533
- ;
1534
1679
  /**
1535
1680
  * Get line point at position t in [0 ... 1]:<br>
1536
1681
  * <pre>[P(0)]=[A]--------------------[P(t)]------[B]=[P(1)]</pre><br>
@@ -1546,7 +1691,6 @@ class VertTuple {
1546
1691
  vertAt(t) {
1547
1692
  return new Vertex(this.a.x + (this.b.x - this.a.x) * t, this.a.y + (this.b.y - this.a.y) * t);
1548
1693
  }
1549
- ;
1550
1694
  /**
1551
1695
  * Get the denominator of this and the given line.
1552
1696
  *
@@ -1560,9 +1704,8 @@ class VertTuple {
1560
1704
  **/
1561
1705
  denominator(line) {
1562
1706
  // http://jsfiddle.net/justin_c_rounds/Gd2S2/
1563
- 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));
1707
+ 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);
1564
1708
  }
1565
- ;
1566
1709
  /**
1567
1710
  * Checks if this and the given line are co-linear.
1568
1711
  *
@@ -1577,7 +1720,6 @@ class VertTuple {
1577
1720
  colinear(line) {
1578
1721
  return Math.abs(this.denominator(line)) < Vertex.EPSILON;
1579
1722
  }
1580
- ;
1581
1723
  /**
1582
1724
  * Get the closest position T from this line to the specified point.
1583
1725
  *
@@ -1600,7 +1742,6 @@ class VertTuple {
1600
1742
  // t = Math.max(0, Math.min(1, t));
1601
1743
  return t;
1602
1744
  }
1603
- ;
1604
1745
  /**
1605
1746
  * Check if the given point is located on this line. Optionally also check if
1606
1747
  * that point is located between point `a` and `b`.
@@ -1636,7 +1777,6 @@ class VertTuple {
1636
1777
  var t = this.getClosestT(p);
1637
1778
  return this.vertAt(t);
1638
1779
  }
1639
- ;
1640
1780
  /**
1641
1781
  * The the minimal distance between this line and the specified point.
1642
1782
  *
@@ -1651,7 +1791,6 @@ class VertTuple {
1651
1791
  // https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
1652
1792
  return Math.sqrt(VertTuple.vtutils.dist2(p, this.vertAt(this.getClosestT(p))));
1653
1793
  }
1654
- ;
1655
1794
  /**
1656
1795
  * Create a deep clone of this instance.
1657
1796
  *
@@ -1663,7 +1802,6 @@ class VertTuple {
1663
1802
  clone() {
1664
1803
  return this.factory(this.a.clone(), this.b.clone());
1665
1804
  }
1666
- ;
1667
1805
  /**
1668
1806
  * Create a string representation of this line.
1669
1807
  *
@@ -1675,7 +1813,16 @@ class VertTuple {
1675
1813
  toString() {
1676
1814
  return "{ a : " + this.a.toString() + ", b : " + this.b.toString() + " }";
1677
1815
  }
1678
- ;
1816
+ /**
1817
+ * This function should invalidate any installed listeners and invalidate this object.
1818
+ * After calling this function the object might not hold valid data any more and
1819
+ * should not be used.
1820
+ */
1821
+ destroy() {
1822
+ this.a.destroy();
1823
+ this.b.destroy();
1824
+ this.isDestroyed = true;
1825
+ }
1679
1826
  }
1680
1827
  /**
1681
1828
  * @private
@@ -1697,7 +1844,9 @@ VertTuple.vtutils = {
1697
1844
  * @modified 2019-12-04 Added the Vector.inv() function.
1698
1845
  * @modified 2020-03-23 Ported to Typescript from JS.
1699
1846
  * @modified 2021-01-20 Added UID.
1700
- * @version 1.3.0
1847
+ * @modified 2022-02-02 Added the `destroy` method.
1848
+ * @modified 2022-02-02 Cleared the `Vector.toSVGString` function (deprecated). Use `drawutilssvg` instead.
1849
+ * @version 1.4.0
1701
1850
  *
1702
1851
  * @file Vector
1703
1852
  * @public
@@ -1728,7 +1877,6 @@ class Vector extends VertTuple {
1728
1877
  **/
1729
1878
  this.className = "Vector";
1730
1879
  }
1731
- ;
1732
1880
  /**
1733
1881
  * Get the perpendicular of this vector which is located at a.
1734
1882
  *
@@ -1743,7 +1891,6 @@ class Vector extends VertTuple {
1743
1891
  v.b.add(this.a);
1744
1892
  return v;
1745
1893
  }
1746
- ;
1747
1894
  /**
1748
1895
  * The inverse of a vector is a vector witht the same magnitude but oppose direction.
1749
1896
  *
@@ -1757,7 +1904,6 @@ class Vector extends VertTuple {
1757
1904
  this.b = tmp;
1758
1905
  return this;
1759
1906
  }
1760
- ;
1761
1907
  /**
1762
1908
  * This function computes the inverse of the vector, which means 'a' stays untouched.
1763
1909
  *
@@ -1768,7 +1914,6 @@ class Vector extends VertTuple {
1768
1914
  this.b.y = this.a.y - (this.b.y - this.a.y);
1769
1915
  return this;
1770
1916
  }
1771
- ;
1772
1917
  /**
1773
1918
  * Get the intersection if this vector and the specified vector.
1774
1919
  *
@@ -1784,16 +1929,15 @@ class Vector extends VertTuple {
1784
1929
  return null;
1785
1930
  var a = this.a.y - line.a.y;
1786
1931
  var b = this.a.x - line.a.x;
1787
- var numerator1 = ((line.b.x - line.a.x) * a) - ((line.b.y - line.a.y) * b);
1788
- var numerator2 = ((this.b.x - this.a.x) * a) - ((this.b.y - this.a.y) * b);
1932
+ var numerator1 = (line.b.x - line.a.x) * a - (line.b.y - line.a.y) * b;
1933
+ var numerator2 = (this.b.x - this.a.x) * a - (this.b.y - this.a.y) * b;
1789
1934
  a = numerator1 / denominator; // NaN if parallel lines
1790
1935
  b = numerator2 / denominator;
1791
1936
  // TODO:
1792
1937
  // FOR A VECTOR THE LINE-INTERSECTION MUST BE ON BOTH VECTORS
1793
1938
  // if we cast these lines infinitely in both directions, they intersect here:
1794
- return new Vertex(this.a.x + (a * (this.b.x - this.a.x)), this.a.y + (a * (this.b.y - this.a.y)));
1939
+ return new Vertex(this.a.x + a * (this.b.x - this.a.x), this.a.y + a * (this.b.y - this.a.y));
1795
1940
  }
1796
- ;
1797
1941
  /**
1798
1942
  * Create an SVG representation of this line.
1799
1943
  *
@@ -1806,31 +1950,30 @@ class Vector extends VertTuple {
1806
1950
  * @memberof Vector
1807
1951
  **/
1808
1952
  toSVGString(options) {
1809
- options = options || {};
1810
- var buffer = [];
1811
- var vertices = Vector.utils.buildArrowHead(this.a, this.b, 8, 1.0, 1.0);
1812
- buffer.push('<g');
1813
- if (options.className)
1814
- buffer.push(' class="' + options.className + '"');
1815
- buffer.push('>');
1816
- buffer.push(' <line');
1817
- buffer.push(' x1="' + this.a.x + '"');
1818
- buffer.push(' y1="' + this.a.y + '"');
1819
- buffer.push(' x2="' + vertices[0].x + '"');
1820
- buffer.push(' y2="' + vertices[0].y + '"');
1821
- buffer.push(' />');
1822
- // Add arrow head
1823
- buffer.push(' <polygon points="');
1824
- for (var i = 0; i < vertices.length; i++) {
1825
- if (i > 0)
1826
- buffer.push(' ');
1827
- buffer.push('' + vertices[i].x + ',' + vertices[i].y);
1828
- }
1829
- buffer.push('"/>');
1830
- buffer.push('</g>');
1831
- return buffer.join('');
1953
+ // options = options || {};
1954
+ // var buffer = [];
1955
+ // var vertices = Vector.utils.buildArrowHead(this.a, this.b, 8, 1.0, 1.0);
1956
+ // buffer.push("<g");
1957
+ // if (options.className) buffer.push(' class="' + options.className + '"');
1958
+ // buffer.push(">");
1959
+ // buffer.push(" <line");
1960
+ // buffer.push(' x1="' + this.a.x + '"');
1961
+ // buffer.push(' y1="' + this.a.y + '"');
1962
+ // buffer.push(' x2="' + vertices[0].x + '"');
1963
+ // buffer.push(' y2="' + vertices[0].y + '"');
1964
+ // buffer.push(" />");
1965
+ // // Add arrow head
1966
+ // buffer.push(' <polygon points="');
1967
+ // for (var i = 0; i < vertices.length; i++) {
1968
+ // if (i > 0) buffer.push(" ");
1969
+ // buffer.push("" + vertices[i].x + "," + vertices[i].y);
1970
+ // }
1971
+ // buffer.push('"/>');
1972
+ // buffer.push("</g>");
1973
+ // return buffer.join("");
1974
+ console.warn("[Deprecation] Warning: the Vector.toSVGString method is deprecated and does not return and valid SVG data any more. Please use `drawutilssvg` instead.");
1975
+ return "";
1832
1976
  }
1833
- ;
1834
1977
  }
1835
1978
  Vector.utils = {
1836
1979
  /**
@@ -1861,10 +2004,10 @@ Vector.utils = {
1861
2004
  buildArrowHead: (zA, zB, headlen, scaleX, scaleY) => {
1862
2005
  var angle = Math.atan2((zB.y - zA.y) * scaleY, (zB.x - zA.x) * scaleX);
1863
2006
  var vertices = [];
1864
- vertices.push(new Vertex(zB.x * scaleX - (headlen) * Math.cos(angle), zB.y * scaleY - (headlen) * Math.sin(angle)));
1865
- 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)));
2007
+ vertices.push(new Vertex(zB.x * scaleX - headlen * Math.cos(angle), zB.y * scaleY - headlen * Math.sin(angle)));
2008
+ 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)));
1866
2009
  vertices.push(new Vertex(zB.x * scaleX, zB.y * scaleY));
1867
- 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)));
2010
+ 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)));
1868
2011
  return vertices;
1869
2012
  }
1870
2013
  };
@@ -1889,7 +2032,9 @@ Vector.utils = {
1889
2032
  * @modified 2020-07-14 Changed the moveCurvePoint(...,Vertex) to moveCurvePoint(...,XYCoords), which is more generic.
1890
2033
  * @modified 2020-07-24 Added the getClosestT function and the helper function locateIntervalByDistance(...).
1891
2034
  * @modified 2021-01-20 Added UID.
1892
- * @version 2.5.0
2035
+ * @modified 2022-02-02 Added the `destroy` method.
2036
+ * @modified 2022-02-02 Cleared the `toSVGPathData` function (deprecated). Use `drawutilssvg` instead.
2037
+ * @version 2.6.0
1893
2038
  *
1894
2039
  * @file CubicBezierCurve
1895
2040
  * @public
@@ -1938,7 +2083,6 @@ class CubicBezierCurve {
1938
2083
  this.arcLength = null;
1939
2084
  this.updateArcLengths();
1940
2085
  }
1941
- ;
1942
2086
  /**
1943
2087
  * Move the given curve point (the start point, end point or one of the two
1944
2088
  * control points).
@@ -1975,7 +2119,6 @@ class CubicBezierCurve {
1975
2119
  if (updateArcLengths)
1976
2120
  this.updateArcLengths();
1977
2121
  }
1978
- ;
1979
2122
  /**
1980
2123
  * Translate the whole curve by the given {x,y} amount: moves all four points.
1981
2124
  *
@@ -1992,7 +2135,6 @@ class CubicBezierCurve {
1992
2135
  this.endPoint.add(amount);
1993
2136
  return this;
1994
2137
  }
1995
- ;
1996
2138
  /**
1997
2139
  * Reverse this curve, means swapping start- and end-point and swapping
1998
2140
  * start-control- and end-control-point.
@@ -2011,7 +2153,6 @@ class CubicBezierCurve {
2011
2153
  this.endControlPoint = tmp;
2012
2154
  return this;
2013
2155
  }
2014
- ;
2015
2156
  /**
2016
2157
  * Get the total curve length.<br>
2017
2158
  * <br>
@@ -2030,7 +2171,6 @@ class CubicBezierCurve {
2030
2171
  getLength() {
2031
2172
  return this.arcLength;
2032
2173
  }
2033
- ;
2034
2174
  /**
2035
2175
  * Uptate the internal arc segment buffer and their lengths.<br>
2036
2176
  * <br>
@@ -2068,7 +2208,6 @@ class CubicBezierCurve {
2068
2208
  }
2069
2209
  this.arcLength = newLength;
2070
2210
  }
2071
- ;
2072
2211
  /**
2073
2212
  * Get a 't' (relative position on curve) with the closest distance to point 'p'.
2074
2213
  *
@@ -2091,7 +2230,6 @@ class CubicBezierCurve {
2091
2230
  } while (iteration < 4 && this.getPointAt(result.tPrev).distance(this.getPointAt(result.tNext)) > desiredEpsilon);
2092
2231
  return result.t;
2093
2232
  }
2094
- ;
2095
2233
  /**
2096
2234
  * This helper function locates the 't' on a fixed step interval with the minimal distance
2097
2235
  * between the curve (at 't') and the given point.
@@ -2120,12 +2258,12 @@ class CubicBezierCurve {
2120
2258
  minDist = dist;
2121
2259
  }
2122
2260
  }
2123
- return { t: tStart + tDiff * (minIndex / stepCount),
2261
+ return {
2262
+ t: tStart + tDiff * (minIndex / stepCount),
2124
2263
  tPrev: tStart + tDiff * (Math.max(0, minIndex - 1) / stepCount),
2125
2264
  tNext: tStart + tDiff * (Math.min(stepCount, minIndex + 1) / stepCount)
2126
2265
  };
2127
2266
  }
2128
- ;
2129
2267
  /**
2130
2268
  * Get the bounds of this bezier curve.
2131
2269
  *
@@ -2147,7 +2285,6 @@ class CubicBezierCurve {
2147
2285
  }
2148
2286
  return new Bounds(min, max);
2149
2287
  }
2150
- ;
2151
2288
  /**
2152
2289
  * Get the start point of the curve.<br>
2153
2290
  * <br>
@@ -2161,7 +2298,6 @@ class CubicBezierCurve {
2161
2298
  getStartPoint() {
2162
2299
  return this.startPoint;
2163
2300
  }
2164
- ;
2165
2301
  /**
2166
2302
  * Get the end point of the curve.<br>
2167
2303
  * <br>
@@ -2175,7 +2311,6 @@ class CubicBezierCurve {
2175
2311
  getEndPoint() {
2176
2312
  return this.endPoint;
2177
2313
  }
2178
- ;
2179
2314
  /**
2180
2315
  * Get the start control point of the curve.<br>
2181
2316
  * <br>
@@ -2189,7 +2324,6 @@ class CubicBezierCurve {
2189
2324
  getStartControlPoint() {
2190
2325
  return this.startControlPoint;
2191
2326
  }
2192
- ;
2193
2327
  /**
2194
2328
  * Get the end control point of the curve.<br>
2195
2329
  * <br>
@@ -2203,7 +2337,6 @@ class CubicBezierCurve {
2203
2337
  getEndControlPoint() {
2204
2338
  return this.endControlPoint;
2205
2339
  }
2206
- ;
2207
2340
  /**
2208
2341
  * Get one of the four curve points specified by the passt point ID.
2209
2342
  *
@@ -2224,7 +2357,6 @@ class CubicBezierCurve {
2224
2357
  return this.endControlPoint;
2225
2358
  throw new Error(`Invalid point ID '${id}'.`);
2226
2359
  }
2227
- ;
2228
2360
  /**
2229
2361
  * Get the curve point at a given position t, where t is in [0,1].<br>
2230
2362
  * <br>
@@ -2239,13 +2371,16 @@ class CubicBezierCurve {
2239
2371
  **/
2240
2372
  getPointAt(t) {
2241
2373
  // Perform some powerful math magic
2242
- const x = this.startPoint.x * Math.pow(1.0 - t, 3) + this.startControlPoint.x * 3 * t * Math.pow(1.0 - t, 2)
2243
- + this.endControlPoint.x * 3 * Math.pow(t, 2) * (1.0 - t) + this.endPoint.x * Math.pow(t, 3);
2244
- const y = this.startPoint.y * Math.pow(1.0 - t, 3) + this.startControlPoint.y * 3 * t * Math.pow(1.0 - t, 2)
2245
- + this.endControlPoint.y * 3 * Math.pow(t, 2) * (1.0 - t) + this.endPoint.y * Math.pow(t, 3);
2374
+ const x = this.startPoint.x * Math.pow(1.0 - t, 3) +
2375
+ this.startControlPoint.x * 3 * t * Math.pow(1.0 - t, 2) +
2376
+ this.endControlPoint.x * 3 * Math.pow(t, 2) * (1.0 - t) +
2377
+ this.endPoint.x * Math.pow(t, 3);
2378
+ const y = this.startPoint.y * Math.pow(1.0 - t, 3) +
2379
+ this.startControlPoint.y * 3 * t * Math.pow(1.0 - t, 2) +
2380
+ this.endControlPoint.y * 3 * Math.pow(t, 2) * (1.0 - t) +
2381
+ this.endPoint.y * Math.pow(t, 3);
2246
2382
  return new Vertex(x, y);
2247
2383
  }
2248
- ;
2249
2384
  /**
2250
2385
  * Get the curve point at a given position u, where u is in [0,arcLength].<br>
2251
2386
  * <br>
@@ -2261,7 +2396,6 @@ class CubicBezierCurve {
2261
2396
  getPoint(u) {
2262
2397
  return this.getPointAt(u / this.arcLength);
2263
2398
  }
2264
- ;
2265
2399
  /**
2266
2400
  * Get the curve tangent vector at a given absolute curve position t in [0,1].<br>
2267
2401
  * <br>
@@ -2282,18 +2416,11 @@ class CubicBezierCurve {
2282
2416
  const t2 = t * t;
2283
2417
  // (1 - t)^2 = (1-t)*(1-t) = 1 - t - t + t^2 = 1 - 2*t + t^2
2284
2418
  const nt2 = 1 - 2 * t + t2;
2285
- const tX = -3 * a.x * nt2 +
2286
- b.x * (3 * nt2 - 6 * (t - t2)) +
2287
- c.x * (6 * (t - t2) - 3 * t2) +
2288
- 3 * d.x * t2;
2289
- const tY = -3 * a.y * nt2 +
2290
- b.y * (3 * nt2 - 6 * (t - t2)) +
2291
- c.y * (6 * (t - t2) - 3 * t2) +
2292
- 3 * d.y * t2;
2419
+ const tX = -3 * a.x * nt2 + b.x * (3 * nt2 - 6 * (t - t2)) + c.x * (6 * (t - t2) - 3 * t2) + 3 * d.x * t2;
2420
+ const tY = -3 * a.y * nt2 + b.y * (3 * nt2 - 6 * (t - t2)) + c.y * (6 * (t - t2) - 3 * t2) + 3 * d.y * t2;
2293
2421
  // Note: my implementation does NOT normalize tangent vectors!
2294
2422
  return new Vertex(tX, tY);
2295
2423
  }
2296
- ;
2297
2424
  /**
2298
2425
  * Get a sub curve at the given start end end offsets (values between 0.0 and 1.0).
2299
2426
  *
@@ -2319,7 +2446,6 @@ class CubicBezierCurve {
2319
2446
  // pb.draw.cubicBezier( startVec.a, endVec.a, startVec.b, endVec.b, '#8800ff', 2 );
2320
2447
  return new CubicBezierCurve(startVec.a, endVec.a, startVec.b, endVec.b);
2321
2448
  }
2322
- ;
2323
2449
  /**
2324
2450
  * Convert a relative curve position u to the absolute curve position t.
2325
2451
  *
@@ -2330,9 +2456,8 @@ class CubicBezierCurve {
2330
2456
  * @return {number}
2331
2457
  **/
2332
2458
  convertU2T(u) {
2333
- return Math.max(0.0, Math.min(1.0, (u / this.arcLength)));
2459
+ return Math.max(0.0, Math.min(1.0, u / this.arcLength));
2334
2460
  }
2335
- ;
2336
2461
  /**
2337
2462
  * Get the curve tangent vector at a given relative position u in [0,arcLength].<br>
2338
2463
  * <br>
@@ -2347,7 +2472,6 @@ class CubicBezierCurve {
2347
2472
  getTangent(u) {
2348
2473
  return this.getTangentAt(this.convertU2T(u));
2349
2474
  }
2350
- ;
2351
2475
  /**
2352
2476
  * Get the curve perpendicular at a given relative position u in [0,arcLength] as a vector.<br>
2353
2477
  * <br>
@@ -2362,7 +2486,6 @@ class CubicBezierCurve {
2362
2486
  getPerpendicular(u) {
2363
2487
  return this.getPerpendicularAt(this.convertU2T(u));
2364
2488
  }
2365
- ;
2366
2489
  /**
2367
2490
  * Get the curve perpendicular at a given absolute position t in [0,1] as a vector.<br>
2368
2491
  * <br>
@@ -2378,7 +2501,6 @@ class CubicBezierCurve {
2378
2501
  const tangentVector = this.getTangentAt(t);
2379
2502
  return new Vertex(tangentVector.y, -tangentVector.x);
2380
2503
  }
2381
- ;
2382
2504
  /**
2383
2505
  * Clone this Bézier curve (deep clone).
2384
2506
  *
@@ -2390,7 +2512,6 @@ class CubicBezierCurve {
2390
2512
  clone() {
2391
2513
  return new CubicBezierCurve(this.getStartPoint().clone(), this.getEndPoint().clone(), this.getStartControlPoint().clone(), this.getEndControlPoint().clone());
2392
2514
  }
2393
- ;
2394
2515
  /**
2395
2516
  * Check if this and the specified curve are equal.<br>
2396
2517
  * <br>
@@ -2409,17 +2530,25 @@ class CubicBezierCurve {
2409
2530
  // Let's see if this restricted version works out.
2410
2531
  if (!curve)
2411
2532
  return false;
2412
- if (!curve.startPoint ||
2413
- !curve.endPoint ||
2414
- !curve.startControlPoint ||
2415
- !curve.endControlPoint)
2533
+ if (!curve.startPoint || !curve.endPoint || !curve.startControlPoint || !curve.endControlPoint)
2416
2534
  return false;
2417
- return this.startPoint.equals(curve.startPoint)
2418
- && this.endPoint.equals(curve.endPoint)
2419
- && this.startControlPoint.equals(curve.startControlPoint)
2420
- && this.endControlPoint.equals(curve.endControlPoint);
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));
2539
+ }
2540
+ /**
2541
+ * This function should invalidate any installed listeners and invalidate this object.
2542
+ * After calling this function the object might not hold valid data any more and
2543
+ * should not be used.
2544
+ */
2545
+ destroy() {
2546
+ this.startPoint.destroy();
2547
+ this.endPoint.destroy();
2548
+ this.startControlPoint.destroy();
2549
+ this.endControlPoint.destroy();
2550
+ this.isDestroyed = true;
2421
2551
  }
2422
- ;
2423
2552
  /**
2424
2553
  * Quick check for class instance.
2425
2554
  * Is there a better way?
@@ -2445,7 +2574,6 @@ class CubicBezierCurve {
2445
2574
  */
2446
2575
  return obj instanceof CubicBezierCurve;
2447
2576
  }
2448
- ;
2449
2577
  /**
2450
2578
  * Create an SVG path data representation of this bézier curve.
2451
2579
  *
@@ -2454,32 +2582,34 @@ class CubicBezierCurve {
2454
2582
  * or in other words<br>
2455
2583
  * <pre>'M startoint.x startPoint.y C startControlPoint.x startControlPoint.y endControlPoint.x endControlPoint.y endPoint.x endPoint.y'</pre>
2456
2584
  *
2585
+ * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
2457
2586
  * @method toSVGPathData
2458
2587
  * @instance
2459
2588
  * @memberof CubicBezierCurve
2460
2589
  * @return {string} The SVG path data string.
2461
2590
  **/
2462
2591
  toSVGPathData() {
2463
- var buffer = [];
2464
- buffer.push('M ');
2465
- buffer.push(this.startPoint.x.toString());
2466
- buffer.push(' ');
2467
- buffer.push(this.startPoint.y.toString());
2468
- buffer.push(' C ');
2469
- buffer.push(this.startControlPoint.x.toString());
2470
- buffer.push(' ');
2471
- buffer.push(this.startControlPoint.y.toString());
2472
- buffer.push(' ');
2473
- buffer.push(this.endControlPoint.x.toString());
2474
- buffer.push(' ');
2475
- buffer.push(this.endControlPoint.y.toString());
2476
- buffer.push(' ');
2477
- buffer.push(this.endPoint.x.toString());
2478
- buffer.push(' ');
2479
- buffer.push(this.endPoint.y.toString());
2480
- return buffer.join('');
2592
+ // var buffer: Array<string> = [];
2593
+ // buffer.push("M ");
2594
+ // buffer.push(this.startPoint.x.toString());
2595
+ // buffer.push(" ");
2596
+ // buffer.push(this.startPoint.y.toString());
2597
+ // buffer.push(" C ");
2598
+ // buffer.push(this.startControlPoint.x.toString());
2599
+ // buffer.push(" ");
2600
+ // buffer.push(this.startControlPoint.y.toString());
2601
+ // buffer.push(" ");
2602
+ // buffer.push(this.endControlPoint.x.toString());
2603
+ // buffer.push(" ");
2604
+ // buffer.push(this.endControlPoint.y.toString());
2605
+ // buffer.push(" ");
2606
+ // buffer.push(this.endPoint.x.toString());
2607
+ // buffer.push(" ");
2608
+ // buffer.push(this.endPoint.y.toString());
2609
+ // return buffer.join("");
2610
+ console.warn("[Deprecation] Warning: the CubicBezierCurve.toSVGPathData method is deprecated and does not return and valid SVG data any more. Please use `drawutilssvg` instead.");
2611
+ return "";
2481
2612
  }
2482
- ;
2483
2613
  /**
2484
2614
  * Convert this curve to a JSON string.
2485
2615
  *
@@ -2492,18 +2622,33 @@ class CubicBezierCurve {
2492
2622
  toJSON(prettyFormat) {
2493
2623
  var jsonString = "{ " + // begin object
2494
2624
  (prettyFormat ? "\n\t" : "") +
2495
- "\"startPoint\" : [" + this.getStartPoint().x + "," + this.getStartPoint().y + "], " +
2625
+ '"startPoint" : [' +
2626
+ this.getStartPoint().x +
2627
+ "," +
2628
+ this.getStartPoint().y +
2629
+ "], " +
2496
2630
  (prettyFormat ? "\n\t" : "") +
2497
- "\"endPoint\" : [" + this.getEndPoint().x + "," + this.getEndPoint().y + "], " +
2631
+ '"endPoint" : [' +
2632
+ this.getEndPoint().x +
2633
+ "," +
2634
+ this.getEndPoint().y +
2635
+ "], " +
2498
2636
  (prettyFormat ? "\n\t" : "") +
2499
- "\"startControlPoint\": [" + this.getStartControlPoint().x + "," + this.getStartControlPoint().y + "], " +
2637
+ '"startControlPoint": [' +
2638
+ this.getStartControlPoint().x +
2639
+ "," +
2640
+ this.getStartControlPoint().y +
2641
+ "], " +
2500
2642
  (prettyFormat ? "\n\t" : "") +
2501
- "\"endControlPoint\" : [" + this.getEndControlPoint().x + "," + this.getEndControlPoint().y + "]" +
2643
+ '"endControlPoint" : [' +
2644
+ this.getEndControlPoint().x +
2645
+ "," +
2646
+ this.getEndControlPoint().y +
2647
+ "]" +
2502
2648
  (prettyFormat ? "\n\t" : "") +
2503
2649
  " }"; // end object
2504
2650
  return jsonString;
2505
2651
  }
2506
- ;
2507
2652
  /**
2508
2653
  * Parse a Bézier curve from the given JSON string.
2509
2654
  *
@@ -2518,7 +2663,6 @@ class CubicBezierCurve {
2518
2663
  var obj = JSON.parse(jsonString);
2519
2664
  return CubicBezierCurve.fromObject(obj);
2520
2665
  }
2521
- ;
2522
2666
  /**
2523
2667
  * Try to convert the passed object to a CubicBezierCurve.
2524
2668
  *
@@ -2533,16 +2677,15 @@ class CubicBezierCurve {
2533
2677
  if (typeof obj !== "object")
2534
2678
  throw "Can only build from object.";
2535
2679
  if (!obj.startPoint)
2536
- throw "Object member \"startPoint\" missing.";
2680
+ throw 'Object member "startPoint" missing.';
2537
2681
  if (!obj.endPoint)
2538
- throw "Object member \"endPoint\" missing.";
2682
+ throw 'Object member "endPoint" missing.';
2539
2683
  if (!obj.startControlPoint)
2540
- throw "Object member \"startControlPoint\" missing.";
2684
+ throw 'Object member "startControlPoint" missing.';
2541
2685
  if (!obj.endControlPoint)
2542
- throw "Object member \"endControlPoint\" missing.";
2686
+ throw 'Object member "endControlPoint" missing.';
2543
2687
  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]));
2544
2688
  }
2545
- ;
2546
2689
  /**
2547
2690
  * Convert a 4-element array of vertices to a cubic bézier curve.
2548
2691
  *
@@ -2559,7 +2702,6 @@ class CubicBezierCurve {
2559
2702
  throw "Can only build from array with four elements.";
2560
2703
  return new CubicBezierCurve(arr[0], arr[1], arr[2], arr[3]);
2561
2704
  }
2562
- ;
2563
2705
  }
2564
2706
  /** @constant {number} */
2565
2707
  CubicBezierCurve.START_POINT = 0;
@@ -2592,7 +2734,10 @@ CubicBezierCurve.END_POINT = 3;
2592
2734
  * @modified 2020-07-24 Added the getClosestT(Vertex) function.
2593
2735
  * @modified 2020-12-29 Constructor is now private (no explicit use intended).
2594
2736
  * @modified 2021-05-25 Added BezierPath.fromReducedList( Array<number> ).
2595
- * @version 2.3.1
2737
+ * @modified 2022-01-31 Added `BezierPath.getEvenDistributionVertices(number)`.
2738
+ * @modified 2022-02-02 Added the `destroy` method.
2739
+ * @modified 2022-02-02 Cleared the `toSVGString` function (deprecated). Use `drawutilssvg` instead.
2740
+ * @version 2.5.0
2596
2741
  *
2597
2742
  * @file BezierPath
2598
2743
  * @public
@@ -3021,6 +3166,35 @@ class BezierPath {
3021
3166
  this.updateArcLengths();
3022
3167
  return this;
3023
3168
  }
3169
+ /**
3170
+ * Scale the whole bezier path by the given uniform factor.
3171
+ *
3172
+ * @method scale
3173
+ * @param {Vertex} anchor - The scale origin to scale from.
3174
+ * @param {number} scaleFactor - The scalar to be multiplied with.
3175
+ * @instance
3176
+ * @memberof BezierPath
3177
+ * @return {BezierPath} this for chaining.
3178
+ **/
3179
+ scale(anchor, scaleFactor) {
3180
+ // var scaleFactors : XYCoords = { x : scaleFactor, y : scaleFactor };
3181
+ // for (var i = 0; i < this.bezierCurves.length; i++) {
3182
+ // var curve = this.bezierCurves[i];
3183
+ // curve.getStartPoint().scale(scaleFactor, anchor);
3184
+ // curve.getStartControlPoint().scale(scaleFactor, anchor);
3185
+ // curve.getEndControlPoint().scale(scaleFactor, anchor);
3186
+ // // Do NOT scale the end point here!
3187
+ // // Don't forget that the curves are connected and on curve's end point
3188
+ // // the the successor's start point (same instance)!
3189
+ // }
3190
+ // // Finally move the last end point (was not scaled yet)
3191
+ // if (this.bezierCurves.length > 0 && !this.adjustCircular) {
3192
+ // this.bezierCurves[this.bezierCurves.length - 1].getEndPoint().scale(scaleFactor, anchor);
3193
+ // }
3194
+ // this.updateArcLengths();
3195
+ // return this;
3196
+ return this.scaleXY({ x: scaleFactor, y: scaleFactor }, anchor);
3197
+ }
3024
3198
  /**
3025
3199
  * Scale the whole bezier path by the given (x,y)-factors.
3026
3200
  *
@@ -3031,19 +3205,19 @@ class BezierPath {
3031
3205
  * @memberof BezierPath
3032
3206
  * @return {BezierPath} this for chaining.
3033
3207
  **/
3034
- scale(anchor, scaling) {
3208
+ scaleXY(scaleFactors, anchor) {
3035
3209
  for (var i = 0; i < this.bezierCurves.length; i++) {
3036
3210
  var curve = this.bezierCurves[i];
3037
- curve.getStartPoint().scale(scaling, anchor);
3038
- curve.getStartControlPoint().scale(scaling, anchor);
3039
- curve.getEndControlPoint().scale(scaling, anchor);
3211
+ curve.getStartPoint().scaleXY(scaleFactors, anchor);
3212
+ curve.getStartControlPoint().scaleXY(scaleFactors, anchor);
3213
+ curve.getEndControlPoint().scaleXY(scaleFactors, anchor);
3040
3214
  // Do NOT scale the end point here!
3041
3215
  // Don't forget that the curves are connected and on curve's end point
3042
3216
  // the the successor's start point (same instance)!
3043
3217
  }
3044
3218
  // Finally move the last end point (was not scaled yet)
3045
3219
  if (this.bezierCurves.length > 0 && !this.adjustCircular) {
3046
- this.bezierCurves[this.bezierCurves.length - 1].getEndPoint().scale(scaling, anchor);
3220
+ this.bezierCurves[this.bezierCurves.length - 1].getEndPoint().scaleXY(scaleFactors, anchor);
3047
3221
  }
3048
3222
  this.updateArcLengths();
3049
3223
  return this;
@@ -3452,6 +3626,59 @@ class BezierPath {
3452
3626
  }
3453
3627
  return new Bounds(min, max);
3454
3628
  }
3629
+ /**
3630
+ * Get n 'equally' distributed vertices along this Bézier path.
3631
+ *
3632
+ * As the changing curvature of the B slines makes prediction of distances difficult, the
3633
+ * returned vertices' distances are only relatively equal:
3634
+ * - the distance grows where curvature is large.
3635
+ * - the distance shrinks where curvature is small.
3636
+ *
3637
+ * Only the distance mean of all consecutive is 1/n-th of the total arc length.
3638
+ *
3639
+ * Usually this approximation is good enough for most use cases.
3640
+ *
3641
+ * @param {number} pointCount - (must be at least 2) The number of desired points (start and end point included).
3642
+ * @return {Array<Vertex>}
3643
+ */
3644
+ getEvenDistributionVertices(pointCount) {
3645
+ if (pointCount < 2) {
3646
+ throw new Error("pointCount must be larger than one; is " + pointCount + ".");
3647
+ }
3648
+ const result = [];
3649
+ if (this.bezierCurves.length === 0) {
3650
+ return result;
3651
+ }
3652
+ // Fetch and add the start point from the source polygon
3653
+ var polygonPoint = new Vertex(this.bezierCurves[0].startPoint);
3654
+ result.push(polygonPoint);
3655
+ // if (this.bezierCurves.length === 1) {
3656
+ // return result;
3657
+ // }
3658
+ const perimeter = this.totalArcLength;
3659
+ const stepSize = perimeter / (pointCount - 1);
3660
+ const n = this.bezierCurves.length;
3661
+ let curveIndex = 0;
3662
+ let segmentLength = this.bezierCurves[0].arcLength;
3663
+ let curSegmentU = stepSize;
3664
+ let i = 1;
3665
+ while (i < pointCount && curveIndex < n) {
3666
+ // Check if next eq point is inside this segment
3667
+ if (curSegmentU < segmentLength) {
3668
+ var newPoint = this.bezierCurves[curveIndex].getPoint(curSegmentU);
3669
+ result.push(newPoint);
3670
+ curSegmentU += stepSize;
3671
+ i++;
3672
+ }
3673
+ else {
3674
+ curveIndex++;
3675
+ curSegmentU = curSegmentU - segmentLength;
3676
+ segmentLength = curveIndex < n ? this.bezierCurves[curveIndex].arcLength : 0;
3677
+ }
3678
+ }
3679
+ result.push(new Vertex(this.bezierCurves[n - 1].endPoint));
3680
+ return result;
3681
+ }
3455
3682
  /**
3456
3683
  * Clone this BezierPath (deep clone).
3457
3684
  *
@@ -3509,19 +3736,30 @@ class BezierPath {
3509
3736
  * @return {string} The SVG string.
3510
3737
  **/
3511
3738
  toSVGString(options) {
3512
- options = options || {};
3513
- var buffer = [];
3514
- buffer.push("<path");
3515
- if (options.className)
3516
- buffer.push(' class="' + options.className + '"');
3517
- buffer.push(' d="');
3518
- for (var c = 0; c < this.bezierCurves.length; c++) {
3519
- if (c > 0)
3520
- buffer.push(" ");
3521
- buffer.push(this.bezierCurves[c].toSVGPathData());
3739
+ // options = options || {};
3740
+ // var buffer: Array<string> = [];
3741
+ // buffer.push("<path");
3742
+ // if (options.className) buffer.push(' class="' + options.className + '"');
3743
+ // buffer.push(' d="');
3744
+ // for (var c = 0; c < this.bezierCurves.length; c++) {
3745
+ // if (c > 0) buffer.push(" ");
3746
+ // buffer.push(this.bezierCurves[c].toSVGPathData());
3747
+ // }
3748
+ // buffer.push('" />');
3749
+ // return buffer.join("");
3750
+ console.warn("[Deprecation] Warning: the BezierPath.toSVGString method is deprecated and does not return and valid SVG data any more. Please use `drawutilssvg` instead.");
3751
+ return "";
3752
+ }
3753
+ /**
3754
+ * This function should invalidate any installed listeners and invalidate this object.
3755
+ * After calling this function the object might not hold valid data any more and
3756
+ * should not be used.
3757
+ */
3758
+ destroy() {
3759
+ for (var i = 0; i < this.bezierCurves.length; i++) {
3760
+ this.bezierCurves[i].destroy();
3522
3761
  }
3523
- buffer.push('" />');
3524
- return buffer.join("");
3762
+ this.isDestroyed = true;
3525
3763
  }
3526
3764
  /**
3527
3765
  * Create a JSON string representation of this bézier curve.
@@ -3748,7 +3986,8 @@ BezierPath.END_POINT = 3;
3748
3986
  * @modified 2020-03-16 The Line.angle(Line) parameter is now optional. The baseline (x-axis) will be used if not defined.
3749
3987
  * @modified 2020-03-23 Ported to Typescript from JS.
3750
3988
  * @modified 2020-12-04 The `intersection` function returns undefined if both lines are parallel.
3751
- * @version 2.1.3
3989
+ * @modified 2022-02-02 Added the `destroy` method.
3990
+ * @version 2.2.0
3752
3991
  *
3753
3992
  * @file Line
3754
3993
  * @public
@@ -3793,20 +4032,19 @@ class Line extends VertTuple {
3793
4032
  return null;
3794
4033
  let a = this.a.y - line.a.y;
3795
4034
  let b = this.a.x - line.a.x;
3796
- const numerator1 = ((line.b.x - line.a.x) * a) - ((line.b.y - line.a.y) * b);
3797
- const numerator2 = ((this.b.x - this.a.x) * a) - ((this.b.y - this.a.y) * b);
4035
+ const numerator1 = (line.b.x - line.a.x) * a - (line.b.y - line.a.y) * b;
4036
+ const numerator2 = (this.b.x - this.a.x) * a - (this.b.y - this.a.y) * b;
3798
4037
  a = numerator1 / denominator; // NaN if parallel lines
3799
4038
  b = numerator2 / denominator;
3800
4039
  // Catch NaN?
3801
- const x = this.a.x + (a * (this.b.x - this.a.x));
3802
- const y = this.a.y + (a * (this.b.y - this.a.y));
4040
+ const x = this.a.x + a * (this.b.x - this.a.x);
4041
+ const y = this.a.y + a * (this.b.y - this.a.y);
3803
4042
  if (isNaN(a) || isNaN(x) || isNaN(y)) {
3804
4043
  return undefined;
3805
4044
  }
3806
4045
  // if we cast these lines infinitely in both directions, they intersect here:
3807
4046
  return new Vertex(x, y);
3808
4047
  }
3809
- ;
3810
4048
  /**
3811
4049
  * Create an SVG representation of this line.
3812
4050
  *
@@ -3819,19 +4057,20 @@ class Line extends VertTuple {
3819
4057
  * @memberof Line
3820
4058
  **/
3821
4059
  toSVGString(options) {
3822
- options = options || {};
3823
- var buffer = [];
3824
- buffer.push('<line');
3825
- if (options.className)
3826
- buffer.push(' class="' + options.className + '"');
3827
- buffer.push(' x1="' + this.a.x + '"');
3828
- buffer.push(' y1="' + this.a.y + '"');
3829
- buffer.push(' x2="' + this.b.x + '"');
3830
- buffer.push(' y2="' + this.b.y + '"');
3831
- buffer.push(' />');
3832
- return buffer.join('');
4060
+ // options = options || {};
4061
+ // var buffer = [];
4062
+ // buffer.push( '<line' );
4063
+ // if( options.className )
4064
+ // buffer.push( ' class="' + options.className + '"' );
4065
+ // buffer.push( ' x1="' + this.a.x + '"' );
4066
+ // buffer.push( ' y1="' + this.a.y + '"' );
4067
+ // buffer.push( ' x2="' + this.b.x + '"' );
4068
+ // buffer.push( ' y2="' + this.b.y + '"' );
4069
+ // buffer.push( ' />' );
4070
+ // return buffer.join('');
4071
+ console.warn("[Deprecation] Warning: the Line.toSVGString method is deprecated and does not return and valid SVG data any more. Please use `drawutilssvg` instead.");
4072
+ return "";
3833
4073
  }
3834
- ;
3835
4074
  }
3836
4075
 
3837
4076
  /**
@@ -3843,7 +4082,9 @@ class Line extends VertTuple {
3843
4082
  * @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.
3844
4083
  * @modified 2020-10-16 Added the containsCircle(...) function.
3845
4084
  * @modified 2021-01-20 Added UID.
3846
- * @version 1.2.0
4085
+ * @modified 2022-02-02 Added the `destroy` method.
4086
+ * @modified 2022-02-02 Cleared the `toSVGString` function (deprecated). Use `drawutilssvg` instead.
4087
+ * @version 1.3.0
3847
4088
  **/
3848
4089
  /**
3849
4090
  * @classdesc A simple circle: center point and radius.
@@ -3874,7 +4115,6 @@ class Circle {
3874
4115
  this.center = center;
3875
4116
  this.radius = radius;
3876
4117
  }
3877
- ;
3878
4118
  /**
3879
4119
  * Check if the given circle is fully contained inside this circle.
3880
4120
  *
@@ -3887,7 +4127,6 @@ class Circle {
3887
4127
  containsCircle(circle) {
3888
4128
  return this.center.distance(circle.center) + circle.radius < this.radius;
3889
4129
  }
3890
- ;
3891
4130
  /**
3892
4131
  * Calculate the distance from this circle to the given line.
3893
4132
  *
@@ -3906,7 +4145,6 @@ class Circle {
3906
4145
  const closestPointOnLine = line.getClosestPoint(this.center);
3907
4146
  return closestPointOnLine.distance(this.center) - this.radius;
3908
4147
  }
3909
- ;
3910
4148
  /**
3911
4149
  * Get the vertex on the this circle for the given angle.
3912
4150
  *
@@ -3920,7 +4158,6 @@ class Circle {
3920
4158
  // Find the point on the circle respective the angle. Then move relative to center.
3921
4159
  return Circle.circleUtils.vertAt(angle, this.radius).add(this.center);
3922
4160
  }
3923
- ;
3924
4161
  /**
3925
4162
  * Get a tangent line of this circle for a given angle.
3926
4163
  *
@@ -3937,7 +4174,6 @@ class Circle {
3937
4174
  // Construct the perpendicular of the line in point a. Then move relative to center.
3938
4175
  return new Vector(pointA, new Vertex(0, 0)).add(this.center).perp();
3939
4176
  }
3940
- ;
3941
4177
  /**
3942
4178
  * Calculate the intersection points (if exists) with the given circle.
3943
4179
  *
@@ -3977,48 +4213,56 @@ class Circle {
3977
4213
  // x4 = P2.x - h*(P1.y - P0.y)/d;
3978
4214
  // y4 = P2.y + h*(P1.x - P0.x)/d;
3979
4215
  // return pair<Point, Point>(Point(x3, y3), Point(x4, y4));
3980
- // }
4216
+ // }
3981
4217
  var p0 = this.center;
3982
4218
  var p1 = circle.center;
3983
4219
  var d = p0.distance(p1);
3984
4220
  var a = (this.radius * this.radius - circle.radius * circle.radius + d * d) / (2 * d);
3985
4221
  var h = Math.sqrt(this.radius * this.radius - a * a);
3986
4222
  var p2 = p1.clone().scale(a / d, p0);
3987
- var x3 = p2.x + h * (p1.y - p0.y) / d;
3988
- var y3 = p2.y - h * (p1.x - p0.x) / d;
3989
- var x4 = p2.x - h * (p1.y - p0.y) / d;
3990
- var y4 = p2.y + h * (p1.x - p0.x) / d;
4223
+ var x3 = p2.x + (h * (p1.y - p0.y)) / d;
4224
+ var y3 = p2.y - (h * (p1.x - p0.x)) / d;
4225
+ var x4 = p2.x - (h * (p1.y - p0.y)) / d;
4226
+ var y4 = p2.y + (h * (p1.x - p0.x)) / d;
3991
4227
  return new Line(new Vertex(x3, y3), new Vertex(x4, y4));
3992
4228
  }
3993
- ;
3994
4229
  /**
3995
- * Create an SVG representation of this circle.
3996
- *
3997
- * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
3998
- * @method toSVGString
3999
- * @param {object=} options - An optional set of options, like 'className'.
4000
- * @return {string} A string representing the SVG code for this vertex.
4001
- * @instance
4002
- * @memberof Circle
4003
- */
4230
+ * Create an SVG representation of this circle.
4231
+ *
4232
+ * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
4233
+ * @method toSVGString
4234
+ * @param {object=} options - An optional set of options, like 'className'.
4235
+ * @return {string} A string representing the SVG code for this vertex.
4236
+ * @instance
4237
+ * @memberof Circle
4238
+ */
4004
4239
  toSVGString(options) {
4005
- options = options || {};
4006
- var buffer = [];
4007
- buffer.push('<circle');
4008
- if (options.className)
4009
- buffer.push(' class="' + options.className + '"');
4010
- buffer.push(' cx="' + this.center.x + '"');
4011
- buffer.push(' cy="' + this.center.y + '"');
4012
- buffer.push(' r="' + this.radius + '"');
4013
- buffer.push(' />');
4014
- return buffer.join('');
4240
+ // options = options || {};
4241
+ // var buffer: Array<string> = [];
4242
+ // buffer.push("<circle");
4243
+ // if (options.className) buffer.push(' class="' + options.className + '"');
4244
+ // buffer.push(' cx="' + this.center.x + '"');
4245
+ // buffer.push(' cy="' + this.center.y + '"');
4246
+ // buffer.push(' r="' + this.radius + '"');
4247
+ // buffer.push(" />");
4248
+ // return buffer.join("");
4249
+ console.warn("[Deprecation] Warning: the Circle.toSVGString method is deprecated and does not return and valid SVG data any more. Please use `drawutilssvg` instead.");
4250
+ return "";
4251
+ }
4252
+ /**
4253
+ * This function should invalidate any installed listeners and invalidate this object.
4254
+ * After calling this function the object might not hold valid data any more and
4255
+ * should not be used.
4256
+ */
4257
+ destroy() {
4258
+ this.center.destroy();
4259
+ this.isDestroyed = true;
4015
4260
  }
4016
- ;
4017
4261
  } // END class
4018
4262
  Circle.circleUtils = {
4019
4263
  vertAt: (angle, radius) => {
4020
4264
  /* return new Vertex( Math.sin(angle) * radius,
4021
- Math.cos(angle) * radius ); */
4265
+ Math.cos(angle) * radius ); */
4022
4266
  return new Vertex(Math.cos(angle) * radius, Math.sin(angle) * radius);
4023
4267
  }
4024
4268
  };
@@ -4059,27 +4303,42 @@ class CircleSector {
4059
4303
  this.startAngle = startAngle;
4060
4304
  this.endAngle = endAngle;
4061
4305
  }
4062
- ;
4063
4306
  /**
4064
- * Create an SVG representation of this circle.
4065
- *
4066
- * @method toSVGString
4067
- * @param {object=} options - An optional set of options, like 'className'.
4068
- * @return {string} A string representing the SVG code for this vertex.
4069
- * @instance
4070
- * @memberof Circle
4071
- */
4307
+ * Create an SVG representation of this circle.
4308
+ *
4309
+ * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
4310
+ * @method toSVGString
4311
+ * @param {object=} options - An optional set of options, like 'className'.
4312
+ * @return {string} A string representing the SVG code for this vertex.
4313
+ * @instance
4314
+ * @memberof Circle
4315
+ */
4072
4316
  toSVGString(options) {
4073
- options = options || {};
4074
- var buffer = [];
4075
- buffer.push('<path ');
4076
- if (options.className)
4077
- buffer.push(' class="' + options.className + '"');
4078
- const data = CircleSector.circleSectorUtils.describeSVGArc(this.circle.center.x, this.circle.center.y, this.circle.radius, this.startAngle, this.endAngle);
4079
- buffer.push(' d="' + data.join(" ") + '" />');
4080
- return buffer.join('');
4317
+ // options = options || {};
4318
+ // var buffer: Array<string> = [];
4319
+ // buffer.push("<path ");
4320
+ // if (options.className) buffer.push(' class="' + options.className + '"');
4321
+ // const data: SVGPathParams = CircleSector.circleSectorUtils.describeSVGArc(
4322
+ // this.circle.center.x,
4323
+ // this.circle.center.y,
4324
+ // this.circle.radius,
4325
+ // this.startAngle,
4326
+ // this.endAngle
4327
+ // );
4328
+ // buffer.push(' d="' + data.join(" ") + '" />');
4329
+ // return buffer.join("");
4330
+ console.warn("[Deprecation] Warning: the CircleSector.toSVGString method is deprecated and does not return and valid SVG data any more. Please use `drawutilssvg` instead.");
4331
+ return "";
4332
+ }
4333
+ /**
4334
+ * This function should invalidate any installed listeners and invalidate this object.
4335
+ * After calling this function the object might not hold valid data any more and
4336
+ * should not be used.
4337
+ */
4338
+ destroy() {
4339
+ this.circle.destroy();
4340
+ this.isDestroyed = true;
4081
4341
  }
4082
- ;
4083
4342
  } // END class
4084
4343
  CircleSector.circleSectorUtils = {
4085
4344
  /**
@@ -4088,11 +4347,11 @@ CircleSector.circleSectorUtils = {
4088
4347
  * TODO: generalize for ellipses (two radii).
4089
4348
  *
4090
4349
  * @param {number} angle - The angle in radians.
4091
- */
4350
+ */
4092
4351
  polarToCartesian: (centerX, centerY, radius, angle) => {
4093
4352
  return {
4094
- x: centerX + (radius * Math.cos(angle)),
4095
- y: centerY + (radius * Math.sin(angle))
4353
+ x: centerX + radius * Math.cos(angle),
4354
+ y: centerY + radius * Math.sin(angle)
4096
4355
  };
4097
4356
  },
4098
4357
  /**
@@ -4105,7 +4364,7 @@ CircleSector.circleSectorUtils = {
4105
4364
  * @return [ 'A', radiusx, radiusy, rotation=0, largeArcFlag=1|0, sweepFlag=0, endx, endy ]
4106
4365
  */
4107
4366
  describeSVGArc: (x, y, radius, startAngle, endAngle, options) => {
4108
- if (typeof options === 'undefined')
4367
+ if (typeof options === "undefined")
4109
4368
  options = { moveToStart: true };
4110
4369
  const end = CircleSector.circleSectorUtils.polarToCartesian(x, y, radius, endAngle);
4111
4370
  const start = CircleSector.circleSectorUtils.polarToCartesian(x, y, radius, startAngle);
@@ -4130,7 +4389,7 @@ CircleSector.circleSectorUtils = {
4130
4389
  }
4131
4390
  const pathData = [];
4132
4391
  if (options.moveToStart) {
4133
- pathData.push('M', start.x, start.y);
4392
+ pathData.push("M", start.x, start.y);
4134
4393
  }
4135
4394
  pathData.push("A", radius, radius, 0, largeArcFlag, sweepFlag, end.x, end.y);
4136
4395
  return pathData;
@@ -4165,8 +4424,12 @@ CircleSector.circleSectorUtils = {
4165
4424
  * @modified 2021-03-31 Added 'ellipseSector' the the class names.
4166
4425
  * @modified 2021-03-31 Implemented buffering using a buffer <g> node and the beginDrawCycle and endDrawCycle methods.
4167
4426
  * @modified 2021-05-31 Added the `setConfiguration` function from `DrawLib`.
4168
- * @version 1.3.0
4427
+ * @modified 2021-11-15 Adding more parameters tot the `text()` function: fontSize, textAlign, fontFamily, lineHeight.
4428
+ * @modified 2021-11-19 Fixing the `label(text,x,y)` position.
4429
+ * @modified 2021-11-19 Added the `color` param to the `label(...)` function.
4430
+ * @version 1.4.0
4169
4431
  **/
4432
+ const RAD_TO_DEG = 180 / Math.PI;
4170
4433
  /**
4171
4434
  * @classdesc A helper class for basic SVG drawing operations. This class should
4172
4435
  * be compatible to the default 'draw' class.
@@ -4226,7 +4489,8 @@ class drawutilssvg {
4226
4489
  "vertex": "Vertex",
4227
4490
  "line": "Line",
4228
4491
  "vector": "Vector",
4229
- "image": "Image"
4492
+ "image": "Image",
4493
+ "text": "Text"
4230
4494
  };
4231
4495
  // Question: why isn't this working if the svgNode is created dynamically? (nodeStyle.sheet is null)
4232
4496
  const rules = [];
@@ -5006,27 +5270,65 @@ class drawutilssvg {
5006
5270
  if (!isOpen)
5007
5271
  d.push("Z");
5008
5272
  node.setAttribute("d", d.join(" "));
5009
- return this._bindFillDraw(node, "polyline", color, lineWidth || 1);
5273
+ return this._bindFillDraw(node, "polygon", color, lineWidth || 1);
5010
5274
  }
5011
5275
  /**
5012
- * Draw a text label at the given relative position.
5276
+ * Draw a text at the given relative position.
5013
5277
  *
5014
- * @method label
5278
+ * @method text
5015
5279
  * @param {string} text - The text to draw.
5016
5280
  * @param {number} x - The x-position to draw the text at.
5017
5281
  * @param {number} y - The y-position to draw the text at.
5018
- * @param {number=} rotation - The (optional) rotation in radians.
5282
+ * @param {string=} options.color - The Color to use.
5283
+ * @param {string=} options.fontFamily - The font family to use.
5284
+ * @param {number=} options.fontSize - The font size (in pixels) to use.
5285
+ * @param {FontStyle=} options.fontStyle - The font style to use.
5286
+ * @param {FontWeight=} options.fontWeight - The font weight to use.
5287
+ * @param {number=} options.lineHeight - The line height (in pixels) to use.
5288
+ * @param {number=} options.rotation - The (optional) rotation in radians.
5289
+ * @param {string=} options.textAlign - The text align to use. According to the specifiactions (https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign) valid values are `"left" || "right" || "center" || "start" || "end"`.
5019
5290
  * @return {void}
5020
5291
  * @instance
5021
- * @memberof drawutilssvg
5292
+ * @memberof drawutils
5022
5293
  */
5023
5294
  text(text, x, y, options) {
5295
+ var _a, _b;
5024
5296
  options = options || {};
5025
5297
  const color = options.color || "black";
5026
- const node = this.makeNode("text");
5027
- node.setAttribute("x", `${this._x(x)}`);
5028
- node.setAttribute("y", `${this._y(y)}`);
5029
- node.innerHTML = text;
5298
+ const lineHeight = ((_b = (_a = options.lineHeight) !== null && _a !== void 0 ? _a : options.fontSize) !== null && _b !== void 0 ? _b : 0) * this.scale.x;
5299
+ // https://www.w3.org/TR/SVG/text.html#TextAnchorProperty
5300
+ // start | middle | end
5301
+ const textAlign = options.textAlign === "left" || options.textAlign === "start"
5302
+ ? "start"
5303
+ : options.textAlign === "center"
5304
+ ? "middle"
5305
+ : options.textAlign === "right" || options.textAlign === "end"
5306
+ ? "end"
5307
+ : "start";
5308
+ const transformOrigin = `${this._x(x)}px ${this._y(y)}px`;
5309
+ const translate = `translate(${this._x(x)} ${this._y(y) + lineHeight / 2})`;
5310
+ // Safari has a transform-origin/rotation bug.
5311
+ // It's essential to use rotate(r,x,y) here. "rotate(r)"" with transform-origin(x,y) won't do the job.
5312
+ // And rotate and translate cannot be used is combination on a text object.
5313
+ // So wrap the text inside a <g>, translate the <g>, and rotate the text inside.
5314
+ const rotate = options.rotation ? `rotate(${options.rotation * RAD_TO_DEG} 0 0)` : ``;
5315
+ const node = this.makeNode("g");
5316
+ const curId = this.curId;
5317
+ this.curId = curId + "_text";
5318
+ const textNode = this.makeNode("text");
5319
+ node.appendChild(textNode);
5320
+ textNode.setAttribute("font-family", options.fontFamily); // May be undefined
5321
+ textNode.setAttribute("font-size", options.fontSize ? `${options.fontSize * this.scale.x}` : null);
5322
+ textNode.setAttribute("font-style", options.fontStyle ? `${options.fontStyle}` : null);
5323
+ textNode.setAttribute("font-weight", options.fontWeight ? `${options.fontWeight}` : null);
5324
+ textNode.setAttribute("text-anchor", textAlign);
5325
+ textNode.setAttribute("transform-origin", "0 0");
5326
+ textNode.setAttribute("transform", rotate);
5327
+ node.setAttribute("transform-origin", transformOrigin);
5328
+ node.setAttribute("transform", translate);
5329
+ textNode.innerHTML = text;
5330
+ // Restore old ID
5331
+ this.curId = curId;
5030
5332
  return this._bindFillDraw(node, "text", color, 1);
5031
5333
  }
5032
5334
  /**
@@ -5037,16 +5339,21 @@ class drawutilssvg {
5037
5339
  * @param {number} x - The x-position to draw the text at.
5038
5340
  * @param {number} y - The y-position to draw the text at.
5039
5341
  * @param {number=} rotation - The (optional) rotation in radians.
5342
+ * @param {string="black"} color - The color to use (default is black).
5040
5343
  * @return {void}
5041
5344
  * @instance
5042
5345
  * @memberof drawutilssvg
5043
5346
  */
5044
- label(text, x, y, rotation) {
5347
+ label(text, x, y, rotation, color) {
5045
5348
  const node = this.makeNode("text");
5046
5349
  // For some strange reason SVG rotation transforms use degrees instead of radians
5047
- node.setAttribute("transform", `translate(${this.offset.x},${this.offset.y}), rotate(${(rotation / Math.PI) * 180})`);
5350
+ node.setAttribute("transform", `translate(${x},${y}), rotate(${((rotation || 0) / Math.PI) * 180})`);
5351
+ node.setAttribute("font-family", "Arial");
5352
+ node.setAttribute("font-size", "9pt");
5353
+ node.setAttribute("font-style", "normal");
5354
+ node.setAttribute("font-weight", "lighter");
5048
5355
  node.innerHTML = text;
5049
- return this._bindFillDraw(node, "label", "black", null);
5356
+ return this._bindFillDraw(node, "label", color || "black", null);
5050
5357
  }
5051
5358
  /**
5052
5359
  * Draw an SVG-like path given by the specified path data.
@@ -5355,7 +5662,9 @@ drawutilssvg.HEAD_XML = [
5355
5662
  * @modified 2021-02-22 Added the `path` drawing function to draw SVG path data.
5356
5663
  * @modified 2021-03-31 Added the `endDrawCycle` function from `DrawLib`.
5357
5664
  * @modified 2021-05-31 Added the `setConfiguration` function from `DrawLib`.
5358
- * @version 1.9.0
5665
+ * @modified 2021-11-12 Adding more parameters tot the `text()` function: fontSize, textAlign, fontFamily, lineHeight.
5666
+ * @modified 2021-11-19 Added the `color` param to the `label(...)` function.
5667
+ * @version 1.10.0
5359
5668
  **/
5360
5669
  // Todo: rename this class to Drawutils?
5361
5670
  /**
@@ -6010,20 +6319,62 @@ class drawutils {
6010
6319
  this.ctx.setLineDash([]);
6011
6320
  this.ctx.restore();
6012
6321
  }
6322
+ /**
6323
+ * Draw a text at the given relative position.
6324
+ *
6325
+ * @method text
6326
+ * @param {string} text - The text to draw.
6327
+ * @param {number} x - The x-position to draw the text at.
6328
+ * @param {number} y - The y-position to draw the text at.
6329
+ * @param {string=} options.color - The Color to use.
6330
+ * @param {string=} options.fontFamily - The font family to use.
6331
+ * @param {number=} options.fontSize - The font size (in pixels) to use.
6332
+ * @param {FontStyle=} options.fontStyle - The font style to use.
6333
+ * @param {FontWeight=} options.fontWeight - The font weight to use.
6334
+ * @param {number=} options.lineHeight - The line height (in pixels) to use.
6335
+ * @param {number=} options.rotation - The (optional) rotation in radians.
6336
+ * @param {string=} options.textAlign - The text align to use. According to the specifiactions (https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign) valid values are `"left" || "right" || "center" || "start" || "end"`.
6337
+ * @return {void}
6338
+ * @instance
6339
+ * @memberof drawutils
6340
+ */
6013
6341
  text(text, x, y, options) {
6342
+ // See https://stackoverflow.com/a/23523697
6343
+ var _a, _b, _c;
6014
6344
  options = options || {};
6015
6345
  this.ctx.save();
6016
- x = this.offset.x + x * this.scale.x;
6017
- y = this.offset.y + y * this.scale.y;
6346
+ let relX = this.offset.x + x * this.scale.x;
6347
+ let relY = this.offset.y + y * this.scale.y;
6018
6348
  const color = options.color || "black";
6349
+ if (options.fontSize || options.fontFamily) {
6350
+ // Scaling of text only works in uniform mode
6351
+ this.ctx.font =
6352
+ (options.fontWeight ? options.fontWeight + " " : "") +
6353
+ (options.fontStyle ? options.fontStyle + " " : "") +
6354
+ (options.fontSize ? options.fontSize * this.scale.x + "px " : " ") +
6355
+ (options.fontFamily
6356
+ ? options.fontFamily.indexOf(" ") === -1
6357
+ ? options.fontFamily
6358
+ : `"${options.fontFamily}"`
6359
+ : "Arial");
6360
+ }
6361
+ if (options.textAlign) {
6362
+ this.ctx.textAlign = options.textAlign;
6363
+ }
6364
+ const rotation = (_a = options.rotation) !== null && _a !== void 0 ? _a : 0.0;
6365
+ const lineHeight = ((_c = (_b = options.lineHeight) !== null && _b !== void 0 ? _b : options.fontSize) !== null && _c !== void 0 ? _c : 0) * this.scale.x;
6366
+ this.ctx.translate(relX, relY);
6367
+ this.ctx.rotate(rotation);
6019
6368
  if (this.fillShapes) {
6020
6369
  this.ctx.fillStyle = color;
6021
- this.ctx.fillText(text, x, y);
6370
+ this.ctx.fillText(text, 0, lineHeight / 2);
6022
6371
  }
6023
6372
  else {
6024
6373
  this.ctx.strokeStyle = color;
6025
- this.ctx.strokeText(text, x, y);
6374
+ this.ctx.strokeText(text, 0, lineHeight / 2);
6026
6375
  }
6376
+ // this.ctx.translate(-relX, -relY);
6377
+ // this.ctx.rotate(-rotation); // is this necessary before 'restore()'?
6027
6378
  this.ctx.restore();
6028
6379
  }
6029
6380
  /**
@@ -6043,8 +6394,9 @@ class drawutils {
6043
6394
  */
6044
6395
  label(text, x, y, rotation, color) {
6045
6396
  this.ctx.save();
6397
+ this.ctx.font = "lighter 9pt Arial";
6046
6398
  this.ctx.translate(x, y);
6047
- if (typeof rotation != "undefined")
6399
+ if (typeof rotation !== "undefined")
6048
6400
  this.ctx.rotate(rotation);
6049
6401
  this.ctx.fillStyle = color || "black";
6050
6402
  if (this.fillShapes) {
@@ -6653,6 +7005,25 @@ class drawutilsgl {
6653
7005
  polyline(vertices, isOpen, color, lineWidth) {
6654
7006
  // NOT YET IMPLEMENTED
6655
7007
  }
7008
+ /**
7009
+ * Draw a text at the given relative position.
7010
+ *
7011
+ * @method text
7012
+ * @param {string} text - The text to draw.
7013
+ * @param {number} x - The x-position to draw the text at.
7014
+ * @param {number} y - The y-position to draw the text at.
7015
+ * @param {string=} options.color - The Color to use.
7016
+ * @param {string=} options.fontFamily - The font family to use.
7017
+ * @param {number=} options.fontSize - The font size (in pixels) to use.
7018
+ * @param {FontStyle=} options.fontStyle - The font style to use.
7019
+ * @param {FontWeight=} options.fontWeight - The font weight to use.
7020
+ * @param {number=} options.lineHeight - The line height (in pixels) to use.
7021
+ * @param {number=} options.rotation - The (optional) rotation in radians.
7022
+ * @param {string=} options.textAlign - The text align to use. According to the specifiactions (https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign) valid values are `"left" || "right" || "center" || "start" || "end"`.
7023
+ * @return {void}
7024
+ * @instance
7025
+ * @memberof drawutils
7026
+ */
6656
7027
  text(text, x, y, options) {
6657
7028
  // NOT YET IMPLEMENTED
6658
7029
  }
@@ -6664,14 +7035,12 @@ class drawutilsgl {
6664
7035
  * @param {number} x - The x-position to draw the text at.
6665
7036
  * @param {number} y - The y-position to draw the text at.
6666
7037
  * @param {number=} rotation - The (aoptional) rotation in radians.
7038
+ * @param {string="black"} color - The color to use (default is black).
6667
7039
  * @return {void}
6668
7040
  * @instance
6669
7041
  * @memberof drawutils
6670
7042
  */
6671
- // +---------------------------------------------------------------------------------
6672
- // | Draw a non-scaling text label at the given position.
6673
- // +-------------------------------
6674
- label(text, x, y, rotation) {
7043
+ label(text, x, y, rotation, color) {
6675
7044
  // NOT YET IMPLEMENTED
6676
7045
  }
6677
7046
  /**
@@ -6810,7 +7179,9 @@ class GLU {
6810
7179
  * @modified 2020-12-28 Added the `getArea` function.
6811
7180
  * @modified 2021-01-20 Added UID.
6812
7181
  * @modified 2021-01-22 Always updating circumcircle when retieving it.
6813
- * @version 2.5.1
7182
+ * @modified 2022-02-02 Added the `destroy` method.
7183
+ * @modified 2022-02-02 Cleared the `Triangle.toSVGString` function (deprecated). Use `drawutilssvg` instead.
7184
+ * @version 2.6.0
6814
7185
  *
6815
7186
  * @file Triangle
6816
7187
  * @fileoverview A simple triangle class: three vertices.
@@ -6871,7 +7242,6 @@ class Triangle {
6871
7242
  throw `Cannot create triangle from array with less than three vertices (${arr.length})`;
6872
7243
  return new Triangle(arr[0], arr[1], arr[2]);
6873
7244
  }
6874
- ;
6875
7245
  /**
6876
7246
  * Get the area of this triangle. The returned area is never negative.
6877
7247
  *
@@ -6887,7 +7257,6 @@ class Triangle {
6887
7257
  getArea() {
6888
7258
  return Math.abs(Triangle.utils.signedArea(this.a.x, this.a.y, this.b.x, this.b.y, this.c.x, this.c.y));
6889
7259
  }
6890
- ;
6891
7260
  /**
6892
7261
  * Get the centroid of this triangle.
6893
7262
  *
@@ -6901,7 +7270,6 @@ class Triangle {
6901
7270
  getCentroid() {
6902
7271
  return new Vertex((this.a.x + this.b.x + this.c.x) / 3, (this.a.y + this.b.y + this.c.y) / 3);
6903
7272
  }
6904
- ;
6905
7273
  /**
6906
7274
  * Scale the triangle towards its centroid.
6907
7275
  *
@@ -6918,7 +7286,6 @@ class Triangle {
6918
7286
  this.c.scale(factor, centroid);
6919
7287
  return this;
6920
7288
  }
6921
- ;
6922
7289
  /**
6923
7290
  * Get the circumcircle of this triangle.
6924
7291
  *
@@ -6935,11 +7302,10 @@ class Triangle {
6935
7302
  * @memberof Triangle
6936
7303
  */
6937
7304
  getCircumcircle() {
6938
- // if( !this.center || !this.radius )
7305
+ // if( !this.center || !this.radius )
6939
7306
  this.calcCircumcircle();
6940
7307
  return new Circle(this.center.clone(), this.radius);
6941
7308
  }
6942
- ;
6943
7309
  /**
6944
7310
  * Check if this triangle and the passed triangle share an
6945
7311
  * adjacent edge.
@@ -6959,7 +7325,6 @@ class Triangle {
6959
7325
  var c = this.c.equals(tri.a) || this.c.equals(tri.b) || this.c.equals(tri.c);
6960
7326
  return (a && b) || (a && c) || (b && c);
6961
7327
  }
6962
- ;
6963
7328
  /**
6964
7329
  * Get that vertex of this triangle (a,b,c) that is not vert1 nor vert2 of
6965
7330
  * the passed two.
@@ -6972,14 +7337,13 @@ class Triangle {
6972
7337
  * @memberof Triangle
6973
7338
  */
6974
7339
  getThirdVertex(vert1, vert2) {
6975
- if (this.a.equals(vert1) && this.b.equals(vert2) || this.a.equals(vert2) && this.b.equals(vert1))
7340
+ if ((this.a.equals(vert1) && this.b.equals(vert2)) || (this.a.equals(vert2) && this.b.equals(vert1)))
6976
7341
  return this.c;
6977
- if (this.b.equals(vert1) && this.c.equals(vert2) || this.b.equals(vert2) && this.c.equals(vert1))
7342
+ if ((this.b.equals(vert1) && this.c.equals(vert2)) || (this.b.equals(vert2) && this.c.equals(vert1)))
6978
7343
  return this.a;
6979
7344
  //if( this.c.equals(vert1) && this.a.equals(vert2) || this.c.equals(vert2) && this.a.equals(vert1) )
6980
7345
  return this.b;
6981
7346
  }
6982
- ;
6983
7347
  /**
6984
7348
  * Re-compute the circumcircle of this triangle (if the vertices
6985
7349
  * have changed).
@@ -7019,8 +7383,7 @@ class Triangle {
7019
7383
  }
7020
7384
  this.radius_squared = dx * dx + dy * dy;
7021
7385
  this.radius = Math.sqrt(this.radius_squared);
7022
- }
7023
- ; // END calcCircumcircle
7386
+ } // END calcCircumcircle
7024
7387
  /**
7025
7388
  * Check if the passed vertex is inside this triangle's
7026
7389
  * circumcircle.
@@ -7035,9 +7398,8 @@ class Triangle {
7035
7398
  const dx = this.center.x - v.x;
7036
7399
  const dy = this.center.y - v.y;
7037
7400
  const dist_squared = dx * dx + dy * dy;
7038
- return (dist_squared <= this.radius_squared);
7401
+ return dist_squared <= this.radius_squared;
7039
7402
  }
7040
- ;
7041
7403
  /**
7042
7404
  * Get the rectangular bounds for this triangle.
7043
7405
  *
@@ -7049,7 +7411,6 @@ class Triangle {
7049
7411
  bounds() {
7050
7412
  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)));
7051
7413
  }
7052
- ;
7053
7414
  /**
7054
7415
  * Convert this triangle to a polygon instance.
7055
7416
  *
@@ -7063,7 +7424,6 @@ class Triangle {
7063
7424
  toPolygon() {
7064
7425
  return new Polygon([this.a, this.b, this.c]);
7065
7426
  }
7066
- ;
7067
7427
  /**
7068
7428
  * Get the determinant of this triangle.
7069
7429
  *
@@ -7076,7 +7436,6 @@ class Triangle {
7076
7436
  // (b.y - a.y)*(c.x - b.x) - (c.y - b.y)*(b.x - a.x);
7077
7437
  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);
7078
7438
  }
7079
- ;
7080
7439
  /**
7081
7440
  * Checks if the passed vertex (p) is inside this triangle.
7082
7441
  *
@@ -7091,7 +7450,6 @@ class Triangle {
7091
7450
  containsPoint(p) {
7092
7451
  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);
7093
7452
  }
7094
- ;
7095
7453
  /**
7096
7454
  * Get that inner triangle which defines the maximal incircle.
7097
7455
  *
@@ -7110,7 +7468,6 @@ class Triangle {
7110
7468
  const circleIntersC = lineC.getClosestPoint(intersection);
7111
7469
  return new Triangle(circleIntersA, circleIntersB, circleIntersC);
7112
7470
  }
7113
- ;
7114
7471
  /**
7115
7472
  * Get the incircle of this triangle. That is the circle that touches each side
7116
7473
  * of this triangle in exactly one point.
@@ -7122,7 +7479,6 @@ class Triangle {
7122
7479
  getIncircle() {
7123
7480
  return this.getIncircularTriangle().getCircumcircle();
7124
7481
  }
7125
- ;
7126
7482
  /**
7127
7483
  * Get the incenter of this triangle (which is the center of the circumcircle).
7128
7484
  *
@@ -7136,7 +7492,6 @@ class Triangle {
7136
7492
  this.calcCircumcircle();
7137
7493
  return this.center.clone();
7138
7494
  }
7139
- ;
7140
7495
  /**
7141
7496
  * Converts this triangle into a human-readable string.
7142
7497
  *
@@ -7146,9 +7501,8 @@ class Triangle {
7146
7501
  * @memberof Triangle
7147
7502
  */
7148
7503
  toString() {
7149
- return '{ a : ' + this.a.toString() + ', b : ' + this.b.toString() + ', c : ' + this.c.toString() + '}';
7504
+ return "{ a : " + this.a.toString() + ", b : " + this.b.toString() + ", c : " + this.c.toString() + "}";
7150
7505
  }
7151
- ;
7152
7506
  /**
7153
7507
  * Create an SVG representation of this triangle.
7154
7508
  *
@@ -7160,32 +7514,43 @@ class Triangle {
7160
7514
  * @memberof Triangle
7161
7515
  **/
7162
7516
  toSVGString(options) {
7163
- options = options || {};
7164
- var buffer = [];
7165
- buffer.push('<path');
7166
- if (options.className)
7167
- buffer.push(' class="' + options.className + '"');
7168
- buffer.push(' d="');
7169
- var vertices = [this.a, this.b, this.c];
7170
- if (vertices.length > 0) {
7171
- buffer.push('M ');
7172
- buffer.push(vertices[0].x);
7173
- buffer.push(' ');
7174
- buffer.push(vertices[0].y);
7175
- for (var i = 1; i < vertices.length; i++) {
7176
- buffer.push(' L ');
7177
- buffer.push(vertices[i].x);
7178
- buffer.push(' ');
7179
- buffer.push(vertices[i].y);
7180
- }
7181
- //if( !this.isOpen ) {
7182
- buffer.push(' Z');
7183
- //}
7184
- }
7185
- buffer.push('" />');
7186
- return buffer.join('');
7517
+ // options = options || {};
7518
+ // var buffer = [];
7519
+ // buffer.push("<path");
7520
+ // if (options.className) buffer.push(' class="' + options.className + '"');
7521
+ // buffer.push(' d="');
7522
+ // var vertices = [this.a, this.b, this.c];
7523
+ // if (vertices.length > 0) {
7524
+ // buffer.push("M ");
7525
+ // buffer.push(vertices[0].x);
7526
+ // buffer.push(" ");
7527
+ // buffer.push(vertices[0].y);
7528
+ // for (var i = 1; i < vertices.length; i++) {
7529
+ // buffer.push(" L ");
7530
+ // buffer.push(vertices[i].x);
7531
+ // buffer.push(" ");
7532
+ // buffer.push(vertices[i].y);
7533
+ // }
7534
+ // //if( !this.isOpen ) {
7535
+ // buffer.push(" Z");
7536
+ // //}
7537
+ // }
7538
+ // buffer.push('" />');
7539
+ // return buffer.join("");
7540
+ console.warn("[Deprecation] Warning: the Triangle.toSVGString method is deprecated and does not return and valid SVG data any more. Please use `drawutilssvg` instead.");
7541
+ return "";
7542
+ }
7543
+ /**
7544
+ * This function should invalidate any installed listeners and invalidate this object.
7545
+ * After calling this function the object might not hold valid data any more and
7546
+ * should not be used.
7547
+ */
7548
+ destroy() {
7549
+ this.a.destroy();
7550
+ this.b.destroy();
7551
+ this.c.destroy();
7552
+ this.isDestroyed = true;
7187
7553
  }
7188
- ;
7189
7554
  }
7190
7555
  /**
7191
7556
  * An epsilon for comparison.
@@ -7197,10 +7562,10 @@ Triangle.EPSILON = 1.0e-6;
7197
7562
  Triangle.utils = {
7198
7563
  // Used in the bounds() function.
7199
7564
  max3(a, b, c) {
7200
- return (a >= b && a >= c) ? a : (b >= a && b >= c) ? b : c;
7565
+ return a >= b && a >= c ? a : b >= a && b >= c ? b : c;
7201
7566
  },
7202
7567
  min3(a, b, c) {
7203
- return (a <= b && a <= c) ? a : (b <= a && b <= c) ? b : c;
7568
+ return a <= b && a <= c ? a : b <= a && b <= c ? b : c;
7204
7569
  },
7205
7570
  signedArea(p0x, p0y, p1x, p1y, p2x, p2y) {
7206
7571
  return 0.5 * (-p1y * p2x + p0y * (-p1x + p2x) + p0x * (p1y - p2y) + p1x * p2y);
@@ -7216,9 +7581,9 @@ Triangle.utils = {
7216
7581
  // http://stackoverflow.com/questions/2049582/how-to-determine-a-point-in-a-2d-triangle
7217
7582
  // var area : number = 1/2*(-p1y*p2x + p0y*(-p1x + p2x) + p0x*(p1y - p2y) + p1x*p2y);
7218
7583
  var area = Triangle.utils.signedArea(p0x, p0y, p1x, p1y, p2x, p2y);
7219
- var s = 1 / (2 * area) * (p0y * p2x - p0x * p2y + (p2y - p0y) * px + (p0x - p2x) * py);
7220
- var t = 1 / (2 * area) * (p0x * p1y - p0y * p1x + (p0y - p1y) * px + (p1x - p0x) * py);
7221
- return s > 0 && t > 0 && (1 - s - t) > 0;
7584
+ var s = (1 / (2 * area)) * (p0y * p2x - p0x * p2y + (p2y - p0y) * px + (p0x - p2x) * py);
7585
+ var t = (1 / (2 * area)) * (p0x * p1y - p0y * p1x + (p0y - p1y) * px + (p1x - p0x) * py);
7586
+ return s > 0 && t > 0 && 1 - s - t > 0;
7222
7587
  }
7223
7588
  };
7224
7589
 
@@ -7389,7 +7754,8 @@ Grid.utils = {
7389
7754
  * @modified 2020-07-28 Changed the `delete` key code from 8 to 46.
7390
7755
  * @modified 2020-10-04 Changed `window` to `globalThis`.
7391
7756
  * @modified 2020-10-04 Added extended JSDoc.
7392
- * @version 1.0.4
7757
+ * @modified 2022-02-02 Added the `destroy` method.
7758
+ * @version 1.1.0
7393
7759
  *
7394
7760
  * @file KeyHandler
7395
7761
  * @public
@@ -7420,7 +7786,7 @@ class KeyHandler {
7420
7786
  * @memberof KeyHandler
7421
7787
  * @param {HTMLElement} options.element (optional) The HTML element to listen on; if null then 'window' will be used.
7422
7788
  * @param {boolean} options.trackAll (optional) Set to true if you want to keep track of _all_ keys (keyStatus).
7423
- **/
7789
+ **/
7424
7790
  constructor(options) {
7425
7791
  this.downListeners = [];
7426
7792
  this.pressListeners = [];
@@ -7439,7 +7805,6 @@ class KeyHandler {
7439
7805
  // Install the listeners
7440
7806
  this.installListeners();
7441
7807
  }
7442
- ;
7443
7808
  /**
7444
7809
  * A helper function to fire key events from this KeyHandler.
7445
7810
  *
@@ -7457,7 +7822,6 @@ class KeyHandler {
7457
7822
  }
7458
7823
  return hasListener;
7459
7824
  }
7460
- ;
7461
7825
  /**
7462
7826
  * Internal function to fire a new keydown event to all listeners.
7463
7827
  * You should not call this function on your own unless you know what you do.
@@ -7473,10 +7837,9 @@ class KeyHandler {
7473
7837
  fireDownEvent(e, handler) {
7474
7838
  if (handler.fireEvent(e, handler.downListeners) || handler.trackAllKeys) {
7475
7839
  // Down event has listeners. Update key state.
7476
- handler.keyStates[e.keyCode] = 'down';
7840
+ handler.keyStates[e.keyCode] = "down";
7477
7841
  }
7478
7842
  }
7479
- ;
7480
7843
  /**
7481
7844
  * Internal function to fire a new keypress event to all listeners.
7482
7845
  * You should not call this function on your own unless you know what you do.
@@ -7492,7 +7855,6 @@ class KeyHandler {
7492
7855
  firePressEvent(e, handler) {
7493
7856
  handler.fireEvent(e, handler.pressListeners);
7494
7857
  }
7495
- ;
7496
7858
  /**
7497
7859
  * Internal function to fire a new keyup event to all listeners.
7498
7860
  * You should not call this function on your own unless you know what you do.
@@ -7511,20 +7873,18 @@ class KeyHandler {
7511
7873
  delete handler.keyStates[e.keyCode];
7512
7874
  }
7513
7875
  }
7514
- ;
7515
7876
  /**
7516
7877
  * Resolve the key/name code.
7517
7878
  */
7518
7879
  static key2code(key) {
7519
- if (typeof key == 'number')
7880
+ if (typeof key == "number")
7520
7881
  return key;
7521
- if (typeof key != 'string')
7882
+ if (typeof key != "string")
7522
7883
  throw "Unknown key name or key type (should be a string or integer): " + key;
7523
7884
  if (KeyHandler.KEY_CODES[key])
7524
7885
  return KeyHandler.KEY_CODES[key];
7525
7886
  throw "Unknown key (cannot resolve key code): " + key;
7526
7887
  }
7527
- ;
7528
7888
  /**
7529
7889
  * Install the required listeners into the initially passed element.
7530
7890
  *
@@ -7533,20 +7893,24 @@ class KeyHandler {
7533
7893
  */
7534
7894
  installListeners() {
7535
7895
  var _self = this;
7536
- this.element.addEventListener('keydown', this._keyDownListener = (e) => { _self.fireDownEvent(e, _self); });
7537
- this.element.addEventListener('keypress', this._keyPressListener = (e) => { _self.firePressEvent(e, _self); });
7538
- this.element.addEventListener('keyup', this._keyUpListener = (e) => { _self.fireUpEvent(e, _self); });
7896
+ this.element.addEventListener("keydown", (this._keyDownListener = (e) => {
7897
+ _self.fireDownEvent(e, _self);
7898
+ }));
7899
+ this.element.addEventListener("keypress", (this._keyPressListener = (e) => {
7900
+ _self.firePressEvent(e, _self);
7901
+ }));
7902
+ this.element.addEventListener("keyup", (this._keyUpListener = (e) => {
7903
+ _self.fireUpEvent(e, _self);
7904
+ }));
7539
7905
  }
7540
- ;
7541
7906
  /**
7542
7907
  * Remove all installed event listeners from the underlying element.
7543
7908
  */
7544
7909
  releaseListeners() {
7545
- this.element.removeEventListener('keydown', this._keyDownListener);
7546
- this.element.removeEventListener('keypress', this._keyPressListener);
7547
- this.element.removeEventListener('keyup', this._keyUpListener);
7910
+ this.element.removeEventListener("keydown", this._keyDownListener);
7911
+ this.element.removeEventListener("keypress", this._keyPressListener);
7912
+ this.element.removeEventListener("keyup", this._keyUpListener);
7548
7913
  }
7549
- ;
7550
7914
  /**
7551
7915
  * Listen for key down. This function allows chaining.
7552
7916
  *
@@ -7563,7 +7927,6 @@ class KeyHandler {
7563
7927
  this.downListeners.push({ key: key, keyCode: KeyHandler.key2code(key), listener: listener });
7564
7928
  return this;
7565
7929
  }
7566
- ;
7567
7930
  /**
7568
7931
  * Listen for key press.
7569
7932
  *
@@ -7580,7 +7943,6 @@ class KeyHandler {
7580
7943
  this.pressListeners.push({ key: key, keyCode: KeyHandler.key2code(key), listener: listener });
7581
7944
  return this;
7582
7945
  }
7583
- ;
7584
7946
  /**
7585
7947
  * Listen for key up.
7586
7948
  *
@@ -7597,23 +7959,31 @@ class KeyHandler {
7597
7959
  this.upListeners.push({ key: key, keyCode: KeyHandler.key2code(key), listener: listener });
7598
7960
  return this;
7599
7961
  }
7600
- ;
7601
7962
  /**
7602
7963
  * Check if a specific key is currently held pressed.
7603
7964
  *
7604
7965
  * @param {string|number} key - Any key identifier, key code or one from the KEY_CODES list.
7605
7966
  */
7606
7967
  isDown(key) {
7607
- if (typeof key == 'number')
7968
+ if (typeof key == "number")
7608
7969
  return this.keyStates[key] ? true : false;
7609
7970
  else
7610
7971
  return this.keyStates[KeyHandler.key2code(key)] ? true : false;
7611
7972
  }
7973
+ /**
7974
+ * This function should invalidate any installed listeners and invalidate this object.
7975
+ * After calling this function the object might not hold valid data any more and
7976
+ * should not be used any more.
7977
+ */
7978
+ destroy() {
7979
+ this.releaseListeners();
7980
+ }
7612
7981
  }
7613
7982
  /**
7614
7983
  * Source:
7615
7984
  * https://keycode.info/
7616
7985
  */
7986
+ // prettier-ignore
7617
7987
  KeyHandler.KEY_CODES = {
7618
7988
  'break': 3,
7619
7989
  'backspace': 8,
@@ -7930,41 +8300,41 @@ class MouseHandler {
7930
8300
  // | drag offset, ...) to the callbacks.
7931
8301
  // +-------------------------------------------------
7932
8302
  const _self = this;
7933
- this.handlers['mousemove'] = (e) => {
8303
+ this.handlers["mousemove"] = (e) => {
7934
8304
  if (_self.listeners.mousemove)
7935
- _self.listeners.mousemove(_self.mkParams(e, 'mousemove'));
8305
+ _self.listeners.mousemove(_self.mkParams(e, "mousemove"));
7936
8306
  if (_self.mouseDragPos && _self.listeners.drag)
7937
- _self.listeners.drag(_self.mkParams(e, 'drag'));
8307
+ _self.listeners.drag(_self.mkParams(e, "drag"));
7938
8308
  if (_self.mouseDownPos)
7939
8309
  _self.mouseDragPos = _self.relPos(e);
7940
8310
  };
7941
- this.handlers['mouseup'] = (e) => {
8311
+ this.handlers["mouseup"] = (e) => {
7942
8312
  if (_self.listeners.mouseup)
7943
- _self.listeners.mouseup(_self.mkParams(e, 'mouseup'));
8313
+ _self.listeners.mouseup(_self.mkParams(e, "mouseup"));
7944
8314
  _self.mouseDragPos = undefined;
7945
8315
  _self.mouseDownPos = undefined;
7946
8316
  _self.mouseButton = -1;
7947
8317
  };
7948
- this.handlers['mousedown'] = (e) => {
8318
+ this.handlers["mousedown"] = (e) => {
7949
8319
  _self.mouseDragPos = _self.relPos(e);
7950
8320
  _self.mouseDownPos = _self.relPos(e);
7951
8321
  _self.mouseButton = e.button;
7952
8322
  if (_self.listeners.mousedown)
7953
- _self.listeners.mousedown(_self.mkParams(e, 'mousedown'));
8323
+ _self.listeners.mousedown(_self.mkParams(e, "mousedown"));
7954
8324
  };
7955
- this.handlers['click'] = (e) => {
8325
+ this.handlers["click"] = (e) => {
7956
8326
  if (_self.listeners.click)
7957
- _self.listeners.click(_self.mkParams(e, 'click'));
8327
+ _self.listeners.click(_self.mkParams(e, "click"));
7958
8328
  };
7959
- this.handlers['wheel'] = (e) => {
8329
+ this.handlers["wheel"] = (e) => {
7960
8330
  if (_self.listeners.wheel)
7961
- _self.listeners.wheel(_self.mkParams(e, 'wheel'));
8331
+ _self.listeners.wheel(_self.mkParams(e, "wheel"));
7962
8332
  };
7963
- this.element.addEventListener('mousemove', this.handlers['mousemove']);
7964
- this.element.addEventListener('mouseup', this.handlers['mouseup']);
7965
- this.element.addEventListener('mousedown', this.handlers['mousedown']);
7966
- this.element.addEventListener('click', this.handlers['click']);
7967
- this.element.addEventListener('wheel', this.handlers['wheel']);
8333
+ this.element.addEventListener("mousemove", this.handlers["mousemove"]);
8334
+ this.element.addEventListener("mouseup", this.handlers["mouseup"]);
8335
+ this.element.addEventListener("mousedown", this.handlers["mousedown"]);
8336
+ this.element.addEventListener("click", this.handlers["click"]);
8337
+ this.element.addEventListener("wheel", this.handlers["wheel"]);
7968
8338
  }
7969
8339
  /**
7970
8340
  * Get relative position from the given MouseEvent.
@@ -7977,11 +8347,8 @@ class MouseHandler {
7977
8347
  * @return {XYCoords} The relative mouse coordinates.
7978
8348
  */
7979
8349
  relPos(e) {
7980
- return { x: e.offsetX,
7981
- y: e.offsetY
7982
- };
8350
+ return { x: e.offsetX, y: e.offsetY };
7983
8351
  }
7984
- ;
7985
8352
  /**
7986
8353
  * Build the extended event params.
7987
8354
  *
@@ -8007,8 +8374,8 @@ class MouseHandler {
8007
8374
  rightButton: this.mouseButton == 2,
8008
8375
  mouseDownPos: this.mouseDownPos,
8009
8376
  draggedFrom: this.mouseDragPos,
8010
- wasDragged: (this.mouseDownPos != null && (this.mouseDownPos.x != rel.x || this.mouseDownPos.y != rel.y)),
8011
- dragAmount: (this.mouseDownPos != null ? { x: rel.x - this.mouseDragPos.x, y: rel.y - this.mouseDragPos.y } : { x: 0, y: 0 })
8377
+ wasDragged: this.mouseDownPos != null && (this.mouseDownPos.x != rel.x || this.mouseDownPos.y != rel.y),
8378
+ dragAmount: this.mouseDownPos != null ? { x: rel.x - this.mouseDragPos.x, y: rel.y - this.mouseDragPos.y } : { x: 0, y: 0 }
8012
8379
  };
8013
8380
  return xEvent;
8014
8381
  }
@@ -8059,14 +8426,13 @@ class MouseHandler {
8059
8426
  */
8060
8427
  drag(callback) {
8061
8428
  if (this.listeners.drag)
8062
- this.throwAlreadyInstalled('drag');
8429
+ this.throwAlreadyInstalled("drag");
8063
8430
  this.listeners.drag = callback;
8064
- this.listenFor('mousedown');
8065
- this.listenFor('mousemove');
8066
- this.listenFor('mouseup');
8431
+ this.listenFor("mousedown");
8432
+ this.listenFor("mousemove");
8433
+ this.listenFor("mouseup");
8067
8434
  return this;
8068
8435
  }
8069
- ;
8070
8436
  /**
8071
8437
  * Installer function to listen for a specific event: mouse-move.
8072
8438
  * Pass your callbacks here.
@@ -8081,12 +8447,11 @@ class MouseHandler {
8081
8447
  */
8082
8448
  move(callback) {
8083
8449
  if (this.listeners.mousemove)
8084
- this.throwAlreadyInstalled('mousemove');
8085
- this.listenFor('mousemove');
8450
+ this.throwAlreadyInstalled("mousemove");
8451
+ this.listenFor("mousemove");
8086
8452
  this.listeners.mousemove = callback;
8087
8453
  return this;
8088
8454
  }
8089
- ;
8090
8455
  /**
8091
8456
  * Installer function to listen for a specific event: mouse-up.
8092
8457
  * Pass your callbacks here.
@@ -8101,12 +8466,11 @@ class MouseHandler {
8101
8466
  */
8102
8467
  up(callback) {
8103
8468
  if (this.listeners.mouseup)
8104
- this.throwAlreadyInstalled('mouseup');
8105
- this.listenFor('mouseup');
8469
+ this.throwAlreadyInstalled("mouseup");
8470
+ this.listenFor("mouseup");
8106
8471
  this.listeners.mouseup = callback;
8107
8472
  return this;
8108
8473
  }
8109
- ;
8110
8474
  /**
8111
8475
  * Installer function to listen for a specific event: mouse-down.
8112
8476
  * Pass your callbacks here.
@@ -8121,12 +8485,11 @@ class MouseHandler {
8121
8485
  */
8122
8486
  down(callback) {
8123
8487
  if (this.listeners.mousedown)
8124
- this.throwAlreadyInstalled('mousedown');
8125
- this.listenFor('mousedown');
8488
+ this.throwAlreadyInstalled("mousedown");
8489
+ this.listenFor("mousedown");
8126
8490
  this.listeners.mousedown = callback;
8127
8491
  return this;
8128
8492
  }
8129
- ;
8130
8493
  /**
8131
8494
  * Installer function to listen for a specific event: mouse-click.
8132
8495
  * Pass your callbacks here.
@@ -8141,12 +8504,11 @@ class MouseHandler {
8141
8504
  */
8142
8505
  click(callback) {
8143
8506
  if (this.listeners.click)
8144
- this.throwAlreadyInstalled('click');
8145
- this.listenFor('click');
8507
+ this.throwAlreadyInstalled("click");
8508
+ this.listenFor("click");
8146
8509
  this.listeners.click = callback;
8147
8510
  return this;
8148
8511
  }
8149
- ;
8150
8512
  /**
8151
8513
  * Installer function to listen for a specific event: mouse-wheel.
8152
8514
  * Pass your callbacks here.
@@ -8161,12 +8523,11 @@ class MouseHandler {
8161
8523
  */
8162
8524
  wheel(callback) {
8163
8525
  if (this.listeners.wheel)
8164
- this.throwAlreadyInstalled('wheel');
8165
- this.listenFor('wheel');
8526
+ this.throwAlreadyInstalled("wheel");
8527
+ this.listenFor("wheel");
8166
8528
  this.listeners.wheel = callback;
8167
8529
  return this;
8168
8530
  }
8169
- ;
8170
8531
  /**
8171
8532
  * An internal function to throw events.
8172
8533
  *
@@ -8180,7 +8541,6 @@ class MouseHandler {
8180
8541
  throwAlreadyInstalled(name) {
8181
8542
  throw `This MouseHandler already has a '${name}' callback. To keep the code simple there is only room for one.`;
8182
8543
  }
8183
- ;
8184
8544
  /**
8185
8545
  * Call this when your work is done.
8186
8546
  *
@@ -8193,16 +8553,16 @@ class MouseHandler {
8193
8553
  * @return {void}
8194
8554
  */
8195
8555
  destroy() {
8196
- this.unlistenFor('mousedown');
8197
- this.unlistenFor('mousemove');
8198
- this.unlistenFor('moseup');
8199
- this.unlistenFor('click');
8200
- this.unlistenFor('wheel');
8201
- this.element.removeEventListener('mousemove', this.handlers['mousemove']);
8202
- this.element.removeEventListener('mouseup', this.handlers['mousedown']);
8203
- this.element.removeEventListener('mousedown', this.handlers['mousedown']);
8204
- this.element.removeEventListener('click', this.handlers['click']);
8205
- this.element.removeEventListener('wheel', this.handlers['wheel']);
8556
+ this.unlistenFor("mousedown");
8557
+ this.unlistenFor("mousemove");
8558
+ this.unlistenFor("moseup");
8559
+ this.unlistenFor("click");
8560
+ this.unlistenFor("wheel");
8561
+ this.element.removeEventListener("mousemove", this.handlers["mousemove"]);
8562
+ this.element.removeEventListener("mouseup", this.handlers["mousedown"]);
8563
+ this.element.removeEventListener("mousedown", this.handlers["mousedown"]);
8564
+ this.element.removeEventListener("click", this.handlers["click"]);
8565
+ this.element.removeEventListener("wheel", this.handlers["wheel"]);
8206
8566
  }
8207
8567
  }
8208
8568
 
@@ -8212,7 +8572,9 @@ class MouseHandler {
8212
8572
  * @modified 2019-03-23 Added JSDoc tags.
8213
8573
  * @modified 2020-03-25 Ported this class from vanilla-JS to Typescript.
8214
8574
  * @modified 2021-01-20 Added UID.
8215
- * @version 1.1.0
8575
+ * @modified 2022-02-02 Added the `destroy` method.
8576
+ * @modified 2022-02-02 Cleared the `PBImage.toSVGString` function (deprecated). Use `drawutilssvg` instead.
8577
+ * @version 1.2.0
8216
8578
  *
8217
8579
  * @file PBImage
8218
8580
  * @fileoverview As native Image objects have only a position and with
@@ -8247,7 +8609,6 @@ class PBImage {
8247
8609
  this.upperLeft = upperLeft;
8248
8610
  this.lowerRight = lowerRight;
8249
8611
  }
8250
- ;
8251
8612
  /**
8252
8613
  * Convert this vertex to SVG code.
8253
8614
  *
@@ -8262,9 +8623,87 @@ class PBImage {
8262
8623
  console.warn("PBImage is not yet SVG serializable. Returning empty SVG string.");
8263
8624
  return "";
8264
8625
  }
8265
- ;
8626
+ /**
8627
+ * This function should invalidate any installed listeners and invalidate this object.
8628
+ * After calling this function the object might not hold valid data any more and
8629
+ * should not be used.
8630
+ */
8631
+ destroy() {
8632
+ this.upperLeft.destroy();
8633
+ this.lowerRight.destroy();
8634
+ this.isDestroyed = true;
8635
+ }
8266
8636
  }
8267
8637
 
8638
+ /**
8639
+ * @author Ikaros Kappler
8640
+ * @date 2021-11-16
8641
+ * @modified 2022-02-02 Added the `destroy` method.
8642
+ * @version 1.1.0
8643
+ **/
8644
+ /**
8645
+ * @classdesc A simple text element: position, fontSize, fontFamily, color, textAlign, lineHeight and rotation.
8646
+ *
8647
+ * @requires FontOptions
8648
+ * @requires FontSize
8649
+ * @requires FontStyle
8650
+ * @requires FontWeight
8651
+ * @requires Vertex
8652
+ * @requires SVGSerializale
8653
+ * @requires UID
8654
+ * @requires UIDGenerator
8655
+ **/
8656
+ class PBText {
8657
+ /**
8658
+ * Create a new circle with given center point and radius.
8659
+ *
8660
+ * @constructor
8661
+ * @name Circle
8662
+ * @param {Vertex} center - The center point of the circle.
8663
+ * @param {number} radius - The radius of the circle.
8664
+ */
8665
+ constructor(text, anchor, options) {
8666
+ /**
8667
+ * Required to generate proper CSS classes and other class related IDs.
8668
+ **/
8669
+ this.className = "PBText";
8670
+ this.uid = UIDGenerator.next();
8671
+ this.text = text;
8672
+ this.anchor = anchor !== null && anchor !== void 0 ? anchor : new Vertex();
8673
+ this.color = options.color;
8674
+ this.fontFamily = options.fontFamily;
8675
+ this.fontSize = options.fontSize;
8676
+ this.fontStyle = options.fontStyle;
8677
+ this.fontWeight = options.fontWeight;
8678
+ this.lineHeight = options.lineHeight;
8679
+ this.textAlign = options.textAlign;
8680
+ this.rotation = options.rotation;
8681
+ }
8682
+ /**
8683
+ * Create an SVG representation of this circle.
8684
+ *
8685
+ * @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
8686
+ * @method toSVGString
8687
+ * @param {object=} options - An optional set of options, like 'className'.
8688
+ * @return {string} A string representing the SVG code for this vertex.
8689
+ * @instance
8690
+ * @memberof Circle
8691
+ */
8692
+ toSVGString(options) {
8693
+ console.warn("[PBText.toSVGString()] This function is not implemented as it defines a deprecated method. Use the 'drawutilssvg.text()' method instead.");
8694
+ return "";
8695
+ }
8696
+ /**
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.anchor.destroy();
8703
+ this.isDestroyed = true;
8704
+ }
8705
+ } // END class
8706
+
8268
8707
  /* Port from AlloyFinger v0.1.15
8269
8708
  * Original by dntzhang
8270
8709
  * Typescript port by Ikaros Kappler
@@ -8666,7 +9105,9 @@ class AlloyFinger {
8666
9105
  * @modified 2021-03-10 Added the `toCubicBezier` method.
8667
9106
  * @modified 2021-03-15 Added `VEllipse.quarterSegmentCount` and `VEllipse.scale` functions.
8668
9107
  * @modified 2021-03-19 Added the `VEllipse.rotate` function.
8669
- * @version 1.2.2
9108
+ * @modified 2022-02-02 Added the `destroy` method.
9109
+ * @modified 2022-02-02 Cleared the `VEllipse.toSVGString` function (deprecated). Use `drawutilssvg` instead.
9110
+ * @version 1.3.0
8670
9111
  *
8671
9112
  * @file VEllipse
8672
9113
  * @fileoverview Ellipses with a center and an x- and a y-axis (stored as a vertex).
@@ -8992,17 +9433,28 @@ class VEllipse {
8992
9433
  * @return string The SVG string
8993
9434
  */
8994
9435
  toSVGString(options) {
8995
- options = options || {};
8996
- var buffer = [];
8997
- buffer.push("<ellipse");
8998
- if (options.className)
8999
- buffer.push(' class="' + options.className + '"');
9000
- buffer.push(' cx="' + this.center.x + '"');
9001
- buffer.push(' cy="' + this.center.y + '"');
9002
- buffer.push(' rx="' + this.axis.x + '"');
9003
- buffer.push(' ry="' + this.axis.y + '"');
9004
- buffer.push(" />");
9005
- return buffer.join("");
9436
+ // options = options || {};
9437
+ // var buffer: Array<string> = [];
9438
+ // buffer.push("<ellipse");
9439
+ // if (options.className) buffer.push(' class="' + options.className + '"');
9440
+ // buffer.push(' cx="' + this.center.x + '"');
9441
+ // buffer.push(' cy="' + this.center.y + '"');
9442
+ // buffer.push(' rx="' + this.axis.x + '"');
9443
+ // buffer.push(' ry="' + this.axis.y + '"');
9444
+ // buffer.push(" />");
9445
+ // return buffer.join("");
9446
+ console.warn("[Deprecation] Warning: the VEllipse.toSVGString method is deprecated and does not return and valid SVG data any more. Please use `drawutilssvg` instead.");
9447
+ return "";
9448
+ }
9449
+ /**
9450
+ * This function should invalidate any installed listeners and invalidate this object.
9451
+ * After calling this function the object might not hold valid data any more and
9452
+ * should not be used.
9453
+ */
9454
+ destroy() {
9455
+ this.center.destroy();
9456
+ this.axis.destroy();
9457
+ this.isDestroyed = true;
9006
9458
  }
9007
9459
  }
9008
9460
  /**
@@ -9069,7 +9521,8 @@ VEllipse.utils = {
9069
9521
  *
9070
9522
  * @author Ikaros Kappler
9071
9523
  * @date 2021-02-26
9072
- * @version 1.0.0
9524
+ * @modified 2022-02-02 Added the `destroy` method.
9525
+ * @version 1.1.0
9073
9526
  */
9074
9527
  /**
9075
9528
  * @classdesc A class for elliptic sectors.
@@ -9155,6 +9608,15 @@ class VEllipseSector {
9155
9608
  }
9156
9609
  return curves;
9157
9610
  }
9611
+ /**
9612
+ * This function should invalidate any installed listeners and invalidate this object.
9613
+ * After calling this function the object might not hold valid data any more and
9614
+ * should not be used.
9615
+ */
9616
+ destroy() {
9617
+ this.ellipse.destroy();
9618
+ this.isDestroyed = true;
9619
+ }
9158
9620
  }
9159
9621
  VEllipseSector.ellipseSectorUtils = {
9160
9622
  /**
@@ -9394,7 +9856,8 @@ VEllipseSector.ellipseSectorUtils = {
9394
9856
  * @modified 2021-03-03 Added the `VEllipseSector` drawable.
9395
9857
  * @modified 2021-03-29 Clearing `currentClassName` and `currentId` after drawing each drawable.
9396
9858
  * @modified 2021-04-25 Extending `remove` to accept arrays of drawables.
9397
- * @version 1.14.0
9859
+ * @modified 2021-11-16 Adding the `PBText` drawable.
9860
+ * @version 1.15.0
9398
9861
  *
9399
9862
  * @file PlotBoilerplate
9400
9863
  * @fileoverview The main class.
@@ -9639,6 +10102,12 @@ class PlotBoilerplate {
9639
10102
  image: {
9640
10103
  color: "#a8a8a8",
9641
10104
  lineWidth: 1
10105
+ },
10106
+ text: {
10107
+ color: "rgba(192,0,128,0.5)",
10108
+ lineWidth: 1,
10109
+ fill: true,
10110
+ anchor: true
9642
10111
  }
9643
10112
  }; // END drawConfig
9644
10113
  // +---------------------------------------------------------------------------------
@@ -9760,7 +10229,7 @@ class PlotBoilerplate {
9760
10229
  var blob = new Blob([svgCode], { type: "image/svg;charset=utf-8" });
9761
10230
  // See documentation for FileSaver.js for usage.
9762
10231
  // https://github.com/eligrey/FileSaver.js
9763
- if (typeof globalThis["saveAs"] != "function")
10232
+ if (typeof globalThis["saveAs"] !== "function")
9764
10233
  throw "Cannot save file; did you load the ./utils/savefile helper function and the eligrey/SaveFile library?";
9765
10234
  var _saveAs = globalThis["saveAs"];
9766
10235
  _saveAs(blob, "plotboilerplate.svg");
@@ -9866,7 +10335,6 @@ class PlotBoilerplate {
9866
10335
  add(drawable, redraw) {
9867
10336
  if (Array.isArray(drawable)) {
9868
10337
  const arr = drawable;
9869
- // for( var i in arr )
9870
10338
  for (var i = 0; i < arr.length; i++) {
9871
10339
  this.add(arr[i], false);
9872
10340
  }
@@ -9912,9 +10380,9 @@ class PlotBoilerplate {
9912
10380
  }
9913
10381
  else if (drawable instanceof Polygon) {
9914
10382
  this.drawables.push(drawable);
9915
- // for( var i in drawable.vertices )
9916
- for (var i = 0; i < drawable.vertices.length; i++)
10383
+ for (var i = 0; i < drawable.vertices.length; i++) {
9917
10384
  this.vertices.push(drawable.vertices[i]);
10385
+ }
9918
10386
  }
9919
10387
  else if (drawable instanceof Triangle) {
9920
10388
  this.drawables.push(drawable);
@@ -9926,8 +10394,9 @@ class PlotBoilerplate {
9926
10394
  this.drawables.push(drawable);
9927
10395
  const bezierPath = drawable;
9928
10396
  for (var i = 0; i < bezierPath.bezierCurves.length; i++) {
9929
- if (!drawable.adjustCircular && i == 0)
10397
+ if (!drawable.adjustCircular && i == 0) {
9930
10398
  this.vertices.push(bezierPath.bezierCurves[i].startPoint);
10399
+ }
9931
10400
  this.vertices.push(bezierPath.bezierCurves[i].endPoint);
9932
10401
  this.vertices.push(bezierPath.bezierCurves[i].startControlPoint);
9933
10402
  this.vertices.push(bezierPath.bezierCurves[i].endControlPoint);
@@ -9946,6 +10415,11 @@ class PlotBoilerplate {
9946
10415
  });
9947
10416
  drawable.lowerRight.attr.selectable = false;
9948
10417
  }
10418
+ else if (drawable instanceof PBText) {
10419
+ this.vertices.push(drawable.anchor);
10420
+ this.drawables.push(drawable);
10421
+ drawable.anchor.attr.selectable = false;
10422
+ }
9949
10423
  else {
9950
10424
  throw "Cannot add drawable of unrecognized type: " + typeof drawable + ".";
9951
10425
  }
@@ -9993,7 +10467,7 @@ class PlotBoilerplate {
9993
10467
  }
9994
10468
  }
9995
10469
  for (var i = 0; i < this.drawables.length; i++) {
9996
- if (this.drawables[i] === drawable) {
10470
+ if (this.drawables[i] === drawable || this.drawables[i].uid === drawable.uid) {
9997
10471
  this.drawables.splice(i, 1);
9998
10472
  if (removeWithVertices) {
9999
10473
  // Check if some listeners need to be removed
@@ -10044,6 +10518,9 @@ class PlotBoilerplate {
10044
10518
  this.removeVertex(drawable.upperLeft, false);
10045
10519
  this.removeVertex(drawable.lowerRight, false);
10046
10520
  }
10521
+ else if (drawable instanceof PBText) {
10522
+ this.removeVertex(drawable.anchor, false);
10523
+ }
10047
10524
  } // END removeWithVertices
10048
10525
  if (redraw) {
10049
10526
  this.redraw();
@@ -10065,8 +10542,9 @@ class PlotBoilerplate {
10065
10542
  for (var i = 0; i < this.vertices.length; i++) {
10066
10543
  if (this.vertices[i] === vert) {
10067
10544
  this.vertices.splice(i, 1);
10068
- if (redraw)
10545
+ if (redraw) {
10069
10546
  this.redraw();
10547
+ }
10070
10548
  return;
10071
10549
  }
10072
10550
  }
@@ -10101,8 +10579,9 @@ class PlotBoilerplate {
10101
10579
  **/
10102
10580
  getVertexNear(pixelPosition, pixelTolerance) {
10103
10581
  var p = this.locatePointNear(this.transformMousePosition(pixelPosition.x, pixelPosition.y), pixelTolerance / Math.min(this.config.cssScaleX, this.config.cssScaleY));
10104
- if (p && p.typeName == "vertex")
10582
+ if (p && p.typeName == "vertex") {
10105
10583
  return this.vertices[p.vindex];
10584
+ }
10106
10585
  return undefined;
10107
10586
  }
10108
10587
  /**
@@ -10369,6 +10848,16 @@ class PlotBoilerplate {
10369
10848
  d.lowerRight.attr.renderTime = renderTime;
10370
10849
  }
10371
10850
  }
10851
+ else if (d instanceof PBText) {
10852
+ fill.setCurrentId(d.uid);
10853
+ fill.text(d.text, d.anchor.x, d.anchor.y, d);
10854
+ if (this.drawConfig.text.anchor) {
10855
+ draw.setCurrentId(`${d.uid}_a0`);
10856
+ draw.setCurrentClassName(`${d.className}-anchor`);
10857
+ (this.drawConfig.text.fill ? fill : draw).point(d.anchor, this.drawConfig.text.color);
10858
+ }
10859
+ d.anchor.attr.renderTime = renderTime;
10860
+ }
10372
10861
  else {
10373
10862
  console.error("Cannot draw object. Unknown class.");
10374
10863
  }
@@ -10647,7 +11136,6 @@ class PlotBoilerplate {
10647
11136
  // Apply the zoom (the tolerant area should not shrink or grow when zooming)
10648
11137
  tolerance /= _self.draw.scale.x;
10649
11138
  // Search in vertices
10650
- // for( var vindex in _self.vertices ) {
10651
11139
  for (var vindex = 0; vindex < _self.vertices.length; vindex++) {
10652
11140
  var vert = _self.vertices[vindex];
10653
11141
  if ((vert.attr.draggable || vert.attr.selectable) && vert.distance(point) < tolerance) {
@@ -10667,10 +11155,7 @@ class PlotBoilerplate {
10667
11155
  * @return {void}
10668
11156
  **/
10669
11157
  handleClick(e) {
10670
- // x:number,y:number) {
10671
11158
  const _self = this;
10672
- // const x:number = e.params.pos.x;
10673
- //const y:number = e.params.pos.y;
10674
11159
  var p = this.locatePointNear(_self.transformMousePosition(e.params.pos.x, e.params.pos.y), PlotBoilerplate.DEFAULT_CLICK_TOLERANCE / Math.min(_self.config.cssScaleX, _self.config.cssScaleY));
10675
11160
  if (p) {
10676
11161
  _self.vertices[p.vindex].listeners.fireClickEvent(e);
@@ -10687,7 +11172,7 @@ class PlotBoilerplate {
10687
11172
  }
10688
11173
  _self.redraw();
10689
11174
  }
10690
- else if (this.keyHandler.isDown("y") /* && p.type=='bpath' && (p.pid==BezierPath.START_POINT || p.pid==BezierPath.END_POINT) */) {
11175
+ else if (this.keyHandler.isDown("y")) {
10691
11176
  _self.vertices[p.vindex].attr.bezierAutoAdjust = !_self.vertices[p.vindex].attr.bezierAutoAdjust;
10692
11177
  _self.redraw();
10693
11178
  }
@@ -10985,6 +11470,7 @@ class PlotBoilerplate {
10985
11470
  _self.draggedElements = [];
10986
11471
  };
10987
11472
  const afProps = {
11473
+ // touchStart: (evt: TouchEvent) => {
10988
11474
  touchStart: (evt) => {
10989
11475
  if (evt.touches.length == 1) {
10990
11476
  touchMovePos = new Vertex(relPos({ x: evt.touches[0].clientX, y: evt.touches[0].clientY }));
@@ -11087,10 +11573,13 @@ class PlotBoilerplate {
11087
11573
  _self.redraw();
11088
11574
  }
11089
11575
  }; // END afProps
11090
- if (window["createAlloyFinger"])
11576
+ if (window["createAlloyFinger"]) {
11091
11577
  window["createAlloyFinger"](this.eventCatcher ? this.eventCatcher : this.canvas, afProps);
11092
- else
11578
+ }
11579
+ else {
11580
+ /* tslint:disable-next-line */
11093
11581
  new AlloyFinger(this.eventCatcher ? this.eventCatcher : this.canvas, afProps);
11582
+ }
11094
11583
  }
11095
11584
  catch (e) {
11096
11585
  console.error("Failed to initialize AlloyFinger!");
@@ -11453,5 +11942,5 @@ class SVGBuilder {
11453
11942
  ;
11454
11943
  }
11455
11944
 
11456
- export { BezierPath, Bounds, Circle, CircleSector, CubicBezierCurve, Grid, KeyHandler, Line, MouseHandler, PBImage, PlotBoilerplate, Polygon, SVGBuilder, Triangle, UIDGenerator, VEllipse, VEllipseSector, Vector, VertTuple, Vertex, VertexAttr, VertexListeners, XMouseEvent, XWheelEvent, drawutils, drawutilsgl, drawutilssvg, geomutils };
11945
+ 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 };
11457
11946
  //# sourceMappingURL=index.esm.js.map