plotboilerplate 1.24.0 → 1.25.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 (141) hide show
  1. package/README.md +13 -1
  2. package/dist/index.esm.js +294 -129
  3. package/dist/index.esm.js.map +1 -1
  4. package/dist/index.esm.min.js +1 -1
  5. package/dist/index.esm.min.js.map +1 -1
  6. package/dist/plotboilerplate.browser.min.js +1 -1
  7. package/dist/plotboilerplate.browser.min.js.map +1 -1
  8. package/dist/plotboilerplate.js +12084 -11919
  9. package/dist/plotboilerplate.min.js +1 -1
  10. package/package.json +9 -5
  11. package/src/cjs/PlotBoilerplate.d.ts +37 -6
  12. package/src/cjs/PlotBoilerplate.js +222 -116
  13. package/src/cjs/PlotBoilerplate.js.map +1 -1
  14. package/src/cjs/Polygon.d.ts +26 -7
  15. package/src/cjs/Polygon.js +56 -10
  16. package/src/cjs/Polygon.js.map +1 -1
  17. package/src/cjs/Triangle.js +2 -2
  18. package/src/cjs/Triangle.js.map +1 -1
  19. package/src/cjs/Vertex.d.ts +15 -3
  20. package/src/cjs/Vertex.js +18 -1
  21. package/src/cjs/Vertex.js.map +1 -1
  22. package/src/cjs/interfaces/core.d.ts +28 -0
  23. package/src/cjs/interfaces/core.js +2 -0
  24. package/src/cjs/interfaces/core.js.map +1 -1
  25. package/src/cjs/utils/datastructures/Color.d.ts +147 -1
  26. package/src/cjs/utils/datastructures/Color.js +385 -41
  27. package/src/cjs/utils/datastructures/Color.js.map +1 -1
  28. package/src/cjs/utils/datastructures/ColorGradient.d.ts +79 -0
  29. package/src/cjs/utils/datastructures/ColorGradient.js +171 -0
  30. package/src/cjs/utils/datastructures/ColorGradient.js.map +1 -0
  31. package/src/cjs/utils/dom/components/ColorGradientPicker.d.ts +245 -0
  32. package/src/cjs/utils/dom/components/ColorGradientPicker.js +667 -0
  33. package/src/cjs/utils/dom/components/ColorGradientPicker.js.map +1 -0
  34. package/src/cjs/utils/dom/components/ColorGradientPickerJSX.d.ts +129 -0
  35. package/src/cjs/utils/dom/components/ColorGradientPickerJSX.js +520 -0
  36. package/src/cjs/utils/dom/components/ColorGradientPickerJSX.js.map +1 -0
  37. package/src/cjs/utils/dom/components/ColorGradientSelector.d.ts +117 -0
  38. package/src/cjs/utils/dom/components/ColorGradientSelector.js +325 -0
  39. package/src/cjs/utils/dom/components/ColorGradientSelector.js.map +1 -0
  40. package/src/cjs/utils/dom/components/Test.d.ts +7 -0
  41. package/src/cjs/utils/dom/components/Test.js +30 -0
  42. package/src/cjs/utils/dom/components/Test.js.map +1 -0
  43. package/src/cjs/utils/dom/guiSizeToggler.js +1 -1
  44. package/src/cjs/utils/dom/guiSizeToggler.js.map +1 -1
  45. package/src/cjs/utils/helpers/BezierPathInteractionHelper.d.ts +9 -3
  46. package/src/cjs/utils/helpers/BezierPathInteractionHelper.js +20 -13
  47. package/src/cjs/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
  48. package/src/cjs/utils/helpers/CircleHelper.d.ts +10 -1
  49. package/src/cjs/utils/helpers/CircleHelper.js +13 -2
  50. package/src/cjs/utils/helpers/CircleHelper.js.map +1 -1
  51. package/src/cjs/utils/helpers/CircleSectorHelper.d.ts +2 -2
  52. package/src/cjs/utils/helpers/CircleSectorHelper.js +1 -0
  53. package/src/cjs/utils/helpers/CircleSectorHelper.js.map +1 -1
  54. package/src/cjs/utils/helpers/TriangleHelper.d.ts +57 -0
  55. package/src/cjs/utils/helpers/TriangleHelper.js +83 -0
  56. package/src/cjs/utils/helpers/TriangleHelper.js.map +1 -0
  57. package/src/cjs/utils/helpers/VEllipseHelper.d.ts +6 -4
  58. package/src/cjs/utils/helpers/VEllipseHelper.js +4 -2
  59. package/src/cjs/utils/helpers/VEllipseHelper.js.map +1 -1
  60. package/src/cjs/utils/helpers/VEllipseSectorHelper.d.ts +3 -2
  61. package/src/cjs/utils/helpers/VEllipseSectorHelper.js +1 -0
  62. package/src/cjs/utils/helpers/VEllipseSectorHelper.js.map +1 -1
  63. package/src/cjs/utils/parsers/LinearColorGradientParser.d.ts +78 -0
  64. package/src/cjs/utils/parsers/LinearColorGradientParser.js +224 -0
  65. package/src/cjs/utils/parsers/LinearColorGradientParser.js.map +1 -0
  66. package/src/createDemoDrawables.js +1 -0
  67. package/src/esm/PlotBoilerplate.d.ts +37 -6
  68. package/src/esm/PlotBoilerplate.js +222 -116
  69. package/src/esm/PlotBoilerplate.js.map +1 -1
  70. package/src/esm/Polygon.d.ts +26 -7
  71. package/src/esm/Polygon.js +53 -10
  72. package/src/esm/Polygon.js.map +1 -1
  73. package/src/esm/Triangle.js +2 -2
  74. package/src/esm/Triangle.js.map +1 -1
  75. package/src/esm/Vertex.d.ts +15 -3
  76. package/src/esm/Vertex.js +18 -1
  77. package/src/esm/Vertex.js.map +1 -1
  78. package/src/esm/interfaces/core.d.ts +28 -0
  79. package/src/esm/interfaces/core.js +2 -0
  80. package/src/esm/interfaces/core.js.map +1 -1
  81. package/src/esm/utils/datastructures/Color.d.ts +147 -1
  82. package/src/esm/utils/datastructures/Color.js +386 -42
  83. package/src/esm/utils/datastructures/Color.js.map +1 -1
  84. package/src/esm/utils/datastructures/ColorGradient.d.ts +79 -0
  85. package/src/esm/utils/datastructures/ColorGradient.js +166 -0
  86. package/src/esm/utils/datastructures/ColorGradient.js.map +1 -0
  87. package/src/esm/utils/dom/components/ColorGradientPicker.d.ts +245 -0
  88. package/src/esm/utils/dom/components/ColorGradientPicker.js +732 -0
  89. package/src/esm/utils/dom/components/ColorGradientPicker.js.map +1 -0
  90. package/src/esm/utils/dom/components/ColorGradientPickerJSX.d.ts +129 -0
  91. package/src/esm/utils/dom/components/ColorGradientPickerJSX.js +582 -0
  92. package/src/esm/utils/dom/components/ColorGradientPickerJSX.js.map +1 -0
  93. package/src/esm/utils/dom/components/ColorGradientSelector.d.ts +117 -0
  94. package/src/esm/utils/dom/components/ColorGradientSelector.js +332 -0
  95. package/src/esm/utils/dom/components/ColorGradientSelector.js.map +1 -0
  96. package/src/esm/utils/dom/components/Test.d.ts +7 -0
  97. package/src/esm/utils/dom/components/Test.js +26 -0
  98. package/src/esm/utils/dom/components/Test.js.map +1 -0
  99. package/src/esm/utils/dom/guiSizeToggler.js +1 -1
  100. package/src/esm/utils/dom/guiSizeToggler.js.map +1 -1
  101. package/src/esm/utils/helpers/BezierPathInteractionHelper.d.ts +9 -3
  102. package/src/esm/utils/helpers/BezierPathInteractionHelper.js +20 -13
  103. package/src/esm/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
  104. package/src/esm/utils/helpers/CircleHelper.d.ts +10 -1
  105. package/src/esm/utils/helpers/CircleHelper.js +13 -2
  106. package/src/esm/utils/helpers/CircleHelper.js.map +1 -1
  107. package/src/esm/utils/helpers/CircleSectorHelper.d.ts +2 -2
  108. package/src/esm/utils/helpers/CircleSectorHelper.js +1 -0
  109. package/src/esm/utils/helpers/CircleSectorHelper.js.map +1 -1
  110. package/src/esm/utils/helpers/TriangleHelper.d.ts +57 -0
  111. package/src/esm/utils/helpers/TriangleHelper.js +78 -0
  112. package/src/esm/utils/helpers/TriangleHelper.js.map +1 -0
  113. package/src/esm/utils/helpers/VEllipseHelper.d.ts +6 -4
  114. package/src/esm/utils/helpers/VEllipseHelper.js +4 -2
  115. package/src/esm/utils/helpers/VEllipseHelper.js.map +1 -1
  116. package/src/esm/utils/helpers/VEllipseSectorHelper.d.ts +3 -2
  117. package/src/esm/utils/helpers/VEllipseSectorHelper.js +1 -0
  118. package/src/esm/utils/helpers/VEllipseSectorHelper.js.map +1 -1
  119. package/src/esm/utils/parsers/LinearColorGradientParser.d.ts +78 -0
  120. package/src/esm/utils/parsers/LinearColorGradientParser.js +217 -0
  121. package/src/esm/utils/parsers/LinearColorGradientParser.js.map +1 -0
  122. package/src/external.d.ts +9 -0
  123. package/src/ts/PlotBoilerplate.ts +233 -105
  124. package/src/ts/Polygon.ts +68 -14
  125. package/src/ts/Triangle.ts +2 -2
  126. package/src/ts/Vertex.ts +21 -3
  127. package/src/ts/interfaces/core.ts +31 -0
  128. package/src/ts/utils/datastructures/Color.ts +423 -44
  129. package/src/ts/utils/datastructures/ColorGradient.ts +196 -0
  130. package/src/ts/utils/dom/components/ColorGradientPicker.tsx +877 -0
  131. package/src/ts/utils/dom/components/ColorGradientSelector.tsx +445 -0
  132. package/src/ts/utils/dom/components/Test.tsx +44 -0
  133. package/src/ts/utils/dom/components/_ColorGradientPicker_raw.ts_ +392 -0
  134. package/src/ts/utils/dom/guiSizeToggler.ts +1 -1
  135. package/src/ts/utils/helpers/BezierPathInteractionHelper.ts +25 -15
  136. package/src/ts/utils/helpers/CircleHelper.ts +17 -3
  137. package/src/ts/utils/helpers/CircleSectorHelper.ts +4 -2
  138. package/src/ts/utils/helpers/TriangleHelper.ts +102 -0
  139. package/src/ts/utils/helpers/VEllipseHelper.ts +6 -4
  140. package/src/ts/utils/helpers/VEllipseSectorHelper.ts +3 -2
  141. package/src/ts/utils/parsers/LinearColorGradientParser.ts +297 -0
package/dist/index.esm.js CHANGED
@@ -958,7 +958,7 @@ class Triangle {
958
958
  // Find the intersections of all lines inside the edge bounds
959
959
  return Polygon.utils
960
960
  .locateLineIntersecion(line, [this.a, this.b, this.c], false, inVectorBoundsOnly)
961
- .map(intersectionTuple => intersectionTuple.intersectionPoint);
961
+ .map(intersectionTuple => intersectionTuple.intersection);
962
962
  }
963
963
  /**
964
964
  * Get all line intersections of this polygon and their tangents along the shape.
@@ -976,7 +976,7 @@ class Triangle {
976
976
  .map(intersectionTuple => {
977
977
  // const polyLine = this.getEdgeAt(intersectionTuple.edgeIndex);
978
978
  const polyLine = this.getEdgeAt(intersectionTuple.edgeIndex);
979
- return new Vector(polyLine.a.clone(), polyLine.b.clone()).moveTo(intersectionTuple.intersectionPoint);
979
+ return new Vector(polyLine.a.clone(), polyLine.b.clone()).moveTo(intersectionTuple.intersection);
980
980
  });
981
981
  }
982
982
  //--- END --- Implement interface `Intersectable`
@@ -1293,7 +1293,8 @@ const geomutils = {
1293
1293
  * @modified 2024-12-17 Outsourced the euclidean distance calculation of `Vertex.distance` to `geomutils.dist4`.
1294
1294
  * @modified 2025-03-24 Making the second parameter `center` of the `Vertex.rotate` method optional.
1295
1295
  * @modified 2025-04-13 Adding the `Vertex.move(amount: XYCoords)` method (does the same as `add`, added by naming convention).
1296
- * @version 2.10.0
1296
+ * @modified 2025-05-07 Class `Vertex` is now implementing interface `IBounded` (to meet convention).
1297
+ * @version 2.11.0
1297
1298
  *
1298
1299
  * @file Vertex
1299
1300
  * @public
@@ -1838,6 +1839,21 @@ class Vertex {
1838
1839
  this.y = Math.abs(this.y);
1839
1840
  return this;
1840
1841
  }
1842
+ //--- BEGIN --- Implement interface `IBounded`
1843
+ /**
1844
+ * Get the bounding box (bounds) of this Vertex.
1845
+ * This is just by convention – any vertex is just a position without any useful with or height (0).
1846
+ *
1847
+ * @method getBounds
1848
+ * @instance
1849
+ * @memberof Vertex
1850
+ * @return {Bounds} The rectangular bounds of this Vertex (width and height are zero).
1851
+ **/
1852
+ getBounds() {
1853
+ // return Bounds.computeFromVertices([this.a, this.b, this.c]);
1854
+ return Bounds.computeFromVertices([this]);
1855
+ }
1856
+ //--- END --- Implement interface `IBounded`
1841
1857
  /**
1842
1858
  * Get a string representation of this vertex.
1843
1859
  *
@@ -2679,7 +2695,9 @@ class Line extends VertTuple {
2679
2695
  * @modified 2025-03-28 Added the `Polygon.lineIntersectionTangents` method.
2680
2696
  * @modified 2025-04-09 Added the `Polygon.getCentroid` method.
2681
2697
  * @modified 2025-05-16 Class `Polygon` now implements `IBounded`.
2682
- * @version 1.15.0
2698
+ * @modified 2025-05-20 Tweaking `Polygon.getInnerAngleAt` and `Polygo.isAngleAcute` to handle indices out of array bounds as well.
2699
+ * @modified 2025-06-07 Adding `Polygon.closestLineIntersectionIndex` to determine line intersections plus detected edge index.
2700
+ * @version 1.16.0
2683
2701
  *
2684
2702
  * @file Polygon
2685
2703
  * @public
@@ -2786,7 +2804,7 @@ class Polygon {
2786
2804
  * @returns {boolean} `true` is angle is acute, `false` is obtuse.
2787
2805
  */
2788
2806
  getInnerAngleAt(vertIndex) {
2789
- const p2 = this.vertices[vertIndex];
2807
+ const p2 = this.vertices[vertIndex % this.vertices.length];
2790
2808
  const p1 = this.vertices[(vertIndex + this.vertices.length - 1) % this.vertices.length].clone();
2791
2809
  const p3 = this.vertices[(vertIndex + 1) % this.vertices.length].clone();
2792
2810
  // See
@@ -2822,7 +2840,7 @@ class Polygon {
2822
2840
  */
2823
2841
  isAngleAcute(vertIndex) {
2824
2842
  const A = this.vertices[(vertIndex + this.vertices.length - 1) % this.vertices.length].clone();
2825
- const B = this.vertices[vertIndex];
2843
+ const B = this.vertices[vertIndex % this.vertices.length];
2826
2844
  const C = this.vertices[(vertIndex + 1) % this.vertices.length].clone();
2827
2845
  // Find local winding number for triangle A B C
2828
2846
  const windingNumber = Triangle.utils.determinant(A, B, C);
@@ -2888,8 +2906,9 @@ class Polygon {
2888
2906
  let xi = this.vertices[i].x, yi = this.vertices[i].y;
2889
2907
  let xj = this.vertices[j].x, yj = this.vertices[j].y;
2890
2908
  var intersect = yi > vert.y != yj > vert.y && vert.x < ((xj - xi) * (vert.y - yi)) / (yj - yi) + xi;
2891
- if (intersect)
2909
+ if (intersect) {
2892
2910
  inside = !inside;
2911
+ }
2893
2912
  }
2894
2913
  return inside;
2895
2914
  }
@@ -3099,7 +3118,7 @@ class Polygon {
3099
3118
  // Find the intersections of all lines inside the edge bounds
3100
3119
  return Polygon.utils
3101
3120
  .locateLineIntersecion(line, this.vertices, this.isOpen, inVectorBoundsOnly)
3102
- .map(intersectionTuple => intersectionTuple.intersectionPoint);
3121
+ .map(intersectionTuple => intersectionTuple.intersection);
3103
3122
  }
3104
3123
  /**
3105
3124
  * Get all line intersections of this polygon and their tangents along the shape.
@@ -3114,10 +3133,29 @@ class Polygon {
3114
3133
  // Find the intersection tangents of all lines inside the edge bounds
3115
3134
  return Polygon.utils.locateLineIntersecion(line, this.vertices, this.isOpen, inVectorBoundsOnly).map(intersectionTuple => {
3116
3135
  const polyLine = this.getEdgeAt(intersectionTuple.edgeIndex);
3117
- return new Vector(polyLine.a.clone(), polyLine.b.clone()).moveTo(intersectionTuple.intersectionPoint);
3136
+ return new Vector(polyLine.a.clone(), polyLine.b.clone()).moveTo(intersectionTuple.intersection);
3118
3137
  });
3119
3138
  }
3120
3139
  //--- END --- Implement interface `Intersectable`
3140
+ /**
3141
+ * Get all line intersections of this polygon and their tangents along the shape.
3142
+ *
3143
+ * This method returns all intersection tangents (as vectors) with this shape. The returned array of vectors is in no specific order.
3144
+ *
3145
+ * @param line
3146
+ * @param inVectorBoundsOnly
3147
+ * @returns
3148
+ */
3149
+ lineIntersectionTangentsIndices(line, inVectorBoundsOnly = false) {
3150
+ // Find the intersection tangents of all lines inside the edge bounds
3151
+ return Polygon.utils.locateLineIntersecion(line, this.vertices, this.isOpen, inVectorBoundsOnly).map(intersectionTuple => {
3152
+ const polyLine = this.getEdgeAt(intersectionTuple.edgeIndex);
3153
+ return {
3154
+ intersection: new Vector(polyLine.a.clone(), polyLine.b.clone()).moveTo(intersectionTuple.intersection),
3155
+ edgeIndex: intersectionTuple.edgeIndex
3156
+ };
3157
+ });
3158
+ }
3121
3159
  /**
3122
3160
  * Get the closest line-polygon-intersection point (closest the line point A).
3123
3161
  *
@@ -3125,9 +3163,27 @@ class Polygon {
3125
3163
  *
3126
3164
  * @param {VertTuple} line - The line to find intersections with.
3127
3165
  * @param {boolean} inVectorBoundsOnly - If set to true only intersecion points on the passed vector are considered (located strictly between start and end vertex).
3128
- * @returns {Array<Vertex>} - An array of all intersections within the polygon bounds.
3166
+ * @returns {Vertex | null} - The intersection point within the polygon bounds.
3129
3167
  */
3130
3168
  closestLineIntersection(line, inVectorBoundsOnly = false) {
3169
+ var closestInterSectionIndex = this.closestLineIntersectionIndex(line, inVectorBoundsOnly);
3170
+ if (closestInterSectionIndex) {
3171
+ return closestInterSectionIndex.intersection;
3172
+ }
3173
+ else {
3174
+ return null;
3175
+ }
3176
+ }
3177
+ /**
3178
+ * Get the closest line-polygon-intersection point (closest the line point A) plus the edge index..
3179
+ *
3180
+ * See demo `63-measure-angles-on-polygon` for how it works.
3181
+ *
3182
+ * @param {VertTuple} line - The line to find intersections with.
3183
+ * @param {boolean} inVectorBoundsOnly - If set to true only intersecion points on the passed vector are considered (located strictly between start and end vertex).
3184
+ * @returns {PolygonIntersectionTuple| null} - A pair containing the intersection point and the affected polygon edge index.
3185
+ */
3186
+ closestLineIntersectionIndex(line, inVectorBoundsOnly = false) {
3131
3187
  const allIntersections = this.lineIntersections(line, inVectorBoundsOnly);
3132
3188
  if (allIntersections.length <= 0) {
3133
3189
  // Empty polygon -> no intersections
@@ -3135,17 +3191,20 @@ class Polygon {
3135
3191
  }
3136
3192
  // Find the closest intersection
3137
3193
  let closestIntersection = new Vertex(Number.MAX_VALUE, Number.MAX_VALUE);
3194
+ let closestInterSectionIndex = -1;
3138
3195
  let curDist = Number.MAX_VALUE;
3139
- for (var i in allIntersections) {
3196
+ for (var i = 0; i < allIntersections.length; i++) {
3140
3197
  const curVert = allIntersections[i];
3141
3198
  const dist = curVert.distance(line.a);
3142
3199
  if (dist < curDist) {
3143
3200
  // && line.hasPoint(curVert)) {
3144
3201
  curDist = dist;
3145
3202
  closestIntersection = curVert;
3203
+ closestInterSectionIndex = i;
3146
3204
  }
3147
3205
  }
3148
- return closestIntersection;
3206
+ // return [closestIntersection, closestInterSectionIndex];
3207
+ return { edgeIndex: closestInterSectionIndex, intersection: closestIntersection };
3149
3208
  }
3150
3209
  /**
3151
3210
  * Construct a new polygon from this polygon with more vertices on each edge. The
@@ -3503,7 +3562,7 @@ Polygon.utils = {
3503
3562
  if (intersection !== null &&
3504
3563
  polyLine.hasPoint(intersection, true) &&
3505
3564
  (!inVectorBoundsOnly || line.hasPoint(intersection, inVectorBoundsOnly))) {
3506
- intersectionPoints.push({ edgeIndex: i, intersectionPoint: intersection });
3565
+ intersectionPoints.push({ edgeIndex: i, intersection: intersection });
3507
3566
  }
3508
3567
  }
3509
3568
  return intersectionPoints;
@@ -12325,8 +12384,13 @@ VEllipseSector.ellipseSectorUtils = {
12325
12384
  * @modified 2024-07-08 Adding `PlotBoilerplate.getGUI()` to retrieve the GUI instance.
12326
12385
  * @modified 2024-08-25 Extending main class `PlotBoilerplate` optional param `isBackdropFiltersEnabled`.
12327
12386
  * @modified 2024-12-02 Adding the `triggerRedraw` to the `removeAll` method.
12387
+ * @modified 2025-05-07 Changing the return type of `removeVertex` from `void` to `boolean`.
12388
+ * @modified 2025-05-07 Handling content changes now with `contentChangeListeners`.
12389
+ * @modified 2025-05-07 Added `PlogBoilerplate.addContentChangeListener` and `.removeContentChangeListener`.
12390
+ * @modified 2025-05-07 Moving full vectors now by default when vector point a is moved.
12391
+ * @modified 2025-05-20 Applying `lineWith` parameter in the draw routine for vectors (had been missing).
12328
12392
  *
12329
- * @version 1.20.0
12393
+ * @version 1.21.1
12330
12394
  *
12331
12395
  * @file PlotBoilerplate
12332
12396
  * @fileoverview The main class.
@@ -12429,6 +12493,10 @@ class PlotBoilerplate {
12429
12493
  */
12430
12494
  constructor(config, drawConfig) {
12431
12495
  var _b, _c;
12496
+ /**
12497
+ * A list of content change listeners.
12498
+ */
12499
+ this.contentChangeListeners = [];
12432
12500
  /**
12433
12501
  * A discrete timestamp to identify single render cycles.
12434
12502
  * Note that using system time milliseconds is not a safe way to identify render frames, as on modern powerful machines
@@ -12816,6 +12884,52 @@ class PlotBoilerplate {
12816
12884
  PlotBoilerplate.utils.setCSSscale(this.canvas, (_d = this.config.cssScaleX) !== null && _d !== void 0 ? _d : 1.0, (_e = this.config.cssScaleY) !== null && _e !== void 0 ? _e : 1.0);
12817
12885
  }
12818
12886
  }
12887
+ /**
12888
+ * Adds a new content change listener to this instance. Adding duplicates is not possible.
12889
+ *
12890
+ * @param {PBContentChangeListener} listener - The listenre to add.
12891
+ * @method addContentChangeListener
12892
+ * @instance
12893
+ * @memberof PlotBoilerplate
12894
+ * @returns {void}
12895
+ */
12896
+ addContentChangeListener(listener) {
12897
+ for (var i in this.contentChangeListeners) {
12898
+ if (this.contentChangeListeners[i] === listener) {
12899
+ return;
12900
+ }
12901
+ }
12902
+ this.contentChangeListeners.push(listener);
12903
+ }
12904
+ /**
12905
+ * Removes an existing content change listener from this instance.
12906
+ *
12907
+ * @param {PBContentChangeListener} listener - The listenre to add.
12908
+ * @method removeContentChangeListener
12909
+ * @instance
12910
+ * @memberof PlotBoilerplate
12911
+ * @returns {void}
12912
+ */
12913
+ removeContentChangeListener(listener) {
12914
+ for (var i = 0; i < this.contentChangeListeners.length; i++) {
12915
+ if (this.contentChangeListeners[i] === listener) {
12916
+ this.contentChangeListeners.splice(i, 1);
12917
+ return;
12918
+ }
12919
+ }
12920
+ }
12921
+ _fireContentChanged(addedDrawables, removedDrawables) {
12922
+ for (var i in this.contentChangeListeners) {
12923
+ const listener = this.contentChangeListeners[i];
12924
+ if (listener && typeof listener === "function") {
12925
+ listener({
12926
+ type: addedDrawables.length > 0 ? "DRAWABLES_ADDED" : "DRAWABLES_REMOVED",
12927
+ addedDrawables: addedDrawables,
12928
+ removedDrawables: removedDrawables
12929
+ });
12930
+ }
12931
+ }
12932
+ }
12819
12933
  /**
12820
12934
  * Add a drawable object.<br>
12821
12935
  * <br>
@@ -12840,100 +12954,121 @@ class PlotBoilerplate {
12840
12954
  * @memberof PlotBoilerplate
12841
12955
  * @return {void}
12842
12956
  **/
12843
- add(drawable, redraw) {
12957
+ add(drawable, redraw, doNotFireEvent) {
12844
12958
  if (Array.isArray(drawable)) {
12845
12959
  const arr = drawable;
12846
12960
  for (var i = 0; i < arr.length; i++) {
12847
- this.add(arr[i], false);
12961
+ this.add(arr[i], false, doNotFireEvent);
12848
12962
  }
12963
+ // !doNotFireEvent && this._fireContentChanged(arr, []);
12849
12964
  }
12850
- else if (drawable instanceof Vertex) {
12851
- this.drawables.push(drawable);
12852
- this.vertices.push(drawable);
12853
- }
12854
- else if (drawable instanceof Line) {
12855
- // Add some lines
12856
- this.drawables.push(drawable);
12857
- this.vertices.push(drawable.a);
12858
- this.vertices.push(drawable.b);
12859
- }
12860
- else if (drawable instanceof Vector) {
12861
- this.drawables.push(drawable);
12862
- this.vertices.push(drawable.a);
12863
- this.vertices.push(drawable.b);
12864
- }
12865
- else if (drawable instanceof VEllipse) {
12866
- this.vertices.push(drawable.center);
12867
- this.vertices.push(drawable.axis);
12868
- this.drawables.push(drawable);
12869
- drawable.center.listeners.addDragListener((event) => {
12870
- drawable.axis.add(event.params.dragAmount);
12871
- });
12872
- }
12873
- else if (drawable instanceof VEllipseSector) {
12874
- this.vertices.push(drawable.ellipse.center);
12875
- this.vertices.push(drawable.ellipse.axis);
12876
- this.drawables.push(drawable);
12877
- drawable.ellipse.center.listeners.addDragListener((event) => {
12878
- drawable.ellipse.axis.add(event.params.dragAmount);
12879
- });
12880
- }
12881
- else if (drawable instanceof Circle) {
12882
- this.vertices.push(drawable.center);
12883
- this.drawables.push(drawable);
12884
- }
12885
- else if (drawable instanceof CircleSector) {
12886
- this.vertices.push(drawable.circle.center);
12887
- this.drawables.push(drawable);
12888
- }
12889
- else if (drawable instanceof Polygon) {
12890
- this.drawables.push(drawable);
12891
- for (var i = 0; i < drawable.vertices.length; i++) {
12892
- this.vertices.push(drawable.vertices[i]);
12965
+ else {
12966
+ const addedDrawables = [drawable];
12967
+ if (drawable instanceof Vertex) {
12968
+ this.drawables.push(drawable);
12969
+ this.vertices.push(drawable);
12893
12970
  }
12894
- }
12895
- else if (drawable instanceof Triangle) {
12896
- this.drawables.push(drawable);
12897
- this.vertices.push(drawable.a);
12898
- this.vertices.push(drawable.b);
12899
- this.vertices.push(drawable.c);
12900
- }
12901
- else if (drawable instanceof BezierPath) {
12902
- this.drawables.push(drawable);
12903
- const bezierPath = drawable;
12904
- for (var i = 0; i < bezierPath.bezierCurves.length; i++) {
12905
- if (!drawable.adjustCircular && i == 0) {
12906
- this.vertices.push(bezierPath.bezierCurves[i].startPoint);
12971
+ else if (drawable instanceof Line) {
12972
+ // Add some lines
12973
+ this.drawables.push(drawable);
12974
+ this.vertices.push(drawable.a);
12975
+ this.vertices.push(drawable.b);
12976
+ addedDrawables.push(drawable.a, drawable.b);
12977
+ }
12978
+ else if (drawable instanceof Vector) {
12979
+ this.drawables.push(drawable);
12980
+ this.vertices.push(drawable.a);
12981
+ this.vertices.push(drawable.b);
12982
+ addedDrawables.push(drawable.a, drawable.b);
12983
+ drawable.a.listeners.addDragListener((event) => {
12984
+ drawable.b.add(event.params.dragAmount);
12985
+ });
12986
+ }
12987
+ else if (drawable instanceof VEllipse) {
12988
+ this.vertices.push(drawable.center);
12989
+ this.vertices.push(drawable.axis);
12990
+ addedDrawables.push(drawable.center, drawable.axis);
12991
+ this.drawables.push(drawable);
12992
+ drawable.center.listeners.addDragListener((event) => {
12993
+ drawable.axis.add(event.params.dragAmount);
12994
+ });
12995
+ }
12996
+ else if (drawable instanceof VEllipseSector) {
12997
+ this.vertices.push(drawable.ellipse.center);
12998
+ this.vertices.push(drawable.ellipse.axis);
12999
+ addedDrawables.push(drawable.ellipse.center, drawable.ellipse.axis);
13000
+ this.drawables.push(drawable);
13001
+ drawable.ellipse.center.listeners.addDragListener((event) => {
13002
+ drawable.ellipse.axis.add(event.params.dragAmount);
13003
+ });
13004
+ }
13005
+ else if (drawable instanceof Circle) {
13006
+ this.vertices.push(drawable.center);
13007
+ addedDrawables.push(drawable.center);
13008
+ this.drawables.push(drawable);
13009
+ }
13010
+ else if (drawable instanceof CircleSector) {
13011
+ this.vertices.push(drawable.circle.center);
13012
+ addedDrawables.push(drawable.circle.center);
13013
+ this.drawables.push(drawable);
13014
+ }
13015
+ else if (drawable instanceof Polygon) {
13016
+ this.drawables.push(drawable);
13017
+ for (var i = 0; i < drawable.vertices.length; i++) {
13018
+ this.vertices.push(drawable.vertices[i]);
13019
+ addedDrawables.push(drawable.vertices[i]);
12907
13020
  }
12908
- this.vertices.push(bezierPath.bezierCurves[i].endPoint);
12909
- this.vertices.push(bezierPath.bezierCurves[i].startControlPoint);
12910
- this.vertices.push(bezierPath.bezierCurves[i].endControlPoint);
12911
- bezierPath.bezierCurves[i].startControlPoint.attr.selectable = false;
12912
- bezierPath.bezierCurves[i].endControlPoint.attr.selectable = false;
12913
13021
  }
12914
- PlotBoilerplate.utils.enableBezierPathAutoAdjust(drawable);
12915
- }
12916
- else if (drawable instanceof PBImage) {
12917
- this.vertices.push(drawable.upperLeft);
12918
- this.vertices.push(drawable.lowerRight);
12919
- this.drawables.push(drawable);
12920
- // Todo: think about a IDragEvent interface
12921
- drawable.upperLeft.listeners.addDragListener((e) => {
12922
- drawable.lowerRight.add(e.params.dragAmount);
12923
- });
12924
- drawable.lowerRight.attr.selectable = false;
12925
- }
12926
- else if (drawable instanceof PBText) {
12927
- this.vertices.push(drawable.anchor);
12928
- this.drawables.push(drawable);
12929
- drawable.anchor.attr.selectable = false;
12930
- }
12931
- else {
12932
- throw "Cannot add drawable of unrecognized type: " + typeof drawable + ".";
13022
+ else if (drawable instanceof Triangle) {
13023
+ this.drawables.push(drawable);
13024
+ this.vertices.push(drawable.a);
13025
+ this.vertices.push(drawable.b);
13026
+ this.vertices.push(drawable.c);
13027
+ addedDrawables.push(drawable.a, drawable.b, drawable.c);
13028
+ }
13029
+ else if (drawable instanceof BezierPath) {
13030
+ this.drawables.push(drawable);
13031
+ const bezierPath = drawable;
13032
+ for (var i = 0; i < bezierPath.bezierCurves.length; i++) {
13033
+ if (!drawable.adjustCircular && i == 0) {
13034
+ this.vertices.push(bezierPath.bezierCurves[i].startPoint);
13035
+ addedDrawables.push(bezierPath.bezierCurves[i].startPoint);
13036
+ }
13037
+ this.vertices.push(bezierPath.bezierCurves[i].endPoint);
13038
+ this.vertices.push(bezierPath.bezierCurves[i].startControlPoint);
13039
+ this.vertices.push(bezierPath.bezierCurves[i].endControlPoint);
13040
+ addedDrawables.push(bezierPath.bezierCurves[i].endPoint, bezierPath.bezierCurves[i].startControlPoint, bezierPath.bezierCurves[i].endControlPoint);
13041
+ bezierPath.bezierCurves[i].startControlPoint.attr.selectable = false;
13042
+ bezierPath.bezierCurves[i].endControlPoint.attr.selectable = false;
13043
+ }
13044
+ PlotBoilerplate.utils.enableBezierPathAutoAdjust(drawable);
13045
+ }
13046
+ else if (drawable instanceof PBImage) {
13047
+ this.vertices.push(drawable.upperLeft);
13048
+ this.vertices.push(drawable.lowerRight);
13049
+ addedDrawables.push(drawable.upperLeft, drawable.lowerRight);
13050
+ this.drawables.push(drawable);
13051
+ // Todo: think about a IDragEvent interface
13052
+ drawable.upperLeft.listeners.addDragListener((e) => {
13053
+ drawable.lowerRight.add(e.params.dragAmount);
13054
+ });
13055
+ drawable.lowerRight.attr.selectable = false;
13056
+ }
13057
+ else if (drawable instanceof PBText) {
13058
+ this.vertices.push(drawable.anchor);
13059
+ addedDrawables.push(drawable.anchor);
13060
+ this.drawables.push(drawable);
13061
+ drawable.anchor.attr.selectable = false;
13062
+ }
13063
+ else {
13064
+ throw "Cannot add drawable of unrecognized type: " + typeof drawable + ".";
13065
+ }
13066
+ !doNotFireEvent && this._fireContentChanged(addedDrawables, []);
12933
13067
  }
12934
13068
  // This is a workaround for backwards compatibility when the 'redraw' param was not yet present.
12935
- if (redraw || typeof redraw == "undefined")
13069
+ if (redraw || typeof redraw == "undefined") {
12936
13070
  this.redraw();
13071
+ }
12937
13072
  }
12938
13073
  /**
12939
13074
  * Remove a drawable object.<br>
@@ -12953,88 +13088,113 @@ class PlotBoilerplate {
12953
13088
  *
12954
13089
  * @param {Drawable|Array<Drawable>} drawable - The drawable (of one of the allowed class instance) to remove.
12955
13090
  * @param {boolean} [redraw=false]
13091
+ * @param {removeWidth}
12956
13092
  * @method remove
12957
13093
  * @instance
12958
13094
  * @memberof PlotBoilerplate
12959
13095
  * @return {void}
12960
13096
  **/
12961
- remove(drawable, redraw, removeWithVertices) {
13097
+ remove(drawable, redraw, removeWithVertices, doNotFireEvent) {
12962
13098
  if (Array.isArray(drawable)) {
13099
+ const removedDrawables = [];
12963
13100
  for (var i = 0; i < drawable.length; i++) {
12964
- this.remove(drawable[i], false, removeWithVertices);
13101
+ if (this.remove(drawable[i], false, removeWithVertices, true)) {
13102
+ removedDrawables.push(drawable[i]);
13103
+ }
12965
13104
  }
12966
13105
  if (redraw) {
12967
13106
  this.redraw();
12968
13107
  }
12969
- return;
13108
+ !doNotFireEvent && this._fireContentChanged([], removedDrawables);
13109
+ return removedDrawables.length > 0;
12970
13110
  }
12971
13111
  if (drawable instanceof Vertex) {
12972
- this.removeVertex(drawable, false);
13112
+ const wasRemoved = this.removeVertex(drawable, false, false);
12973
13113
  if (redraw) {
12974
13114
  this.redraw();
12975
13115
  }
13116
+ !doNotFireEvent && this._fireContentChanged([], [drawable]);
13117
+ return wasRemoved;
12976
13118
  }
13119
+ let wasRemoved = false;
13120
+ const removedDrawables = [];
12977
13121
  for (var i = 0; i < this.drawables.length; i++) {
12978
13122
  if (this.drawables[i] === drawable || this.drawables[i].uid === drawable.uid) {
12979
13123
  this.drawables.splice(i, 1);
13124
+ removedDrawables.push(drawable);
12980
13125
  if (removeWithVertices) {
12981
13126
  // Check if some listeners need to be removed
12982
13127
  if (drawable instanceof Line) {
12983
13128
  // Add some lines
12984
- this.removeVertex(drawable.a, false);
12985
- this.removeVertex(drawable.b, false);
13129
+ this.removeVertex(drawable.a, false, true);
13130
+ this.removeVertex(drawable.b, false, true);
13131
+ removedDrawables.push(drawable.a, drawable.b);
12986
13132
  }
12987
13133
  else if (drawable instanceof Vector) {
12988
- this.removeVertex(drawable.a, false);
12989
- this.removeVertex(drawable.b, false);
13134
+ this.removeVertex(drawable.a, false, true);
13135
+ this.removeVertex(drawable.b, false, true);
13136
+ removedDrawables.push(drawable.a, drawable.b);
12990
13137
  }
12991
13138
  else if (drawable instanceof VEllipse) {
12992
- this.removeVertex(drawable.center, false);
12993
- this.removeVertex(drawable.axis, false);
13139
+ this.removeVertex(drawable.center, false, true);
13140
+ this.removeVertex(drawable.axis, false, true);
13141
+ removedDrawables.push(drawable.center, drawable.axis);
12994
13142
  }
12995
13143
  else if (drawable instanceof VEllipseSector) {
12996
- this.removeVertex(drawable.ellipse.center);
12997
- this.removeVertex(drawable.ellipse.axis);
13144
+ this.removeVertex(drawable.ellipse.center, false, true);
13145
+ this.removeVertex(drawable.ellipse.axis, false, true);
13146
+ removedDrawables.push(drawable.ellipse.center, drawable.ellipse.axis);
12998
13147
  }
12999
13148
  else if (drawable instanceof Circle) {
13000
- this.removeVertex(drawable.center, false);
13149
+ this.removeVertex(drawable.center, false, true);
13001
13150
  }
13002
13151
  else if (drawable instanceof CircleSector) {
13003
- this.removeVertex(drawable.circle.center, false);
13152
+ this.removeVertex(drawable.circle.center, false, true);
13153
+ removedDrawables.push(drawable.circle.center);
13004
13154
  }
13005
13155
  else if (drawable instanceof Polygon) {
13006
13156
  // for( var i in drawable.vertices )
13007
- for (var i = 0; i < drawable.vertices.length; i++)
13008
- this.removeVertex(drawable.vertices[i], false);
13157
+ for (var i = 0; i < drawable.vertices.length; i++) {
13158
+ this.removeVertex(drawable.vertices[i], false, true);
13159
+ removedDrawables.push(drawable.vertices[i]);
13160
+ }
13009
13161
  }
13010
13162
  else if (drawable instanceof Triangle) {
13011
- this.removeVertex(drawable.a, false);
13012
- this.removeVertex(drawable.b, false);
13013
- this.removeVertex(drawable.c, false);
13163
+ this.removeVertex(drawable.a, false, true);
13164
+ this.removeVertex(drawable.b, false, true);
13165
+ this.removeVertex(drawable.c, false, true);
13166
+ removedDrawables.push(drawable.a, drawable.b, drawable.c);
13014
13167
  }
13015
13168
  else if (drawable instanceof BezierPath) {
13016
13169
  for (var i = 0; i < drawable.bezierCurves.length; i++) {
13017
- this.removeVertex(drawable.bezierCurves[i].startPoint, false);
13018
- this.removeVertex(drawable.bezierCurves[i].startControlPoint, false);
13019
- this.removeVertex(drawable.bezierCurves[i].endControlPoint, false);
13170
+ this.removeVertex(drawable.bezierCurves[i].startPoint, false, true);
13171
+ this.removeVertex(drawable.bezierCurves[i].startControlPoint, false, true);
13172
+ this.removeVertex(drawable.bezierCurves[i].endControlPoint, false, true);
13173
+ removedDrawables.push(drawable.bezierCurves[i].startPoint, drawable.bezierCurves[i].startControlPoint, drawable.bezierCurves[i].endControlPoint);
13020
13174
  if (i + 1 == drawable.bezierCurves.length) {
13021
- this.removeVertex(drawable.bezierCurves[i].endPoint, false);
13175
+ this.removeVertex(drawable.bezierCurves[i].endPoint, false, true);
13176
+ removedDrawables.push(drawable.bezierCurves[i].endPoint);
13022
13177
  }
13023
13178
  }
13024
13179
  }
13025
13180
  else if (drawable instanceof PBImage) {
13026
- this.removeVertex(drawable.upperLeft, false);
13027
- this.removeVertex(drawable.lowerRight, false);
13181
+ this.removeVertex(drawable.upperLeft, false, true);
13182
+ this.removeVertex(drawable.lowerRight, false, true);
13183
+ removedDrawables.push(drawable.upperLeft, drawable.lowerRight);
13028
13184
  }
13029
13185
  else if (drawable instanceof PBText) {
13030
- this.removeVertex(drawable.anchor, false);
13186
+ this.removeVertex(drawable.anchor, false, true);
13187
+ removedDrawables.push(drawable.anchor);
13031
13188
  }
13032
13189
  } // END removeWithVertices
13033
13190
  if (redraw) {
13034
13191
  this.redraw();
13035
13192
  }
13036
- }
13037
- }
13193
+ !doNotFireEvent && this._fireContentChanged([], removedDrawables);
13194
+ wasRemoved = true;
13195
+ } // END if
13196
+ } // END for
13197
+ return wasRemoved;
13038
13198
  }
13039
13199
  /**
13040
13200
  * Remove a vertex from the vertex list.<br>
@@ -13044,18 +13204,20 @@ class PlotBoilerplate {
13044
13204
  * @method removeVertex
13045
13205
  * @instance
13046
13206
  * @memberof PlotBoilerplate
13047
- * @return {void}
13207
+ * @return {boolean}
13048
13208
  **/
13049
- removeVertex(vert, redraw) {
13209
+ removeVertex(vert, redraw, doNotFireEvent) {
13050
13210
  for (var i = 0; i < this.vertices.length; i++) {
13051
13211
  if (this.vertices[i] === vert) {
13052
13212
  this.vertices.splice(i, 1);
13053
13213
  if (redraw) {
13054
13214
  this.redraw();
13055
13215
  }
13056
- return;
13216
+ !doNotFireEvent && this._fireContentChanged([], [vert]);
13217
+ return true;
13057
13218
  }
13058
13219
  }
13220
+ return false;
13059
13221
  }
13060
13222
  /**
13061
13223
  * Remove all elements.
@@ -13070,13 +13232,16 @@ class PlotBoilerplate {
13070
13232
  * @return {void}
13071
13233
  */
13072
13234
  removeAll(keepVertices, triggerRedraw) {
13235
+ let removedDrawables = this.drawables;
13073
13236
  this.drawables = [];
13074
13237
  if (!Boolean(keepVertices)) {
13238
+ removedDrawables = removedDrawables.concat(this.vertices);
13075
13239
  this.vertices = [];
13076
13240
  }
13077
13241
  if (triggerRedraw || typeof triggerRedraw === "undefined") {
13078
13242
  this.redraw();
13079
13243
  }
13244
+ removedDrawables.length > 0 && this._fireContentChanged([], removedDrawables);
13080
13245
  }
13081
13246
  /**
13082
13247
  * Find the vertex near the given position.
@@ -13331,7 +13496,7 @@ class PlotBoilerplate {
13331
13496
  d.b.attr.renderTime = renderTime;
13332
13497
  }
13333
13498
  else if (d instanceof Vector) {
13334
- draw.arrow(d.a, d.b, this.drawConfig.vector.color);
13499
+ draw.arrow(d.a, d.b, this.drawConfig.vector.color, this.drawConfig.vector.lineWidth);
13335
13500
  if (this.drawConfig.drawHandlePoints && d.b.attr.selectable && d.b.attr.visible) {
13336
13501
  draw.setCurrentId(`${d.uid}_h0`);
13337
13502
  draw.setCurrentClassName(`${d.className}-handle`);