plotboilerplate 1.20.1 → 1.21.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 +17 -1
  2. package/dist/index.esm.js +2065 -1397
  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 +1265 -584
  9. package/dist/plotboilerplate.min.js +1 -1
  10. package/package.json +2 -1
  11. package/src/cjs/BezierPath.d.ts +27 -49
  12. package/src/cjs/BezierPath.js +69 -237
  13. package/src/cjs/BezierPath.js.map +1 -1
  14. package/src/cjs/Bounds.d.ts +14 -1
  15. package/src/cjs/Bounds.js +21 -1
  16. package/src/cjs/Bounds.js.map +1 -1
  17. package/src/cjs/CubicBezierCurve.d.ts +70 -1
  18. package/src/cjs/CubicBezierCurve.js +130 -12
  19. package/src/cjs/CubicBezierCurve.js.map +1 -1
  20. package/src/cjs/Line.d.ts +2 -1
  21. package/src/cjs/Line.js +1 -0
  22. package/src/cjs/Line.js.map +1 -1
  23. package/src/cjs/PBText.d.ts +2 -1
  24. package/src/cjs/PBText.js +10 -9
  25. package/src/cjs/PBText.js.map +1 -1
  26. package/src/cjs/PlotBoilerplate.d.ts +10 -13
  27. package/src/cjs/PlotBoilerplate.js +136 -47
  28. package/src/cjs/PlotBoilerplate.js.map +1 -1
  29. package/src/cjs/Polygon.d.ts +35 -1
  30. package/src/cjs/Polygon.js +87 -1
  31. package/src/cjs/Polygon.js.map +1 -1
  32. package/src/cjs/Triangle.js +1 -0
  33. package/src/cjs/Triangle.js.map +1 -1
  34. package/src/cjs/VEllipse.js +1 -1
  35. package/src/cjs/VEllipse.js.map +1 -1
  36. package/src/cjs/Vector.d.ts +4 -4
  37. package/src/cjs/Vector.js +2 -2
  38. package/src/cjs/Vector.js.map +1 -1
  39. package/src/cjs/VertTuple.d.ts +2 -1
  40. package/src/cjs/VertTuple.js +4 -3
  41. package/src/cjs/VertTuple.js.map +1 -1
  42. package/src/cjs/Vertex.d.ts +14 -3
  43. package/src/cjs/Vertex.js +18 -3
  44. package/src/cjs/Vertex.js.map +1 -1
  45. package/src/cjs/draw.d.ts +159 -79
  46. package/src/cjs/draw.js +311 -139
  47. package/src/cjs/draw.js.map +1 -1
  48. package/src/cjs/drawgl.d.ts +93 -55
  49. package/src/cjs/drawgl.js +90 -34
  50. package/src/cjs/drawgl.js.map +1 -1
  51. package/src/cjs/drawutilssvg.d.ts +233 -58
  52. package/src/cjs/drawutilssvg.js +384 -95
  53. package/src/cjs/drawutilssvg.js.map +1 -1
  54. package/src/cjs/interfaces/DrawLib.d.ts +161 -82
  55. package/src/cjs/interfaces/DrawLib.js +7 -0
  56. package/src/cjs/interfaces/DrawLib.js.map +1 -1
  57. package/src/cjs/interfaces/core.d.ts +46 -32
  58. package/src/cjs/interfaces/core.js +2 -0
  59. package/src/cjs/interfaces/core.js.map +1 -1
  60. package/src/cjs/utils/creategui.js +16 -10
  61. package/src/cjs/utils/datastructures/Color.d.ts +3 -1
  62. package/src/cjs/utils/datastructures/Color.js +12 -1
  63. package/src/cjs/utils/datastructures/Color.js.map +1 -1
  64. package/src/cjs/utils/detectDarkMode.d.ts +10 -0
  65. package/src/cjs/utils/detectDarkMode.js +32 -0
  66. package/src/cjs/utils/detectDarkMode.js.map +1 -0
  67. package/src/cjs/utils/module.js +4 -2
  68. package/src/esm/BezierPath.d.ts +27 -49
  69. package/src/esm/BezierPath.js +69 -237
  70. package/src/esm/BezierPath.js.map +1 -1
  71. package/src/esm/Bounds.d.ts +14 -1
  72. package/src/esm/Bounds.js +19 -1
  73. package/src/esm/Bounds.js.map +1 -1
  74. package/src/esm/CubicBezierCurve.d.ts +70 -1
  75. package/src/esm/CubicBezierCurve.js +130 -12
  76. package/src/esm/CubicBezierCurve.js.map +1 -1
  77. package/src/esm/Line.d.ts +2 -1
  78. package/src/esm/Line.js +1 -0
  79. package/src/esm/Line.js.map +1 -1
  80. package/src/esm/PBText.d.ts +2 -1
  81. package/src/esm/PBText.js +10 -9
  82. package/src/esm/PBText.js.map +1 -1
  83. package/src/esm/PlotBoilerplate.d.ts +10 -13
  84. package/src/esm/PlotBoilerplate.js +136 -48
  85. package/src/esm/PlotBoilerplate.js.map +1 -1
  86. package/src/esm/Polygon.d.ts +35 -1
  87. package/src/esm/Polygon.js +85 -1
  88. package/src/esm/Polygon.js.map +1 -1
  89. package/src/esm/Triangle.js +1 -0
  90. package/src/esm/Triangle.js.map +1 -1
  91. package/src/esm/VEllipse.js +1 -1
  92. package/src/esm/VEllipse.js.map +1 -1
  93. package/src/esm/Vector.d.ts +4 -4
  94. package/src/esm/Vector.js +2 -2
  95. package/src/esm/Vector.js.map +1 -1
  96. package/src/esm/VertTuple.d.ts +2 -1
  97. package/src/esm/VertTuple.js +4 -3
  98. package/src/esm/VertTuple.js.map +1 -1
  99. package/src/esm/Vertex.d.ts +14 -3
  100. package/src/esm/Vertex.js +18 -3
  101. package/src/esm/Vertex.js.map +1 -1
  102. package/src/esm/draw.d.ts +159 -79
  103. package/src/esm/draw.js +307 -137
  104. package/src/esm/draw.js.map +1 -1
  105. package/src/esm/drawgl.d.ts +93 -55
  106. package/src/esm/drawgl.js +90 -34
  107. package/src/esm/drawgl.js.map +1 -1
  108. package/src/esm/drawutilssvg.d.ts +233 -58
  109. package/src/esm/drawutilssvg.js +379 -95
  110. package/src/esm/drawutilssvg.js.map +1 -1
  111. package/src/esm/interfaces/DrawLib.d.ts +161 -82
  112. package/src/esm/interfaces/DrawLib.js +7 -0
  113. package/src/esm/interfaces/DrawLib.js.map +1 -1
  114. package/src/esm/interfaces/core.d.ts +46 -32
  115. package/src/esm/interfaces/core.js +2 -0
  116. package/src/esm/interfaces/core.js.map +1 -1
  117. package/src/esm/utils/datastructures/Color.d.ts +3 -1
  118. package/src/esm/utils/datastructures/Color.js +12 -1
  119. package/src/esm/utils/datastructures/Color.js.map +1 -1
  120. package/src/esm/utils/detectDarkMode.d.ts +10 -0
  121. package/src/esm/utils/detectDarkMode.js +28 -0
  122. package/src/esm/utils/detectDarkMode.js.map +1 -0
  123. package/src/ts/BezierPath.ts +74 -244
  124. package/src/ts/Bounds.ts +25 -1
  125. package/src/ts/CubicBezierCurve.ts +139 -12
  126. package/src/ts/Line.ts +2 -1
  127. package/src/ts/PBText.ts +10 -9
  128. package/src/ts/PlotBoilerplate.ts +130 -50
  129. package/src/ts/Polygon.ts +91 -1
  130. package/src/ts/Triangle.ts +2 -1
  131. package/src/ts/VEllipse.ts +2 -2
  132. package/src/ts/Vector.ts +4 -4
  133. package/src/ts/VertTuple.ts +4 -3
  134. package/src/ts/Vertex.ts +20 -4
  135. package/src/ts/draw.ts +316 -119
  136. package/src/ts/drawgl.ts +141 -78
  137. package/src/ts/drawutilssvg.ts +562 -133
  138. package/src/ts/interfaces/DrawLib.ts +223 -86
  139. package/src/ts/interfaces/core.ts +47 -32
  140. package/src/ts/utils/datastructures/Color.ts +13 -1
  141. package/src/ts/utils/detectDarkMode.ts +30 -0
@@ -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
  /**
@@ -78,7 +78,12 @@
78
78
  * @modified 2022-10-25 Added the `origin` to the default draw config.
79
79
  * @modified 2022-11-06 Adding an XML declaration to the SVG export routine.
80
80
  * @modified 2022-11-23 Added the `drawRaster` (default=true) option to the config/drawconfig.
81
- * @version 1.17.0
81
+ * @modified 2023-02-04 Fixed a bug in the `drawDrawable` function; fill's current classname was not set.
82
+ * @modified 2023-02-10 Fixing an issue of the `style.position` setting when `fitToParent=true` from `absolute` to `static` (default).
83
+ * @modified 2023-02-10 Cleaning up most type errors in the main class (mostly null checks).
84
+ * @modified 2023-02-10 Adding `enableZoom` and `enablePan` (both default true) to have the option to disable these functions.
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
82
87
  *
83
88
  * @file PlotBoilerplate
84
89
  * @fileoverview The main class.
@@ -377,6 +382,8 @@ export class PlotBoilerplate {
377
382
  * @param {boolean=} [config.enableTouch=true] - Indicates if the application should handle touch events for you.
378
383
  * @param {boolean=} [config.enableKeys=true] - Indicates if the application should handle key events for you.
379
384
  * @param {boolean=} [config.enableMouseWheel=true] - Indicates if the application should handle mouse wheel events for you.
385
+ * @param {boolean=} [config.enablePan=true] - (default true) Set to false if you want to disable panning completely.
386
+ * @param {boolean=} [config.enableZoom=true] - (default true) Set to false if you want to disable zooming completely.
380
387
  * @param {boolean=} [config.enableGL=false] - Indicates if the application should use the experimental WebGL features (not recommended).
381
388
  * @param {boolean=} [config.enableSVGExport=true] - Indicates if the SVG export should be enabled (default is true).
382
389
  * Note that changes from the postDraw hook might not be visible in the export.
@@ -393,7 +400,7 @@ export class PlotBoilerplate {
393
400
  visible: true
394
401
  };
395
402
 
396
- if (typeof config.canvas == "undefined") {
403
+ if (typeof config.canvas === "undefined") {
397
404
  throw "No canvas specified.";
398
405
  }
399
406
 
@@ -450,6 +457,8 @@ export class PlotBoilerplate {
450
457
  enableTouch: f.bool(config, "enableTouch", true),
451
458
  enableKeys: f.bool(config, "enableKeys", true),
452
459
  enableMouseWheel: f.bool(config, "enableMouseWheel", true),
460
+ enableZoom: f.bool(config, "enableZoom", true), // default=true
461
+ enablePan: f.bool(config, "enablePan", true), // default=true
453
462
 
454
463
  // Experimental (and unfinished)
455
464
  enableGL: f.bool(config, "enableGL", false)
@@ -488,6 +497,10 @@ export class PlotBoilerplate {
488
497
  fill: true
489
498
  }
490
499
  },
500
+ // bezierPath: {
501
+ // color: "#0022a8",
502
+ // lineWidth: 1
503
+ // },
491
504
  polygon: {
492
505
  color: "#0022a8",
493
506
  lineWidth: 1
@@ -549,7 +562,10 @@ export class PlotBoilerplate {
549
562
  this.grid = new Grid(new Vertex(0, 0), new Vertex(50, 50));
550
563
  this.canvasSize = { width: PlotBoilerplate.DEFAULT_CANVAS_WIDTH, height: PlotBoilerplate.DEFAULT_CANVAS_HEIGHT };
551
564
  const canvasElement: Element =
552
- 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
+ }
553
569
  // Which renderer to use: Canvas2D, WebGL (experimental) or SVG?
554
570
  if (canvasElement.tagName.toLowerCase() === "canvas") {
555
571
  this.canvas = canvasElement as HTMLCanvasElement;
@@ -1140,7 +1156,7 @@ export class PlotBoilerplate {
1140
1156
  this.draw.setCurrentId(d.uid);
1141
1157
  this.fill.setCurrentId(d.uid);
1142
1158
  this.draw.setCurrentClassName(d.className);
1143
- this.draw.setCurrentClassName(d.className);
1159
+ this.fill.setCurrentClassName(d.className);
1144
1160
  this.drawDrawable(d, renderTime, draw, fill);
1145
1161
  }
1146
1162
  }
@@ -1162,7 +1178,13 @@ export class PlotBoilerplate {
1162
1178
  **/
1163
1179
  drawDrawable(d: Drawable, renderTime: number, draw: DrawLib<any>, fill: DrawLib<any>) {
1164
1180
  if (d instanceof BezierPath) {
1181
+ var curveIndex = 0;
1165
1182
  for (var c in d.bezierCurves) {
1183
+ // Restore these settings again in each loop (will be overwritten)
1184
+ this.draw.setCurrentId(`${d.uid}-${curveIndex}`);
1185
+ this.fill.setCurrentId(`${d.uid}-${curveIndex}`);
1186
+ this.draw.setCurrentClassName(d.className);
1187
+ this.fill.setCurrentClassName(d.className);
1166
1188
  draw.cubicBezier(
1167
1189
  d.bezierCurves[c].startPoint,
1168
1190
  d.bezierCurves[c].endPoint,
@@ -1245,22 +1267,13 @@ export class PlotBoilerplate {
1245
1267
  if (this.drawConfig.drawBezierHandleLines && this.drawConfig.drawHandleLines) {
1246
1268
  draw.setCurrentId(`${d.uid}_l0`);
1247
1269
  draw.setCurrentClassName(`${d.className}-start-line`);
1248
- draw.line(
1249
- d.bezierCurves[c].startPoint,
1250
- d.bezierCurves[c].startControlPoint,
1251
- this.drawConfig.bezier.handleLine.color,
1252
- this.drawConfig.bezier.handleLine.lineWidth
1253
- );
1270
+ draw.handleLine(d.bezierCurves[c].startPoint, d.bezierCurves[c].startControlPoint);
1254
1271
  draw.setCurrentId(`${d.uid}_l1`);
1255
1272
  draw.setCurrentClassName(`${d.className}-end-line`);
1256
- draw.line(
1257
- d.bezierCurves[c].endPoint,
1258
- d.bezierCurves[c].endControlPoint,
1259
- this.drawConfig.bezier.handleLine.color,
1260
- this.drawConfig.bezier.handleLine.lineWidth
1261
- );
1273
+ draw.handleLine(d.bezierCurves[c].endPoint, d.bezierCurves[c].endControlPoint);
1262
1274
  }
1263
- }
1275
+ curveIndex++;
1276
+ } // END for
1264
1277
  } else if (d instanceof Polygon) {
1265
1278
  draw.polygon(d, this.drawConfig.polygon.color, this.drawConfig.polygon.lineWidth);
1266
1279
  if (!this.drawConfig.drawHandlePoints) {
@@ -1276,11 +1289,11 @@ export class PlotBoilerplate {
1276
1289
  draw.setCurrentId(`${d.uid}_e0`);
1277
1290
  draw.setCurrentClassName(`${d.className}-v-line`);
1278
1291
  // draw.line( d.center.clone().add(0,d.axis.y-d.center.y), d.axis, '#c8c8c8' );
1279
- 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");
1280
1293
  draw.setCurrentId(`${d.uid}_e1`);
1281
1294
  draw.setCurrentClassName(`${d.className}-h-line`);
1282
1295
  // draw.line( d.center.clone().add(d.axis.x-d.center.x,0), d.axis, '#c8c8c8' );
1283
- 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");
1284
1297
  }
1285
1298
  draw.setCurrentId(d.uid);
1286
1299
  draw.setCurrentClassName(`${d.className}`);
@@ -1375,10 +1388,10 @@ export class PlotBoilerplate {
1375
1388
  } else {
1376
1389
  console.error("Cannot draw object. Unknown class.");
1377
1390
  }
1378
- draw.setCurrentClassName(undefined);
1379
- draw.setCurrentId(undefined);
1380
- fill.setCurrentClassName(undefined);
1381
- fill.setCurrentId(undefined);
1391
+ draw.setCurrentClassName(null);
1392
+ draw.setCurrentId(null);
1393
+ fill.setCurrentClassName(null);
1394
+ fill.setCurrentId(null);
1382
1395
  }
1383
1396
 
1384
1397
  /**
@@ -1475,8 +1488,8 @@ export class PlotBoilerplate {
1475
1488
 
1476
1489
  // Clear IDs and classnames (postDraw hook might draw somthing and the do not want
1477
1490
  // to interfered with that).
1478
- draw.setCurrentId(undefined);
1479
- draw.setCurrentClassName(undefined);
1491
+ draw.setCurrentId(null);
1492
+ draw.setCurrentClassName(null);
1480
1493
  } // END redraw
1481
1494
 
1482
1495
  /**
@@ -1626,7 +1639,7 @@ export class PlotBoilerplate {
1626
1639
  _setSize(width, height);
1627
1640
  } else if (_self.config.fitToParent) {
1628
1641
  // Set editor size
1629
- _self.canvas.style.position = "absolute";
1642
+ _self.canvas.style.position = "static";
1630
1643
  const space: XYDimension = this.getAvailableContainerSpace();
1631
1644
  _self.canvas.style.width = (_self.config.canvasWidthFactor ?? 1.0) * space.width + "px";
1632
1645
  _self.canvas.style.height = (_self.config.canvasHeightFactor ?? 1.0) * space.height + "px";
@@ -1697,23 +1710,23 @@ export class PlotBoilerplate {
1697
1710
  **/
1698
1711
  private handleClick(e: XMouseEvent) {
1699
1712
  const _self: PlotBoilerplate = this;
1700
- var p: IDraggable = this.locatePointNear(
1713
+ var point: IDraggable | null = this.locatePointNear(
1701
1714
  _self.transformMousePosition(e.params.pos.x, e.params.pos.y),
1702
- PlotBoilerplate.DEFAULT_CLICK_TOLERANCE / Math.min(_self.config.cssScaleX, _self.config.cssScaleY)
1715
+ PlotBoilerplate.DEFAULT_CLICK_TOLERANCE / Math.min(_self.config.cssScaleX || 1.0, _self.config.cssScaleY || 1.0)
1703
1716
  );
1704
- if (p) {
1705
- _self.vertices[p.vindex].listeners.fireClickEvent(e);
1717
+ if (point) {
1718
+ _self.vertices[point.vindex].listeners.fireClickEvent(e);
1706
1719
  if (this.keyHandler && this.keyHandler.isDown("shift")) {
1707
- if (p.typeName == "bpath") {
1708
- let vert: Vertex = _self.paths[p.pindex].bezierCurves[p.cindex].getPointByID(p.pid);
1720
+ if (point.typeName == "bpath") {
1721
+ let vert: Vertex = _self.paths[point.pindex].bezierCurves[point.cindex].getPointByID(point.pid);
1709
1722
  if (vert.attr.selectable) vert.attr.isSelected = !vert.attr.isSelected;
1710
- } else if (p.typeName == "vertex") {
1711
- let vert: Vertex = _self.vertices[p.vindex];
1723
+ } else if (point.typeName == "vertex") {
1724
+ let vert: Vertex = _self.vertices[point.vindex];
1712
1725
  if (vert.attr.selectable) vert.attr.isSelected = !vert.attr.isSelected;
1713
1726
  }
1714
1727
  _self.redraw();
1715
- } else if (this.keyHandler.isDown("y")) {
1716
- _self.vertices[p.vindex].attr.bezierAutoAdjust = !_self.vertices[p.vindex].attr.bezierAutoAdjust;
1728
+ } else if (this.keyHandler && this.keyHandler.isDown("y")) {
1729
+ _self.vertices[point.vindex].attr.bezierAutoAdjust = !_self.vertices[point.vindex].attr.bezierAutoAdjust;
1717
1730
  _self.redraw();
1718
1731
  }
1719
1732
  } else if (_self.selectPolygon != null) {
@@ -1782,13 +1795,13 @@ export class PlotBoilerplate {
1782
1795
  private mouseDownHandler(e: XMouseEvent) {
1783
1796
  const _self = this;
1784
1797
  if (e.button != 0) return; // Only react on left mouse or touch events
1785
- var p: IDraggable = _self.locatePointNear(
1798
+ var draggablePoint: IDraggable | null = _self.locatePointNear(
1786
1799
  _self.transformMousePosition(e.params.pos.x, e.params.pos.y),
1787
1800
  PlotBoilerplate.DEFAULT_CLICK_TOLERANCE / Math.min(_self.config.cssScaleX, _self.config.cssScaleY)
1788
1801
  );
1789
- if (!p) return;
1802
+ if (!draggablePoint) return;
1790
1803
  // Drag all selected elements?
1791
- if (p.typeName == "vertex" && _self.vertices[p.vindex].attr.isSelected) {
1804
+ if (draggablePoint.typeName == "vertex" && _self.vertices[draggablePoint.vindex].attr.isSelected) {
1792
1805
  // Multi drag
1793
1806
  // for( var i in _self.vertices ) {
1794
1807
  for (var i = 0; i < _self.vertices.length; i++) {
@@ -1801,10 +1814,13 @@ export class PlotBoilerplate {
1801
1814
  }
1802
1815
  } else {
1803
1816
  // Single drag
1804
- if (!_self.vertices[p.vindex].attr.draggable) return;
1805
- _self.draggedElements.push(p);
1806
- if (p.typeName == "bpath") _self.paths[p.pindex].bezierCurves[p.cindex].getPointByID(p.pid).listeners.fireDragStartEvent(e);
1807
- else if (p.typeName == "vertex") _self.vertices[p.vindex].listeners.fireDragStartEvent(e);
1817
+ if (!_self.vertices[draggablePoint.vindex].attr.draggable) return;
1818
+ _self.draggedElements.push(draggablePoint);
1819
+ if (draggablePoint.typeName == "bpath")
1820
+ _self.paths[draggablePoint.pindex].bezierCurves[draggablePoint.cindex]
1821
+ .getPointByID(draggablePoint.pid)
1822
+ .listeners.fireDragStartEvent(e);
1823
+ else if (draggablePoint.typeName == "vertex") _self.vertices[draggablePoint.vindex].listeners.fireDragStartEvent(e);
1808
1824
  }
1809
1825
  _self.redraw();
1810
1826
  }
@@ -1832,7 +1848,10 @@ export class PlotBoilerplate {
1832
1848
  // not this one. So this tab will never receive any [Ctrl-down] events
1833
1849
  // until next keypress; the implication is, that [Ctrl] would still
1834
1850
  // considered to be pressed which is not true.
1835
- if (this.keyHandler.isDown("alt") || this.keyHandler.isDown("spacebar")) {
1851
+ if (this.keyHandler && (this.keyHandler.isDown("alt") || this.keyHandler.isDown("spacebar"))) {
1852
+ if (!this.config.enablePan) {
1853
+ return;
1854
+ }
1836
1855
  _self.setOffset(_self.draw.offset.clone().add(e.params.dragAmount));
1837
1856
  _self.redraw();
1838
1857
  } else {
@@ -1898,6 +1917,9 @@ export class PlotBoilerplate {
1898
1917
  * @return {void}
1899
1918
  **/
1900
1919
  private mouseWheelHandler(e: XMouseEvent) {
1920
+ if (!this.config.enableZoom) {
1921
+ return;
1922
+ }
1901
1923
  var zoomStep: number = 1.25; // Make configurable?
1902
1924
  // CHANGED replaced _self by this
1903
1925
  const _self: PlotBoilerplate = this;
@@ -2045,6 +2067,9 @@ export class PlotBoilerplate {
2045
2067
  if (evt.touches.length == 1 && draggedElement) {
2046
2068
  evt.preventDefault();
2047
2069
  evt.stopPropagation();
2070
+ if (!touchDownPos || !touchMovePos) {
2071
+ return;
2072
+ }
2048
2073
  var rel: XYCoords = relPos({ x: evt.touches[0].clientX, y: evt.touches[0].clientY });
2049
2074
  var trans: XYCoords = _self.transformMousePosition(rel.x, rel.y);
2050
2075
  var diff: Vertex = new Vertex(_self.transformMousePosition(touchMovePos.x, touchMovePos.y)).difference(trans);
@@ -2067,6 +2092,9 @@ export class PlotBoilerplate {
2067
2092
  }
2068
2093
  touchMovePos = new Vertex(rel);
2069
2094
  } else if (evt.touches.length == 2) {
2095
+ if (!this.config.enablePan) {
2096
+ return;
2097
+ }
2070
2098
  // If at least two fingers touch and move, then change the draw offset (panning).
2071
2099
  evt.preventDefault();
2072
2100
  evt.stopPropagation();
@@ -2081,6 +2109,9 @@ export class PlotBoilerplate {
2081
2109
  touchEnd: (evt: TouchEvent) => {
2082
2110
  // Note: e.touches.length is 0 here
2083
2111
  if (draggedElement && draggedElement.typeName == "vertex") {
2112
+ if (!touchDownPos) {
2113
+ return;
2114
+ }
2084
2115
  var draggingVertex: Vertex = _self.vertices[draggedElement.vindex];
2085
2116
  var fakeEvent: VertEvent = {
2086
2117
  isTouchEvent: true,
@@ -2112,9 +2143,17 @@ export class PlotBoilerplate {
2112
2143
  multiTouchStartScale = null;
2113
2144
  },
2114
2145
  pinch: (evt: TouchPinchEvent) => {
2146
+ if (!this.config.enableZoom) {
2147
+ return;
2148
+ }
2149
+ const touchItem0 = evt.touches.item(0);
2150
+ const touchItem1 = evt.touches.item(1);
2151
+ if (!evt.touches || !multiTouchStartScale || !touchItem0 || !touchItem1) {
2152
+ return;
2153
+ }
2115
2154
  // For pinching there must be at least two touch items
2116
- const fingerA: Vertex = new Vertex(evt.touches.item(0).clientX, evt.touches.item(0).clientY);
2117
- const fingerB: Vertex = new Vertex(evt.touches.item(1).clientX, evt.touches.item(1).clientY);
2155
+ const fingerA: Vertex = new Vertex(touchItem0.clientX, touchItem0.clientY);
2156
+ const fingerB: Vertex = new Vertex(touchItem1.clientX, touchItem1.clientY);
2118
2157
  const center: Vertex = new Line(fingerA, fingerB).vertAt(0.5);
2119
2158
  _self.setZoom(multiTouchStartScale.x * evt.zoom, multiTouchStartScale.y * evt.zoom, center);
2120
2159
  _self.redraw();
@@ -2192,7 +2231,45 @@ export class PlotBoilerplate {
2192
2231
  * @param {Object} extension
2193
2232
  * @return {Object} base extended by the new attributes.
2194
2233
  **/
2195
- 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> => {
2196
2273
  for (var k in extension) {
2197
2274
  if (!extension.hasOwnProperty(k)) continue;
2198
2275
  if (base.hasOwnProperty(k)) {
@@ -2211,6 +2288,7 @@ export class PlotBoilerplate {
2211
2288
  }
2212
2289
  return base;
2213
2290
  },
2291
+ *()
2214
2292
 
2215
2293
  /**
2216
2294
  * A helper function to scale elements (usually the canvas) using CSS.
@@ -2224,8 +2302,10 @@ export class PlotBoilerplate {
2224
2302
  **/
2225
2303
  setCSSscale: (element: HTMLElement | SVGElement, scaleX: number, scaleY: number): void => {
2226
2304
  element.style["transform-origin"] = "0 0";
2227
- if (scaleX == 1.0 && scaleY == 1.0) element.style.transform = null;
2228
- else element.style.transform = "scale(" + scaleX + "," + scaleY + ")";
2305
+ if (scaleX == 1.0 && scaleY == 1.0) {
2306
+ // element.style.transform = null;
2307
+ element.style.removeProperty("transform");
2308
+ } else element.style.transform = "scale(" + scaleX + "," + scaleY + ")";
2229
2309
  },
2230
2310
 
2231
2311
  // A helper for fetching data from objects.
@@ -2271,7 +2351,7 @@ export class PlotBoilerplate {
2271
2351
  * @param {boolean} fallback - A default value if the key does not exist.
2272
2352
  * @return {boolean}
2273
2353
  **/
2274
- bool: (obj: any, key: string, fallback: boolean) => {
2354
+ bool: (obj: any, key: string, fallback: boolean | null) => {
2275
2355
  if (!obj.hasOwnProperty(key)) return fallback;
2276
2356
  if (typeof obj[key] == "boolean") return obj[key];
2277
2357
  else {