plotboilerplate 1.20.2 → 1.22.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 (169) hide show
  1. package/dist/index.esm.js +2012 -1366
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/index.esm.min.js +1 -1
  4. package/dist/index.esm.min.js.map +1 -1
  5. package/dist/plotboilerplate.browser.min.js +1 -1
  6. package/dist/plotboilerplate.browser.min.js.map +1 -1
  7. package/dist/plotboilerplate.js +1199 -541
  8. package/dist/plotboilerplate.min.js +1 -1
  9. package/package.json +3 -2
  10. package/src/cjs/BezierPath.d.ts +27 -49
  11. package/src/cjs/BezierPath.js +67 -234
  12. package/src/cjs/BezierPath.js.map +1 -1
  13. package/src/cjs/Bounds.d.ts +14 -1
  14. package/src/cjs/Bounds.js +21 -1
  15. package/src/cjs/Bounds.js.map +1 -1
  16. package/src/cjs/CubicBezierCurve.d.ts +70 -1
  17. package/src/cjs/CubicBezierCurve.js +130 -12
  18. package/src/cjs/CubicBezierCurve.js.map +1 -1
  19. package/src/cjs/Line.d.ts +2 -1
  20. package/src/cjs/Line.js +1 -0
  21. package/src/cjs/Line.js.map +1 -1
  22. package/src/cjs/PBText.d.ts +2 -1
  23. package/src/cjs/PBText.js +10 -9
  24. package/src/cjs/PBText.js.map +1 -1
  25. package/src/cjs/PlotBoilerplate.d.ts +4 -13
  26. package/src/cjs/PlotBoilerplate.js +61 -15
  27. package/src/cjs/PlotBoilerplate.js.map +1 -1
  28. package/src/cjs/Polygon.d.ts +47 -1
  29. package/src/cjs/Polygon.js +116 -1
  30. package/src/cjs/Polygon.js.map +1 -1
  31. package/src/cjs/VEllipse.js +1 -1
  32. package/src/cjs/VEllipse.js.map +1 -1
  33. package/src/cjs/Vector.d.ts +4 -4
  34. package/src/cjs/Vector.js +2 -2
  35. package/src/cjs/Vector.js.map +1 -1
  36. package/src/cjs/VertTuple.d.ts +2 -1
  37. package/src/cjs/VertTuple.js +4 -3
  38. package/src/cjs/VertTuple.js.map +1 -1
  39. package/src/cjs/Vertex.d.ts +14 -3
  40. package/src/cjs/Vertex.js +18 -3
  41. package/src/cjs/Vertex.js.map +1 -1
  42. package/src/cjs/draw.d.ts +154 -75
  43. package/src/cjs/draw.js +308 -137
  44. package/src/cjs/draw.js.map +1 -1
  45. package/src/cjs/drawgl.d.ts +87 -50
  46. package/src/cjs/drawgl.js +86 -31
  47. package/src/cjs/drawgl.js.map +1 -1
  48. package/src/cjs/drawutilssvg.d.ts +226 -53
  49. package/src/cjs/drawutilssvg.js +374 -92
  50. package/src/cjs/drawutilssvg.js.map +1 -1
  51. package/src/cjs/interfaces/DrawLib.d.ts +157 -79
  52. package/src/cjs/interfaces/DrawLib.js +6 -0
  53. package/src/cjs/interfaces/DrawLib.js.map +1 -1
  54. package/src/cjs/interfaces/core.d.ts +13 -2
  55. package/src/cjs/interfaces/core.js +1 -0
  56. package/src/cjs/interfaces/core.js.map +1 -1
  57. package/src/cjs/utils/Params.d.ts +15 -0
  58. package/src/cjs/utils/Params.js +49 -0
  59. package/src/cjs/utils/Params.js.map +1 -0
  60. package/src/cjs/utils/algorithms/ContourLineDetection.d.ts +150 -0
  61. package/src/cjs/utils/algorithms/ContourLineDetection.js +367 -0
  62. package/src/cjs/utils/algorithms/ContourLineDetection.js.map +1 -0
  63. package/src/cjs/utils/algorithms/clearDuplicateVertices.d.ts +21 -0
  64. package/src/cjs/utils/algorithms/clearDuplicateVertices.js +48 -0
  65. package/src/cjs/utils/algorithms/clearDuplicateVertices.js.map +1 -0
  66. package/src/cjs/utils/creategui.js +16 -10
  67. package/src/cjs/utils/datastructures/DataGrid2d.d.ts +47 -0
  68. package/src/cjs/utils/datastructures/DataGrid2d.js +20 -0
  69. package/src/cjs/utils/datastructures/DataGrid2d.js.map +1 -0
  70. package/src/cjs/utils/datastructures/DataGrid2dListAdapter.d.ts +65 -0
  71. package/src/cjs/utils/datastructures/DataGrid2dListAdapter.js +84 -0
  72. package/src/cjs/utils/datastructures/DataGrid2dListAdapter.js.map +1 -0
  73. package/src/cjs/utils/datastructures/GenericPath.d.ts +14 -3
  74. package/src/cjs/utils/datastructures/GenericPath.js +20 -3
  75. package/src/cjs/utils/datastructures/GenericPath.js.map +1 -1
  76. package/src/cjs/utils/detectDarkMode.d.ts +10 -0
  77. package/src/cjs/utils/detectDarkMode.js +32 -0
  78. package/src/cjs/utils/detectDarkMode.js.map +1 -0
  79. package/src/esm/BezierPath.d.ts +27 -49
  80. package/src/esm/BezierPath.js +67 -234
  81. package/src/esm/BezierPath.js.map +1 -1
  82. package/src/esm/Bounds.d.ts +14 -1
  83. package/src/esm/Bounds.js +19 -1
  84. package/src/esm/Bounds.js.map +1 -1
  85. package/src/esm/CubicBezierCurve.d.ts +70 -1
  86. package/src/esm/CubicBezierCurve.js +130 -12
  87. package/src/esm/CubicBezierCurve.js.map +1 -1
  88. package/src/esm/Line.d.ts +2 -1
  89. package/src/esm/Line.js +1 -0
  90. package/src/esm/Line.js.map +1 -1
  91. package/src/esm/PBText.d.ts +2 -1
  92. package/src/esm/PBText.js +10 -9
  93. package/src/esm/PBText.js.map +1 -1
  94. package/src/esm/PlotBoilerplate.d.ts +4 -13
  95. package/src/esm/PlotBoilerplate.js +62 -16
  96. package/src/esm/PlotBoilerplate.js.map +1 -1
  97. package/src/esm/Polygon.d.ts +47 -1
  98. package/src/esm/Polygon.js +114 -1
  99. package/src/esm/Polygon.js.map +1 -1
  100. package/src/esm/VEllipse.js +1 -1
  101. package/src/esm/VEllipse.js.map +1 -1
  102. package/src/esm/Vector.d.ts +4 -4
  103. package/src/esm/Vector.js +2 -2
  104. package/src/esm/Vector.js.map +1 -1
  105. package/src/esm/VertTuple.d.ts +2 -1
  106. package/src/esm/VertTuple.js +4 -3
  107. package/src/esm/VertTuple.js.map +1 -1
  108. package/src/esm/Vertex.d.ts +14 -3
  109. package/src/esm/Vertex.js +18 -3
  110. package/src/esm/Vertex.js.map +1 -1
  111. package/src/esm/draw.d.ts +154 -75
  112. package/src/esm/draw.js +304 -135
  113. package/src/esm/draw.js.map +1 -1
  114. package/src/esm/drawgl.d.ts +87 -50
  115. package/src/esm/drawgl.js +86 -31
  116. package/src/esm/drawgl.js.map +1 -1
  117. package/src/esm/drawutilssvg.d.ts +226 -53
  118. package/src/esm/drawutilssvg.js +369 -92
  119. package/src/esm/drawutilssvg.js.map +1 -1
  120. package/src/esm/interfaces/DrawLib.d.ts +157 -79
  121. package/src/esm/interfaces/DrawLib.js +6 -0
  122. package/src/esm/interfaces/DrawLib.js.map +1 -1
  123. package/src/esm/interfaces/core.d.ts +13 -2
  124. package/src/esm/interfaces/core.js +1 -0
  125. package/src/esm/interfaces/core.js.map +1 -1
  126. package/src/esm/utils/Params.d.ts +15 -0
  127. package/src/esm/utils/Params.js +44 -0
  128. package/src/esm/utils/Params.js.map +1 -0
  129. package/src/esm/utils/algorithms/ContourLineDetection.d.ts +150 -0
  130. package/src/esm/utils/algorithms/ContourLineDetection.js +362 -0
  131. package/src/esm/utils/algorithms/ContourLineDetection.js.map +1 -0
  132. package/src/esm/utils/algorithms/clearDuplicateVertices.d.ts +21 -0
  133. package/src/esm/utils/algorithms/clearDuplicateVertices.js +44 -0
  134. package/src/esm/utils/algorithms/clearDuplicateVertices.js.map +1 -0
  135. package/src/esm/utils/datastructures/DataGrid2d.d.ts +47 -0
  136. package/src/esm/utils/datastructures/DataGrid2d.js +19 -0
  137. package/src/esm/utils/datastructures/DataGrid2d.js.map +1 -0
  138. package/src/esm/utils/datastructures/DataGrid2dListAdapter.d.ts +65 -0
  139. package/src/esm/utils/datastructures/DataGrid2dListAdapter.js +79 -0
  140. package/src/esm/utils/datastructures/DataGrid2dListAdapter.js.map +1 -0
  141. package/src/esm/utils/datastructures/GenericPath.d.ts +14 -3
  142. package/src/esm/utils/datastructures/GenericPath.js +20 -3
  143. package/src/esm/utils/datastructures/GenericPath.js.map +1 -1
  144. package/src/esm/utils/detectDarkMode.d.ts +10 -0
  145. package/src/esm/utils/detectDarkMode.js +28 -0
  146. package/src/esm/utils/detectDarkMode.js.map +1 -0
  147. package/src/ts/BezierPath.ts +72 -241
  148. package/src/ts/Bounds.ts +25 -1
  149. package/src/ts/CubicBezierCurve.ts +139 -12
  150. package/src/ts/Line.ts +2 -1
  151. package/src/ts/PBText.ts +10 -9
  152. package/src/ts/PlotBoilerplate.ts +56 -19
  153. package/src/ts/Polygon.ts +121 -1
  154. package/src/ts/VEllipse.ts +2 -2
  155. package/src/ts/Vector.ts +4 -4
  156. package/src/ts/VertTuple.ts +4 -3
  157. package/src/ts/Vertex.ts +20 -4
  158. package/src/ts/draw.ts +311 -115
  159. package/src/ts/drawgl.ts +133 -71
  160. package/src/ts/drawutilssvg.ts +543 -121
  161. package/src/ts/interfaces/DrawLib.ts +219 -83
  162. package/src/ts/interfaces/core.ts +14 -2
  163. package/src/ts/utils/Params.ts +47 -0
  164. package/src/ts/utils/algorithms/ContourLineDetection.ts +485 -0
  165. package/src/ts/utils/algorithms/clearDuplicateVertices.ts +49 -0
  166. package/src/ts/utils/datastructures/DataGrid2d.ts +54 -0
  167. package/src/ts/utils/datastructures/DataGrid2dListAdapter.ts +121 -0
  168. package/src/ts/utils/datastructures/GenericPath.ts +21 -3
  169. package/src/ts/utils/detectDarkMode.ts +30 -0
package/src/ts/Bounds.ts CHANGED
@@ -8,12 +8,14 @@
8
8
  * @modified 2022-02-01 Added the `toString` function.
9
9
  * @modified 2022-10-09 Added the `fromDimension` function.
10
10
  * @modified 2022-11-28 Added the `clone` method.
11
- * @version 1.6.0
11
+ * @modified 2023-09-29 Added the `randomPoint` method.
12
+ * @version 1.7.0
12
13
  **/
13
14
 
14
15
  import { Polygon } from "./Polygon";
15
16
  import { XYCoords, IBounds, XYDimension } from "./interfaces";
16
17
  import { Vertex } from "./Vertex";
18
+ import { VertTuple } from "./VertTuple";
17
19
 
18
20
  /**
19
21
  * @classdesc A bounds class with min and max values. Implementing IBounds.
@@ -97,6 +99,28 @@ export class Bounds implements IBounds, XYDimension {
97
99
  return new Vertex(this.min.x + (this.max.x - this.min.x) / 2.0, this.min.y + (this.max.y - this.min.y) / 2);
98
100
  }
99
101
 
102
+ /**
103
+ * Generate a random point inside this bounds object. Safe areas at the border to avoid
104
+ * included.
105
+ *
106
+ * @method randomPoint
107
+ * @instance
108
+ * @memberof Bounds
109
+ * @param {horizontalSafeArea} - (optional) The horizonal (left and right) safe area. No vertex will be created here. Can be used as percent in (0.0 ... 0.1) interval.
110
+ * @param {verticalSafeArea} - (optional) The vertical (top and bottom) safe area. No vertex will be created here. Can be used as percent in (0.0 ... 0.1) interval
111
+ * @returns {Vertex} A pseudo random point inside these bounds.
112
+ */
113
+ randomPoint(horizontalSafeArea: number = 0, verticalSafeArea: number = 0): Vertex {
114
+ // Check if the safe areas are meant as percent
115
+ const absHorizontalSafeArea =
116
+ horizontalSafeArea > 0 && horizontalSafeArea < 1 ? this.width * horizontalSafeArea : horizontalSafeArea;
117
+ const absVerticalSafeArea = verticalSafeArea > 0 && verticalSafeArea < 1 ? this.height * verticalSafeArea : verticalSafeArea;
118
+ return new Vertex(
119
+ this.min.x + absHorizontalSafeArea + Math.random() * (this.width - 2 * absHorizontalSafeArea),
120
+ this.min.y + absVerticalSafeArea + Math.random() * (this.height - 2 * absVerticalSafeArea)
121
+ );
122
+ }
123
+
100
124
  /**
101
125
  * Convert these bounds to a human readable form.
102
126
  *
@@ -21,7 +21,9 @@
21
21
  * @modified 2022-02-02 Added the `destroy` method.
22
22
  * @modified 2022-02-02 Cleared the `toSVGPathData` function (deprecated). Use `drawutilssvg` instead.
23
23
  * @modified 2022-10-17 The `CubicBezierCurve` class now implements the new `PathSegment` interface.
24
- * @version 2.7.1
24
+ * @modified 2023-09-30 Added the function `CubicbezierCurve.getSubCurve(number,number)` – similar to `getSubCurveAt(...)` but with absolute position parameters.
25
+ * @modified 2023-10-07 Added the `trimEnd`, `trimEndAt`, `trimStart`, `trimStartAt` methods.
26
+ * @version 2.8.0
25
27
  *
26
28
  * @file CubicBezierCurve
27
29
  * @public
@@ -523,6 +525,96 @@ export class CubicBezierCurve implements PathSegment {
523
525
  return new Vertex(tX, tY);
524
526
  }
525
527
 
528
+ /**
529
+ * Trim off a start section of this curve. The position parameter `uValue` is the absolute position on the
530
+ * curve in `[0...arcLength]`.
531
+ * The remaining curve will be the one in the bounds `[uValue,1]` (so `[0.0,uValue]` is cut off).
532
+ *
533
+ * Note this function just converts the absolute parameter to a relative one and call `trimStartAt`.
534
+ *
535
+ * @method trimStart
536
+ * @instance
537
+ * @memberof CubicBezierCurve
538
+ * @param {number} uValue - The absolute position parameter where to cut off the head curve.
539
+ * @returns {CubicBezierCurve} `this` for chanining.
540
+ */
541
+ trimStart(uValue: number): CubicBezierCurve {
542
+ return this.trimStartAt(this.convertU2T(uValue));
543
+ }
544
+
545
+ /**
546
+ * Trim off a start section of this curve. The position parameter `t` is the relative position in [0..1].
547
+ * The remaining curve will be the one in the bounds `[uValue,1]` (so `[0.0,uValue]` is cut off).
548
+ *
549
+ * @method trimStartAt
550
+ * @instance
551
+ * @memberof CubicBezierCurve
552
+ * @param {number} t - The relative position parameter where to cut off the head curve.
553
+ * @returns {CubicBezierCurve} `this` for chanining.
554
+ */
555
+ trimStartAt(t: number): CubicBezierCurve {
556
+ const subCurbePoints = CubicBezierCurve.utils.getSubCurvePointsAt(this, t, 1.0);
557
+ this.startPoint.set(subCurbePoints[0]);
558
+ this.startControlPoint.set(subCurbePoints[2]);
559
+ this.endPoint.set(subCurbePoints[1]);
560
+ this.endControlPoint.set(subCurbePoints[3]);
561
+ this.updateArcLengths();
562
+ return this;
563
+ }
564
+
565
+ /**
566
+ * Trim off the end of this curve. The position parameter `uValue` is the absolute position on the
567
+ * curve in `[0...arcLength]`.
568
+ * The remaining curve will be the one in the bounds `[0,uValue]` (so `[1.0-uValue,1.0]` is cut off).
569
+ *
570
+ * Note this function just converts the absolute parameter to a relative one and call `trimEndAt`.
571
+ *
572
+ * @method trimEnd
573
+ * @instance
574
+ * @memberof CubicBezierCurve
575
+ * @param {number} uValue - The absolute position parameter where to cut off the tail curve.
576
+ * @returns {CubicBezierCurve} `this` for chanining.
577
+ */
578
+ trimEnd(uValue: number): CubicBezierCurve {
579
+ return this.trimEndAt(this.convertU2T(uValue));
580
+ }
581
+
582
+ /**
583
+ * Trim off the end of this curve. The position parameter `t` is the relative position in [0..1].
584
+ * The remaining curve will be the one in the bounds `[0,t]` (so `[1.0-t,1.0]` is cut off).
585
+ *
586
+ * @method trimEndAt
587
+ * @instance
588
+ * @memberof CubicBezierCurve
589
+ * @param {number} t - The relative position parameter where to cut off the tail curve.
590
+ * @returns {CubicBezierCurve} `this` for chanining.
591
+ */
592
+ trimEndAt(t: number): CubicBezierCurve {
593
+ const subCurbePoints = CubicBezierCurve.utils.getSubCurvePointsAt(this, 0.0, t);
594
+ this.startPoint.set(subCurbePoints[0]);
595
+ this.startControlPoint.set(subCurbePoints[2]);
596
+ this.endPoint.set(subCurbePoints[1]);
597
+ this.endControlPoint.set(subCurbePoints[3]);
598
+ this.updateArcLengths();
599
+ return this;
600
+ }
601
+
602
+ /**
603
+ * Get a sub curve at the given start end end positions (values on the curve's length, between 0 and curve.arcLength).
604
+ *
605
+ * tStart >= tEnd is allowed, you will get a reversed sub curve then.
606
+ *
607
+ * @method getSubCurve
608
+ * @param {number} tStart – The start position of the desired sub curve (must be in [0..arcLength]).
609
+ * @param {number} tEnd – The end position if the desired cub curve (must be in [0..arcLength]).
610
+ * @instance
611
+ * @memberof CubicBezierCurve
612
+ * @return {CubicBezierCurve} The sub curve as a new curve.
613
+ **/
614
+ getSubCurve(uStart: number, uEnd: number): CubicBezierCurve {
615
+ return this.getSubCurveAt(this.convertU2T(uStart), this.convertU2T(uEnd));
616
+ }
617
+
526
618
  /**
527
619
  * Get a sub curve at the given start end end offsets (values between 0.0 and 1.0).
528
620
  *
@@ -536,20 +628,22 @@ export class CubicBezierCurve implements PathSegment {
536
628
  * @return {CubicBezierCurve} The sub curve as a new curve.
537
629
  **/
538
630
  getSubCurveAt(tStart: number, tEnd: number): CubicBezierCurve {
539
- const startVec: Vector = new Vector(this.getPointAt(tStart), this.getTangentAt(tStart));
540
- const endVec: Vector = new Vector(this.getPointAt(tEnd), this.getTangentAt(tEnd).inv());
631
+ // const startVec: Vector = new Vector(this.getPointAt(tStart), this.getTangentAt(tStart));
632
+ // const endVec: Vector = new Vector(this.getPointAt(tEnd), this.getTangentAt(tEnd).inv());
541
633
 
542
- // Tangents are relative. Make absolute.
543
- startVec.b.add(startVec.a);
544
- endVec.b.add(endVec.a);
634
+ // // Tangents are relative. Make absolute.
635
+ // startVec.b.add(startVec.a);
636
+ // endVec.b.add(endVec.a);
545
637
 
546
- // This 'splits' the curve at the given point at t.
547
- startVec.scale(0.33333333 * (tEnd - tStart));
548
- endVec.scale(0.33333333 * (tEnd - tStart));
638
+ // // This 'splits' the curve at the given point at t.
639
+ // startVec.scale(0.33333333 * (tEnd - tStart));
640
+ // endVec.scale(0.33333333 * (tEnd - tStart));
549
641
 
550
- // Draw the bezier curve
551
- // pb.draw.cubicBezier( startVec.a, endVec.a, startVec.b, endVec.b, '#8800ff', 2 );
552
- return new CubicBezierCurve(startVec.a, endVec.a, startVec.b, endVec.b);
642
+ // // Draw the bezier curve
643
+ // // pb.draw.cubicBezier( startVec.a, endVec.a, startVec.b, endVec.b, '#8800ff', 2 );
644
+ // return new CubicBezierCurve(startVec.a, endVec.a, startVec.b, endVec.b);
645
+ const subCurbePoints = CubicBezierCurve.utils.getSubCurvePointsAt(this, tStart, tEnd);
646
+ return new CubicBezierCurve(subCurbePoints[0], subCurbePoints[1], subCurbePoints[2], subCurbePoints[3]);
553
647
  }
554
648
 
555
649
  /**
@@ -813,4 +907,37 @@ export class CubicBezierCurve implements PathSegment {
813
907
  if (arr.length != 4) throw "Can only build from array with four elements.";
814
908
  return new CubicBezierCurve(arr[0], arr[1], arr[2], arr[3]);
815
909
  }
910
+
911
+ /**
912
+ * Helper utils.
913
+ */
914
+ private static utils = {
915
+ /**
916
+ * Get the points of a sub curve at the given start end end offsets (values between 0.0 and 1.0).
917
+ *
918
+ * tStart >= tEnd is allowed, you will get a reversed sub curve then.
919
+ *
920
+ * @method getSubCurvePointsAt
921
+ * @param {CubicBezierCurve} curve – The curve to get the sub curve points from.
922
+ * @param {number} tStart – The start offset of the desired sub curve (must be in [0..1]).
923
+ * @param {number} tEnd – The end offset if the desired cub curve (must be in [0..1]).
924
+ * @instance
925
+ * @memberof CubicBezierCurve
926
+ * @return {CubicBezierCurve} The sub curve as a new curve.
927
+ **/
928
+ getSubCurvePointsAt: (curve: CubicBezierCurve, tStart: number, tEnd: number): [Vertex, Vertex, Vertex, Vertex] => {
929
+ const startVec: Vector = new Vector(curve.getPointAt(tStart), curve.getTangentAt(tStart));
930
+ const endVec: Vector = new Vector(curve.getPointAt(tEnd), curve.getTangentAt(tEnd).inv());
931
+
932
+ // Tangents are relative. Make absolute.
933
+ startVec.b.add(startVec.a);
934
+ endVec.b.add(endVec.a);
935
+
936
+ // This 'splits' the curve at the given point at t.
937
+ startVec.scale(0.33333333 * (tEnd - tStart));
938
+ endVec.scale(0.33333333 * (tEnd - tStart));
939
+
940
+ return [startVec.a, endVec.a, startVec.b, endVec.b];
941
+ }
942
+ };
816
943
  }
package/src/ts/Line.ts CHANGED
@@ -15,6 +15,7 @@
15
15
  * @modified 2022-02-02 Added the `destroy` method.
16
16
  * @modified 2022-10-09 Changed the actual return value of the `intersection` function to null (was undefined before).
17
17
  * @modified 2022-10-17 Adding these methods from the `PathSegment` interface: getStartPoint, getEndPoint, revert.
18
+ * @modified 2023-09-25 Changed param type of `intersection()` from Line to VertTuple.
18
19
  * @version 2.3.0
19
20
  *
20
21
  * @file Line
@@ -61,7 +62,7 @@ export class Line extends VertTuple<Line> implements SVGSerializable, PathSegmen
61
62
  * @memberof Line
62
63
  **/
63
64
  // !!! DO NOT MOVE TO VertTuple
64
- intersection(line: Line): Vertex | null {
65
+ intersection(line: VertTuple<any>): Vertex | null {
65
66
  const denominator: number = this.denominator(line);
66
67
  if (denominator == 0) {
67
68
  return null;
package/src/ts/PBText.ts CHANGED
@@ -2,7 +2,8 @@
2
2
  * @author Ikaros Kappler
3
3
  * @date 2021-11-16
4
4
  * @modified 2022-02-02 Added the `destroy` method.
5
- * @version 1.1.0
5
+ * @modified 2023-09-25 Fixed a type error in the constructor. Nothing vital.
6
+ * @version 1.1.1
6
7
  **/
7
8
 
8
9
  import { UIDGenerator } from "./UIDGenerator";
@@ -127,14 +128,14 @@ export class PBText implements SVGSerializable, FontOptions {
127
128
  this.uid = UIDGenerator.next();
128
129
  this.text = text;
129
130
  this.anchor = anchor ?? new Vertex();
130
- this.color = options.color;
131
- this.fontFamily = options.fontFamily;
132
- this.fontSize = options.fontSize;
133
- this.fontStyle = options.fontStyle;
134
- this.fontWeight = options.fontWeight;
135
- this.lineHeight = options.lineHeight;
136
- this.textAlign = options.textAlign;
137
- this.rotation = options.rotation;
131
+ this.color = options?.color;
132
+ this.fontFamily = options?.fontFamily;
133
+ this.fontSize = options?.fontSize;
134
+ this.fontStyle = options?.fontStyle;
135
+ this.fontWeight = options?.fontWeight;
136
+ this.lineHeight = options?.lineHeight;
137
+ this.textAlign = options?.textAlign;
138
+ this.rotation = options?.rotation;
138
139
  }
139
140
 
140
141
  /**
@@ -82,7 +82,8 @@
82
82
  * @modified 2023-02-10 Fixing an issue of the `style.position` setting when `fitToParent=true` from `absolute` to `static` (default).
83
83
  * @modified 2023-02-10 Cleaning up most type errors in the main class (mostly null checks).
84
84
  * @modified 2023-02-10 Adding `enableZoom` and `enablePan` (both default true) to have the option to disable these functions.
85
- * @version 1.17.2
85
+ * @modified 2023-09-29 Adding proper dicionary key and value types to the params of `PlotBoilerplate.utils.safeMergeByKeys` (was `object` before).
86
+ * @version 1.17.3
86
87
  *
87
88
  * @file PlotBoilerplate
88
89
  * @fileoverview The main class.
@@ -399,7 +400,7 @@ export class PlotBoilerplate {
399
400
  visible: true
400
401
  };
401
402
 
402
- if (typeof config.canvas == "undefined") {
403
+ if (typeof config.canvas === "undefined") {
403
404
  throw "No canvas specified.";
404
405
  }
405
406
 
@@ -496,6 +497,10 @@ export class PlotBoilerplate {
496
497
  fill: true
497
498
  }
498
499
  },
500
+ // bezierPath: {
501
+ // color: "#0022a8",
502
+ // lineWidth: 1
503
+ // },
499
504
  polygon: {
500
505
  color: "#0022a8",
501
506
  lineWidth: 1
@@ -557,7 +562,10 @@ export class PlotBoilerplate {
557
562
  this.grid = new Grid(new Vertex(0, 0), new Vertex(50, 50));
558
563
  this.canvasSize = { width: PlotBoilerplate.DEFAULT_CANVAS_WIDTH, height: PlotBoilerplate.DEFAULT_CANVAS_HEIGHT };
559
564
  const canvasElement: Element =
560
- typeof config.canvas == "string" ? (document.querySelector(config.canvas) as Element) : config.canvas;
565
+ typeof config.canvas === "string" ? (document.querySelector(config.canvas) as Element) : config.canvas;
566
+ if (typeof canvasElement === "undefined") {
567
+ throw `Cannot initialize PlotBoilerplate with a null canvas (element "${config.canvas} not found).`;
568
+ }
561
569
  // Which renderer to use: Canvas2D, WebGL (experimental) or SVG?
562
570
  if (canvasElement.tagName.toLowerCase() === "canvas") {
563
571
  this.canvas = canvasElement as HTMLCanvasElement;
@@ -1259,20 +1267,10 @@ export class PlotBoilerplate {
1259
1267
  if (this.drawConfig.drawBezierHandleLines && this.drawConfig.drawHandleLines) {
1260
1268
  draw.setCurrentId(`${d.uid}_l0`);
1261
1269
  draw.setCurrentClassName(`${d.className}-start-line`);
1262
- draw.line(
1263
- d.bezierCurves[c].startPoint,
1264
- d.bezierCurves[c].startControlPoint,
1265
- this.drawConfig.bezier.handleLine.color,
1266
- this.drawConfig.bezier.handleLine.lineWidth
1267
- );
1270
+ draw.handleLine(d.bezierCurves[c].startPoint, d.bezierCurves[c].startControlPoint);
1268
1271
  draw.setCurrentId(`${d.uid}_l1`);
1269
1272
  draw.setCurrentClassName(`${d.className}-end-line`);
1270
- draw.line(
1271
- d.bezierCurves[c].endPoint,
1272
- d.bezierCurves[c].endControlPoint,
1273
- this.drawConfig.bezier.handleLine.color,
1274
- this.drawConfig.bezier.handleLine.lineWidth
1275
- );
1273
+ draw.handleLine(d.bezierCurves[c].endPoint, d.bezierCurves[c].endControlPoint);
1276
1274
  }
1277
1275
  curveIndex++;
1278
1276
  } // END for
@@ -1291,11 +1289,11 @@ export class PlotBoilerplate {
1291
1289
  draw.setCurrentId(`${d.uid}_e0`);
1292
1290
  draw.setCurrentClassName(`${d.className}-v-line`);
1293
1291
  // draw.line( d.center.clone().add(0,d.axis.y-d.center.y), d.axis, '#c8c8c8' );
1294
- draw.line(d.center.clone().add(0, d.signedRadiusV()).rotate(d.rotation, d.center), d.axis, "#c8c8c8");
1292
+ draw.handleLine(d.center.clone().add(0, d.signedRadiusV()).rotate(d.rotation, d.center), d.axis); // , "#c8c8c8");
1295
1293
  draw.setCurrentId(`${d.uid}_e1`);
1296
1294
  draw.setCurrentClassName(`${d.className}-h-line`);
1297
1295
  // draw.line( d.center.clone().add(d.axis.x-d.center.x,0), d.axis, '#c8c8c8' );
1298
- draw.line(d.center.clone().add(d.signedRadiusH(), 0).rotate(d.rotation, d.center), d.axis, "#c8c8c8");
1296
+ draw.handleLine(d.center.clone().add(d.signedRadiusH(), 0).rotate(d.rotation, d.center), d.axis); // , "#c8c8c8");
1299
1297
  }
1300
1298
  draw.setCurrentId(d.uid);
1301
1299
  draw.setCurrentClassName(`${d.className}`);
@@ -2233,7 +2231,45 @@ export class PlotBoilerplate {
2233
2231
  * @param {Object} extension
2234
2232
  * @return {Object} base extended by the new attributes.
2235
2233
  **/
2236
- safeMergeByKeys: (base: Object, extension: Object): Object => {
2234
+ safeMergeByKeys: <KeyType extends string | number | symbol, ValueType>(
2235
+ base: Record<KeyType, ValueType>,
2236
+ extension: Record<KeyType, ValueType>
2237
+ ): Record<KeyType, ValueType> => {
2238
+ for (var k in extension) {
2239
+ if (!extension.hasOwnProperty(k)) {
2240
+ continue;
2241
+ }
2242
+ if (base.hasOwnProperty(k)) {
2243
+ const typ = typeof base[k];
2244
+ const extVal = extension[k];
2245
+ try {
2246
+ if (typ == "boolean") {
2247
+ if (typeof extVal === "string") base[k] = Boolean(!!JSON.parse(extVal)) as unknown as ValueType;
2248
+ else base[k] = extVal as ValueType;
2249
+ } else if (typ == "number") {
2250
+ if (typeof extVal === "string") base[k] = Number(JSON.parse(extVal) * 1) as unknown as ValueType;
2251
+ else base[k] = extension[k] as ValueType;
2252
+ } else if (typ == "function" && typeof extVal == "function") {
2253
+ base[k] = extension[k];
2254
+ } else {
2255
+ // Probably a sting
2256
+ base[k] = extension[k];
2257
+ }
2258
+ } catch (e) {
2259
+ console.error("error in key ", k, extVal, e);
2260
+ }
2261
+ } else {
2262
+ base[k] = extension[k];
2263
+ }
2264
+ }
2265
+ return base;
2266
+ },
2267
+
2268
+ /*
2269
+ __safeMergeByKeys: <KeyType extends string | number | symbol, ValueType extends boolean | number | string | Function>(
2270
+ base: Record<KeyType, ValueType>,
2271
+ extension: Record<KeyType, string>
2272
+ ): Record<KeyType, ValueType> => {
2237
2273
  for (var k in extension) {
2238
2274
  if (!extension.hasOwnProperty(k)) continue;
2239
2275
  if (base.hasOwnProperty(k)) {
@@ -2252,6 +2288,7 @@ export class PlotBoilerplate {
2252
2288
  }
2253
2289
  return base;
2254
2290
  },
2291
+ *()
2255
2292
 
2256
2293
  /**
2257
2294
  * A helper function to scale elements (usually the canvas) using CSS.
@@ -2314,7 +2351,7 @@ export class PlotBoilerplate {
2314
2351
  * @param {boolean} fallback - A default value if the key does not exist.
2315
2352
  * @return {boolean}
2316
2353
  **/
2317
- bool: (obj: any, key: string, fallback: boolean) => {
2354
+ bool: (obj: any, key: string, fallback: boolean | null) => {
2318
2355
  if (!obj.hasOwnProperty(key)) return fallback;
2319
2356
  if (typeof obj[key] == "boolean") return obj[key];
2320
2357
  else {
package/src/ts/Polygon.ts CHANGED
@@ -24,7 +24,11 @@
24
24
  * @modified 2022-02-02 Added the `destroy` method.
25
25
  * @modified 2022-02-02 Cleared the `Polygon.toSVGString` function (deprecated). Use `drawutilssvg` instead.
26
26
  * @modified 2022-03-08 Added the `Polygon.clone()` function.
27
- * @version 1.10.0
27
+ * @modified 2023-09-25 Added the `Polygon.getInterpolationPolygon(number)` function.
28
+ * @modified 2023-09-25 Added the `Polygon.lineIntersections(Line,boolean)` function.
29
+ * @modified 2023-09-29 Added the `Polygon.closestLineIntersection(Line,boolean)` function.
30
+ * @modified 2023-11-24 Added the `Polygon.containsPolygon(Polygon)' function.
31
+ * @version 1.12.0
28
32
  *
29
33
  * @file Polygon
30
34
  * @public
@@ -32,7 +36,9 @@
32
36
 
33
37
  import { BezierPath } from "./BezierPath";
34
38
  import { Bounds } from "./Bounds";
39
+ import { Line } from "./Line";
35
40
  import { UIDGenerator } from "./UIDGenerator";
41
+ import { VertTuple } from "./VertTuple";
36
42
  import { Vertex } from "./Vertex";
37
43
  import { XYCoords, SVGSerializable, UID } from "./interfaces";
38
44
 
@@ -179,6 +185,35 @@ export class Polygon implements SVGSerializable {
179
185
  return inside;
180
186
  }
181
187
 
188
+ /**
189
+ * Check if the passed polygon is completly contained inside this polygon.
190
+ *
191
+ * This means:
192
+ * - all polygon's vertices must be inside this polygon.
193
+ * - the polygon has no edge intersections with this polygon.
194
+ *
195
+ * @param {Polygon} polygon - The polygon to check if contained.
196
+ * @return {boolean}
197
+ */
198
+ containsPolygon(polygon: Polygon): boolean {
199
+ for (var i = 0; i < polygon.vertices.length; i++) {
200
+ if (!this.containsVert(polygon.vertices[i])) {
201
+ return false;
202
+ }
203
+ }
204
+ // All vertices are inside; check for intersections
205
+ const lineSegment = new Line(new Vertex(), new Vertex());
206
+ for (var i = 0; i < polygon.vertices.length; i++) {
207
+ lineSegment.a.set(polygon.vertices[i]);
208
+ lineSegment.b.set(polygon.vertices[(i + 1) % polygon.vertices.length]);
209
+ if (this.lineIntersections(lineSegment, true).length > 0) {
210
+ // Current segment has intersection(s) with this polygon.
211
+ return false;
212
+ }
213
+ }
214
+ return true;
215
+ }
216
+
182
217
  /**
183
218
  * Calculate the area of the given polygon (unsigned).
184
219
  *
@@ -276,6 +311,91 @@ export class Polygon implements SVGSerializable {
276
311
  return this;
277
312
  }
278
313
 
314
+ /**
315
+ * Get all line intersections with this polygon.
316
+ *
317
+ * See demo `47-closest-vector-projection-on-polygon` for how it works.
318
+ *
319
+ * @param {VertTuple} line - The line to find intersections with.
320
+ * @param {boolean} inVectorBoundsOnly - If set to true only intersecion points on the passed vector are returned (located strictly between start and end vertex).
321
+ * @returns {Array<Vertex>} - An array of all intersections within the polygon bounds.
322
+ */
323
+ lineIntersections(line: VertTuple<any>, inVectorBoundsOnly: boolean = false): Array<Vertex> {
324
+ // Find the intersections of all lines inside the edge bounds
325
+ const intersectionPoints: Array<Vertex> = [];
326
+ for (var i = 0; i < this.vertices.length; i++) {
327
+ const polyLine = new Line(this.vertices[i], this.vertices[(i + 1) % this.vertices.length]);
328
+ const intersection = polyLine.intersection(line);
329
+ // true => only inside bounds
330
+ // ignore last edge if open
331
+ if (
332
+ (!this.isOpen || i + 1 !== this.vertices.length) &&
333
+ intersection !== null &&
334
+ polyLine.hasPoint(intersection, true) &&
335
+ (!inVectorBoundsOnly || line.hasPoint(intersection, inVectorBoundsOnly))
336
+ ) {
337
+ intersectionPoints.push(intersection);
338
+ }
339
+ }
340
+ return intersectionPoints;
341
+ }
342
+
343
+ /**
344
+ * Get the closest line-polygon-intersection point (closest the line point A).
345
+ *
346
+ * See demo `47-closest-vector-projection-on-polygon` for how it works.
347
+ *
348
+ * @param {VertTuple} line - The line to find intersections with.
349
+ * @param {boolean} inVectorBoundsOnly - If set to true only intersecion points on the passed vector are considered (located strictly between start and end vertex).
350
+ * @returns {Array<Vertex>} - An array of all intersections within the polygon bounds.
351
+ */
352
+ closestLineIntersection(line: VertTuple<any>, inVectorBoundsOnly: boolean = false): Vertex | null {
353
+ const allIntersections = this.lineIntersections(line, inVectorBoundsOnly);
354
+ if (allIntersections.length <= 0) {
355
+ // Empty polygon -> no intersections
356
+ return null;
357
+ }
358
+ // Find the closest intersection
359
+ let closestIntersection = new Vertex(Number.MAX_VALUE, Number.MAX_VALUE);
360
+ let curDist = Number.MAX_VALUE;
361
+ for (var i in allIntersections) {
362
+ const curVert = allIntersections[i];
363
+ const dist = curVert.distance(line.a);
364
+ if (dist < curDist) {
365
+ // && line.hasPoint(curVert)) {
366
+ curDist = dist;
367
+ closestIntersection = curVert;
368
+ }
369
+ }
370
+ return closestIntersection;
371
+ }
372
+
373
+ /**
374
+ * Construct a new polygon from this polygon with more vertices on each edge. The
375
+ * interpolation count determines the number of additional vertices on each edge.
376
+ * An interpolation count of `0` will return a polygon that equals the source
377
+ * polygon.
378
+ *
379
+ * @param {number} interpolationCount
380
+ * @returns {Polygon} A polygon with `interpolationCount` more vertices (as as factor).
381
+ */
382
+ getInterpolationPolygon(interpolationCount: number): Polygon {
383
+ const verts: Array<Vertex> = [];
384
+ for (var i = 0; i < this.vertices.length; i++) {
385
+ const curVert = this.vertices[i];
386
+ const nextVert = this.vertices[(i + 1) % this.vertices.length];
387
+ verts.push(curVert.clone());
388
+ // Add interpolation points
389
+ if (!this.isOpen || i + 1 !== this.vertices.length) {
390
+ const lerpAmount = 1.0 / (interpolationCount + 1);
391
+ for (var j = 1; j <= interpolationCount; j++) {
392
+ verts.push(curVert.clone().lerp(nextVert, lerpAmount * j));
393
+ }
394
+ }
395
+ }
396
+ return new Polygon(verts, this.isOpen);
397
+ }
398
+
279
399
  /**
280
400
  * Convert this polygon into a new polygon with n evenly distributed vertices.
281
401
  *
@@ -392,8 +392,8 @@ export class VEllipse implements SVGSerializable {
392
392
  let startTangent: Vector = this.tangentAt(curAngle);
393
393
  let endTangent: Vector = this.tangentAt(nextAngle);
394
394
 
395
- // Find intersection
396
- let intersection: Vertex | undefined = startTangent.intersection(endTangent);
395
+ // Find intersection (ignore that the result might be null in some extreme cases)
396
+ let intersection: Vertex = startTangent.intersection(endTangent) as Vertex;
397
397
  // What if intersection is undefined?
398
398
  // --> This *can* not happen if segmentCount > 2 and height and width of the ellipse are not zero.
399
399
 
package/src/ts/Vector.ts CHANGED
@@ -20,7 +20,7 @@
20
20
 
21
21
  import { VertTuple } from "./VertTuple";
22
22
  import { Vertex } from "./Vertex";
23
- import { SVGSerializable } from "./interfaces";
23
+ import { SVGSerializable, XYCoords } from "./interfaces";
24
24
 
25
25
  /**
26
26
  * @classdesc A vector (Vertex,Vertex) is a line with a visible direction.<br>
@@ -156,13 +156,13 @@ export class Vector extends VertTuple<Vector> implements SVGSerializable {
156
156
  * Example:
157
157
  * buildArrowHead( new Vertex(0,0), new Vertex(50,100), 8, 1.0, 1.0 )
158
158
  *
159
- * @param {Vertex} zA - The start vertex of the vector to calculate the arrow head for.
160
- * @param {Vertex} zB - The end vertex of the vector.
159
+ * @param {XYCoords} zA - The start vertex of the vector to calculate the arrow head for.
160
+ * @param {XYCoords} zB - The end vertex of the vector.
161
161
  * @param {number} headlen - The length of the arrow head (along the vector direction. A good value is 12).
162
162
  * @param {number} scaleX - The horizontal scaling during draw.
163
163
  * @param {number} scaleY - the vertical scaling during draw.
164
164
  **/
165
- buildArrowHead: (zA: Vertex, zB: Vertex, headlen: number, scaleX: number, scaleY: number) => {
165
+ buildArrowHead: (zA: XYCoords, zB: XYCoords, headlen: number, scaleX: number, scaleY: number): Array<Vertex> => {
166
166
  const angle = Math.atan2((zB.y - zA.y) * scaleY, (zB.x - zA.x) * scaleX);
167
167
  const vertices: Array<Vertex> = [];
168
168
  vertices.push(new Vertex(zB.x * scaleX - headlen * Math.cos(angle), zB.y * scaleY - headlen * Math.sin(angle)));
@@ -9,7 +9,8 @@
9
9
  * @modified 2020-12-04 Added the `hasPoint(XYCoords)` function.
10
10
  * @modified 2021-01-20 Added UID.
11
11
  * @modified 2022-02-02 Added the `destroy` method.
12
- * @version 1.2.0
12
+ * @modified 2023-09-29 Fixed a calculation error in the VertTuple.hasPoint() function; distance measure was broken!
13
+ * @version 1.2.1
13
14
  */
14
15
 
15
16
  import { Vertex } from "./Vertex";
@@ -277,11 +278,11 @@ export class VertTuple<T extends VertTuple<T>> {
277
278
  hasPoint(point: XYCoords, insideBoundsOnly?: boolean): boolean {
278
279
  const t: number = this.getClosestT(point);
279
280
  // Compare to pointDistance?
281
+ const distance: number = Math.sqrt(VertTuple.vtutils.dist2(point, this.vertAt(t)));
280
282
  if (typeof insideBoundsOnly !== "undefined" && insideBoundsOnly) {
281
- const distance: number = Math.sqrt(VertTuple.vtutils.dist2(point, this.vertAt(t)));
282
283
  return distance < Vertex.EPSILON && t >= 0 && t <= 1;
283
284
  } else {
284
- return t >= 0 && t <= 1;
285
+ return distance < Vertex.EPSILON; // t >= 0 && t <= 1;
285
286
  }
286
287
  }
287
288