plotboilerplate 1.23.3 → 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 (230) hide show
  1. package/README.md +19 -1
  2. package/dist/index.esm.js +1684 -394
  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 +12450 -11120
  9. package/dist/plotboilerplate.min.js +1 -1
  10. package/package.json +9 -5
  11. package/src/cjs/BezierPath.d.ts +41 -5
  12. package/src/cjs/BezierPath.js +52 -2
  13. package/src/cjs/BezierPath.js.map +1 -1
  14. package/src/cjs/Bounds.d.ts +67 -3
  15. package/src/cjs/Bounds.js +101 -3
  16. package/src/cjs/Bounds.js.map +1 -1
  17. package/src/cjs/Circle.d.ts +46 -4
  18. package/src/cjs/Circle.js +82 -3
  19. package/src/cjs/Circle.js.map +1 -1
  20. package/src/cjs/CircleSector.d.ts +51 -2
  21. package/src/cjs/CircleSector.js +112 -3
  22. package/src/cjs/CircleSector.js.map +1 -1
  23. package/src/cjs/CubicBezierCurve.d.ts +113 -7
  24. package/src/cjs/CubicBezierCurve.js +281 -33
  25. package/src/cjs/CubicBezierCurve.js.map +1 -1
  26. package/src/cjs/Line.d.ts +38 -3
  27. package/src/cjs/Line.js +64 -1
  28. package/src/cjs/Line.js.map +1 -1
  29. package/src/cjs/PlotBoilerplate.d.ts +37 -6
  30. package/src/cjs/PlotBoilerplate.js +224 -125
  31. package/src/cjs/PlotBoilerplate.js.map +1 -1
  32. package/src/cjs/Polygon.d.ts +68 -5
  33. package/src/cjs/Polygon.js +143 -22
  34. package/src/cjs/Polygon.js.map +1 -1
  35. package/src/cjs/Triangle.d.ts +52 -3
  36. package/src/cjs/Triangle.js +80 -1
  37. package/src/cjs/Triangle.js.map +1 -1
  38. package/src/cjs/VEllipse.d.ts +62 -3
  39. package/src/cjs/VEllipse.js +181 -17
  40. package/src/cjs/VEllipse.js.map +1 -1
  41. package/src/cjs/VEllipseSector.d.ts +86 -2
  42. package/src/cjs/VEllipseSector.js +148 -4
  43. package/src/cjs/VEllipseSector.js.map +1 -1
  44. package/src/cjs/Vector.d.ts +12 -2
  45. package/src/cjs/Vector.js +15 -2
  46. package/src/cjs/Vector.js.map +1 -1
  47. package/src/cjs/VertTuple.d.ts +28 -4
  48. package/src/cjs/VertTuple.js +36 -3
  49. package/src/cjs/VertTuple.js.map +1 -1
  50. package/src/cjs/Vertex.d.ts +31 -4
  51. package/src/cjs/Vertex.js +35 -1
  52. package/src/cjs/Vertex.js.map +1 -1
  53. package/src/cjs/interfaces/core.d.ts +67 -0
  54. package/src/cjs/interfaces/core.js +4 -0
  55. package/src/cjs/interfaces/core.js.map +1 -1
  56. package/src/cjs/utils/algorithms/convexPolygonIncircle.d.ts +2 -1
  57. package/src/cjs/utils/algorithms/convexPolygonIncircle.js +14 -6
  58. package/src/cjs/utils/algorithms/convexPolygonIncircle.js.map +1 -1
  59. package/src/cjs/utils/createRandomizedPolygon.d.ts +14 -0
  60. package/src/cjs/utils/createRandomizedPolygon.js +32 -0
  61. package/src/cjs/utils/createRandomizedPolygon.js.map +1 -0
  62. package/src/cjs/utils/datastructures/Color.d.ts +147 -1
  63. package/src/cjs/utils/datastructures/Color.js +385 -41
  64. package/src/cjs/utils/datastructures/Color.js.map +1 -1
  65. package/src/cjs/utils/datastructures/ColorGradient.d.ts +79 -0
  66. package/src/cjs/utils/datastructures/ColorGradient.js +171 -0
  67. package/src/cjs/utils/datastructures/ColorGradient.js.map +1 -0
  68. package/src/cjs/utils/dom/components/ColorGradientPicker.d.ts +245 -0
  69. package/src/cjs/utils/dom/components/ColorGradientPicker.js +667 -0
  70. package/src/cjs/utils/dom/components/ColorGradientPicker.js.map +1 -0
  71. package/src/cjs/utils/dom/components/ColorGradientPickerJSX.d.ts +129 -0
  72. package/src/cjs/utils/dom/components/ColorGradientPickerJSX.js +520 -0
  73. package/src/cjs/utils/dom/components/ColorGradientPickerJSX.js.map +1 -0
  74. package/src/cjs/utils/dom/components/ColorGradientSelector.d.ts +117 -0
  75. package/src/cjs/utils/dom/components/ColorGradientSelector.js +325 -0
  76. package/src/cjs/utils/dom/components/ColorGradientSelector.js.map +1 -0
  77. package/src/cjs/utils/dom/components/Test.d.ts +7 -0
  78. package/src/cjs/utils/dom/components/Test.js +30 -0
  79. package/src/cjs/utils/dom/components/Test.js.map +1 -0
  80. package/src/cjs/utils/dom/guiSizeToggler.js +1 -1
  81. package/src/cjs/utils/dom/guiSizeToggler.js.map +1 -1
  82. package/src/cjs/utils/helpers/BezierPathInteractionHelper.d.ts +16 -8
  83. package/src/cjs/utils/helpers/BezierPathInteractionHelper.js +49 -28
  84. package/src/cjs/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
  85. package/src/cjs/utils/helpers/CircleHelper.d.ts +10 -1
  86. package/src/cjs/utils/helpers/CircleHelper.js +13 -2
  87. package/src/cjs/utils/helpers/CircleHelper.js.map +1 -1
  88. package/src/cjs/utils/helpers/CircleSectorHelper.d.ts +11 -2
  89. package/src/cjs/utils/helpers/CircleSectorHelper.js +20 -20
  90. package/src/cjs/utils/helpers/CircleSectorHelper.js.map +1 -1
  91. package/src/cjs/utils/helpers/TriangleHelper.d.ts +57 -0
  92. package/src/cjs/utils/helpers/TriangleHelper.js +83 -0
  93. package/src/cjs/utils/helpers/TriangleHelper.js.map +1 -0
  94. package/src/cjs/utils/helpers/VEllipseHelper.d.ts +32 -0
  95. package/src/cjs/utils/helpers/VEllipseHelper.js +88 -0
  96. package/src/cjs/utils/helpers/VEllipseHelper.js.map +1 -0
  97. package/src/cjs/utils/helpers/VEllipseSectorHelper.d.ts +44 -4
  98. package/src/cjs/utils/helpers/VEllipseSectorHelper.js +108 -25
  99. package/src/cjs/utils/helpers/VEllipseSectorHelper.js.map +1 -1
  100. package/src/cjs/utils/parsers/LinearColorGradientParser.d.ts +78 -0
  101. package/src/cjs/utils/parsers/LinearColorGradientParser.js +224 -0
  102. package/src/cjs/utils/parsers/LinearColorGradientParser.js.map +1 -0
  103. package/src/createDemoDrawables.js +4 -1
  104. package/src/esm/BezierPath.d.ts +41 -5
  105. package/src/esm/BezierPath.js +50 -2
  106. package/src/esm/BezierPath.js.map +1 -1
  107. package/src/esm/Bounds.d.ts +67 -3
  108. package/src/esm/Bounds.js +101 -3
  109. package/src/esm/Bounds.js.map +1 -1
  110. package/src/esm/Circle.d.ts +46 -4
  111. package/src/esm/Circle.js +79 -3
  112. package/src/esm/Circle.js.map +1 -1
  113. package/src/esm/CircleSector.d.ts +51 -2
  114. package/src/esm/CircleSector.js +108 -3
  115. package/src/esm/CircleSector.js.map +1 -1
  116. package/src/esm/CubicBezierCurve.d.ts +113 -7
  117. package/src/esm/CubicBezierCurve.js +277 -33
  118. package/src/esm/CubicBezierCurve.js.map +1 -1
  119. package/src/esm/Line.d.ts +38 -3
  120. package/src/esm/Line.js +62 -1
  121. package/src/esm/Line.js.map +1 -1
  122. package/src/esm/PlotBoilerplate.d.ts +37 -6
  123. package/src/esm/PlotBoilerplate.js +224 -125
  124. package/src/esm/PlotBoilerplate.js.map +1 -1
  125. package/src/esm/Polygon.d.ts +68 -5
  126. package/src/esm/Polygon.js +138 -22
  127. package/src/esm/Polygon.js.map +1 -1
  128. package/src/esm/Triangle.d.ts +52 -3
  129. package/src/esm/Triangle.js +77 -1
  130. package/src/esm/Triangle.js.map +1 -1
  131. package/src/esm/VEllipse.d.ts +62 -3
  132. package/src/esm/VEllipse.js +178 -17
  133. package/src/esm/VEllipse.js.map +1 -1
  134. package/src/esm/VEllipseSector.d.ts +86 -2
  135. package/src/esm/VEllipseSector.js +146 -7
  136. package/src/esm/VEllipseSector.js.map +1 -1
  137. package/src/esm/Vector.d.ts +12 -2
  138. package/src/esm/Vector.js +15 -2
  139. package/src/esm/Vector.js.map +1 -1
  140. package/src/esm/VertTuple.d.ts +28 -4
  141. package/src/esm/VertTuple.js +36 -3
  142. package/src/esm/VertTuple.js.map +1 -1
  143. package/src/esm/Vertex.d.ts +31 -4
  144. package/src/esm/Vertex.js +35 -1
  145. package/src/esm/Vertex.js.map +1 -1
  146. package/src/esm/interfaces/core.d.ts +67 -0
  147. package/src/esm/interfaces/core.js +4 -0
  148. package/src/esm/interfaces/core.js.map +1 -1
  149. package/src/esm/utils/algorithms/convexPolygonIncircle.d.ts +2 -1
  150. package/src/esm/utils/algorithms/convexPolygonIncircle.js +15 -7
  151. package/src/esm/utils/algorithms/convexPolygonIncircle.js.map +1 -1
  152. package/src/esm/utils/algorithms/createRandomizedPolygon.d.ts +14 -0
  153. package/src/esm/utils/algorithms/createRandomizedPolygon.js +28 -0
  154. package/src/esm/utils/algorithms/createRandomizedPolygon.js.map +1 -0
  155. package/src/esm/utils/createRandomizedPolygon.d.ts +14 -0
  156. package/src/esm/utils/createRandomizedPolygon.js +28 -0
  157. package/src/esm/utils/createRandomizedPolygon.js.map +1 -0
  158. package/src/esm/utils/datastructures/Color.d.ts +147 -1
  159. package/src/esm/utils/datastructures/Color.js +386 -42
  160. package/src/esm/utils/datastructures/Color.js.map +1 -1
  161. package/src/esm/utils/datastructures/ColorGradient.d.ts +79 -0
  162. package/src/esm/utils/datastructures/ColorGradient.js +166 -0
  163. package/src/esm/utils/datastructures/ColorGradient.js.map +1 -0
  164. package/src/esm/utils/dom/components/ColorGradientPicker.d.ts +245 -0
  165. package/src/esm/utils/dom/components/ColorGradientPicker.js +732 -0
  166. package/src/esm/utils/dom/components/ColorGradientPicker.js.map +1 -0
  167. package/src/esm/utils/dom/components/ColorGradientPickerJSX.d.ts +129 -0
  168. package/src/esm/utils/dom/components/ColorGradientPickerJSX.js +582 -0
  169. package/src/esm/utils/dom/components/ColorGradientPickerJSX.js.map +1 -0
  170. package/src/esm/utils/dom/components/ColorGradientSelector.d.ts +117 -0
  171. package/src/esm/utils/dom/components/ColorGradientSelector.js +332 -0
  172. package/src/esm/utils/dom/components/ColorGradientSelector.js.map +1 -0
  173. package/src/esm/utils/dom/components/Test.d.ts +7 -0
  174. package/src/esm/utils/dom/components/Test.js +26 -0
  175. package/src/esm/utils/dom/components/Test.js.map +1 -0
  176. package/src/esm/utils/dom/guiSizeToggler.js +1 -1
  177. package/src/esm/utils/dom/guiSizeToggler.js.map +1 -1
  178. package/src/esm/utils/helpers/BezierPathInteractionHelper.d.ts +16 -8
  179. package/src/esm/utils/helpers/BezierPathInteractionHelper.js +47 -27
  180. package/src/esm/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
  181. package/src/esm/utils/helpers/CircleHelper.d.ts +10 -1
  182. package/src/esm/utils/helpers/CircleHelper.js +13 -2
  183. package/src/esm/utils/helpers/CircleHelper.js.map +1 -1
  184. package/src/esm/utils/helpers/CircleSectorHelper.d.ts +11 -2
  185. package/src/esm/utils/helpers/CircleSectorHelper.js +20 -20
  186. package/src/esm/utils/helpers/CircleSectorHelper.js.map +1 -1
  187. package/src/esm/utils/helpers/TriangleHelper.d.ts +57 -0
  188. package/src/esm/utils/helpers/TriangleHelper.js +78 -0
  189. package/src/esm/utils/helpers/TriangleHelper.js.map +1 -0
  190. package/src/esm/utils/helpers/VEllipseHelper.d.ts +32 -0
  191. package/src/esm/utils/helpers/VEllipseHelper.js +83 -0
  192. package/src/esm/utils/helpers/VEllipseHelper.js.map +1 -0
  193. package/src/esm/utils/helpers/VEllipseSectorHelper.d.ts +44 -4
  194. package/src/esm/utils/helpers/VEllipseSectorHelper.js +107 -24
  195. package/src/esm/utils/helpers/VEllipseSectorHelper.js.map +1 -1
  196. package/src/esm/utils/parsers/LinearColorGradientParser.d.ts +78 -0
  197. package/src/esm/utils/parsers/LinearColorGradientParser.js +217 -0
  198. package/src/esm/utils/parsers/LinearColorGradientParser.js.map +1 -0
  199. package/src/external.d.ts +9 -0
  200. package/src/ts/BezierPath.ts +58 -5
  201. package/src/ts/Bounds.ts +110 -6
  202. package/src/ts/Circle.ts +87 -5
  203. package/src/ts/CircleSector.ts +115 -5
  204. package/src/ts/CubicBezierCurve.ts +332 -42
  205. package/src/ts/Line.ts +66 -3
  206. package/src/ts/PlotBoilerplate.ts +236 -114
  207. package/src/ts/Polygon.ts +164 -29
  208. package/src/ts/Triangle.ts +85 -3
  209. package/src/ts/VEllipse.ts +214 -19
  210. package/src/ts/VEllipseSector.ts +154 -8
  211. package/src/ts/Vector.ts +16 -2
  212. package/src/ts/VertTuple.ts +39 -4
  213. package/src/ts/Vertex.ts +40 -4
  214. package/src/ts/interfaces/core.ts +73 -0
  215. package/src/ts/utils/algorithms/convexPolygonIncircle.ts +82 -78
  216. package/src/ts/utils/createRandomizedPolygon.ts +31 -0
  217. package/src/ts/utils/datastructures/Color.ts +423 -44
  218. package/src/ts/utils/datastructures/ColorGradient.ts +196 -0
  219. package/src/ts/utils/dom/components/ColorGradientPicker.tsx +877 -0
  220. package/src/ts/utils/dom/components/ColorGradientSelector.tsx +445 -0
  221. package/src/ts/utils/dom/components/Test.tsx +44 -0
  222. package/src/ts/utils/dom/components/_ColorGradientPicker_raw.ts_ +392 -0
  223. package/src/ts/utils/dom/guiSizeToggler.ts +1 -1
  224. package/src/ts/utils/helpers/BezierPathInteractionHelper.ts +61 -35
  225. package/src/ts/utils/helpers/CircleHelper.ts +17 -3
  226. package/src/ts/utils/helpers/CircleSectorHelper.ts +118 -126
  227. package/src/ts/utils/helpers/TriangleHelper.ts +102 -0
  228. package/src/ts/utils/helpers/VEllipseHelper.ts +115 -0
  229. package/src/ts/utils/helpers/VEllipseSectorHelper.ts +144 -26
  230. package/src/ts/utils/parsers/LinearColorGradientParser.ts +297 -0
@@ -0,0 +1,392 @@
1
+ /**
2
+ * @author Ikaros Kappler
3
+ * @date 2025-06-07
4
+ * @version 1.0.0
5
+ */
6
+
7
+ export class ColorGradientPicker {
8
+ private baseID: number;
9
+
10
+ private container: HTMLElement;
11
+ private sliderElements: Array<HTMLInputElement>;
12
+ private colorInput: HTMLInputElement;
13
+ private indicatorContainer: HTMLDivElement;
14
+ private colorIndicatorButton: HTMLButtonElement;
15
+ private sliderMin: number = 0;
16
+ private sliderMax: number = 100;
17
+ private indicatorWidth_num = 1.0;
18
+ private indicatorWidth = "1em";
19
+ private indicatorWidth_half = "0.5em";
20
+ private indicatorHeight = "1em";
21
+
22
+ private COLORSET: Array<string> = ["red", "orange", "yellow", "green", "blue", "purple"];
23
+
24
+ /**
25
+ * The constructor.
26
+ *
27
+ * Pass a container ID or nothing – in the latter case the constructor will create
28
+ * a new DIV element.
29
+ *
30
+ * @param {string?} containerID
31
+ */
32
+ constructor(containerID?: string) {
33
+ if (containerID) {
34
+ const cont = document.getElementById(containerID);
35
+ if (!cont) {
36
+ throw "Cannot create ColorGradientPicker. Component ID does not exist.";
37
+ }
38
+ this.container = cont;
39
+ } else {
40
+ this.container = document.createElement("div");
41
+ }
42
+ // console.log("created", this.container);
43
+ this.baseID = Math.floor(Math.random() * 65535);
44
+
45
+ this.__init();
46
+ this.__updateBackgroundGradient();
47
+ }
48
+
49
+ /**
50
+ * Init the container contents.
51
+ *
52
+ * @private
53
+ */
54
+ private __init() {
55
+ this.__addCustomStyles();
56
+ this.__setContainerLayout();
57
+ console.log("Init");
58
+ const stepCount: number = 6;
59
+ this.sliderElements = [];
60
+ for (var i = 0; i < stepCount; i++) {
61
+ this.__createRangeSlider((100 / (stepCount - 1)) * i, i);
62
+ }
63
+ this.__createColorIndicator();
64
+ }
65
+
66
+ /**
67
+ * Apply style settings to the main container.
68
+ *
69
+ * @private
70
+ */
71
+ private __setContainerLayout() {
72
+ this.container.style.display = "flex";
73
+ this.container.style.flexDirection = "column";
74
+ this.container.style.width = "100%";
75
+ this.container.style.height = "32px";
76
+ this.container.style.position = "relative";
77
+ }
78
+
79
+ /**
80
+ * Create a new range slider for this color gradient picker.
81
+ *
82
+ * @param {number} initialValue
83
+ * @param {number} index
84
+ */
85
+ private __createRangeSlider(initialValue: number, index: number) {
86
+ const initialColor: string = this.COLORSET[index % this.COLORSET.length];
87
+
88
+ const rangeSlider = document.createElement("input");
89
+ rangeSlider.setAttribute("id", `rage-slider-${this.baseID}-${index}`);
90
+ rangeSlider.setAttribute("type", "range");
91
+ rangeSlider.setAttribute("min", `${this.sliderMin}`);
92
+ rangeSlider.setAttribute("max", `${this.sliderMax}`);
93
+ rangeSlider.setAttribute("value", `${initialValue}`);
94
+ this.container.appendChild(rangeSlider);
95
+ this.sliderElements.push(rangeSlider);
96
+
97
+ rangeSlider.style.position = "absolute";
98
+ rangeSlider.style.left = "0";
99
+ rangeSlider.style.top = "0";
100
+ rangeSlider.style.width = "100%";
101
+
102
+ rangeSlider.dataset["rangeSliderIndex"] = `${index}`;
103
+ rangeSlider.dataset["colorValue"] = initialColor;
104
+ const sliderHandler = this.__createSliderChangeHandler();
105
+ // rangeSlider.addEventListener("change", this.__createSliderChangeHandler());
106
+ rangeSlider.addEventListener("change", sliderHandler);
107
+ rangeSlider.addEventListener("click", sliderHandler);
108
+ }
109
+
110
+ private __createColorIndicator() {
111
+ this.indicatorContainer = document.createElement("div");
112
+ this.indicatorContainer.style["width"] = "100%";
113
+ // this.indicatorContainer.style["position"] = "100%";
114
+
115
+ this.colorIndicatorButton = document.createElement("button");
116
+ this.colorIndicatorButton.style["position"] = "absolute";
117
+ this.colorIndicatorButton.style["bottom"] = "0";
118
+ this.colorIndicatorButton.style["left"] = "0%";
119
+ this.colorIndicatorButton.style["background-color"] = "grey";
120
+ this.colorIndicatorButton.style["border-radius"] = "3px";
121
+ this.colorIndicatorButton.style["border"] = "1px solid grey";
122
+ this.colorIndicatorButton.style["width"] = this.indicatorWidth;
123
+ this.colorIndicatorButton.style["height"] = this.indicatorHeight;
124
+ this.colorIndicatorButton.style["transform"] = "translate(-50%,100%)";
125
+
126
+ this.colorInput = document.createElement("input");
127
+ this.colorInput.setAttribute("type", "color");
128
+ this.colorInput.style["visibility"] = "hidden";
129
+ this.colorInput.dataset["activeSliderIndex"] = "";
130
+ this.colorInput.addEventListener("input", this.__colorChangeHandler());
131
+
132
+ const _self = this;
133
+ this.colorIndicatorButton.addEventListener("click", () => {
134
+ console.log("clicked");
135
+ // _self.colorInput.dispatchEvent(new Event("input"));
136
+ _self.colorInput.click();
137
+ });
138
+
139
+ this.indicatorContainer.appendChild(this.colorIndicatorButton);
140
+ this.container.appendChild(this.indicatorContainer);
141
+ this.container.appendChild(this.colorInput);
142
+ }
143
+
144
+ /**
145
+ * Get a color gradient CSS value string from the current editor settings.
146
+ *
147
+ * @instance
148
+ * @memberof ColorGradientPicker
149
+ * @returns {string}
150
+ */
151
+ public getColorGradient(): string {
152
+ // Example:
153
+ // linear-gradient(90deg,rgba(42, 123, 155, 1) 0%, rgba(87, 199, 133, 1) 38%, rgba(161, 210, 108, 1) 68%, rgba(237, 221, 83, 1) 100%)
154
+ const buffer: Array<string | undefined> = ["linear-gradient( 90deg, "];
155
+ for (var i = 0; i < this.sliderElements.length; i++) {
156
+ if (i > 0) {
157
+ buffer.push(",");
158
+ }
159
+ const colorValue: string = this.__getSliderColor(i, "black");
160
+ buffer.push(colorValue);
161
+ // const sliderValue: number = this.__getSliderValue(i, 0.0);
162
+ // const percentage: number = (this.sliderMin + sliderValue) / (this.sliderMax - this.sliderMin);
163
+ const percentage = this.__getSliderPercentage(i);
164
+ buffer.push(`${percentage * 100}%`);
165
+ }
166
+ buffer.push(")");
167
+
168
+ return buffer.join(" ");
169
+ }
170
+
171
+ /**
172
+ * Creates a callback function for range slider.
173
+ *
174
+ * @returns
175
+ */
176
+ private __createSliderChangeHandler(): (e: Event) => boolean {
177
+ const _self = this;
178
+ return (e: Event): boolean => {
179
+ const targetSlider: HTMLInputElement = e.target as HTMLInputElement;
180
+ console.log("Clicked", targetSlider ? targetSlider.getAttribute("id") : null);
181
+ if (!targetSlider) {
182
+ return false;
183
+ }
184
+ const currentSliderValue: number = Number.parseFloat(targetSlider.value);
185
+ const rangeSliderIndexRaw: string | undefined = targetSlider.dataset["rangeSliderIndex"];
186
+ if (!rangeSliderIndexRaw) {
187
+ return false;
188
+ }
189
+ const rangeSliderIndex: number = Number.parseInt(rangeSliderIndexRaw);
190
+ var leftSliderValue = this.__getSliderValue(rangeSliderIndex - 1, _self.sliderMin);
191
+ var rightSliderValue = this.__getSliderValue(rangeSliderIndex + 1, _self.sliderMax);
192
+ if (leftSliderValue >= currentSliderValue) {
193
+ targetSlider.value = `${leftSliderValue}`;
194
+ _self.__updateBackgroundGradient();
195
+ _self.__updateColorIndicator(rangeSliderIndex);
196
+ return false;
197
+ } else if (rightSliderValue <= currentSliderValue) {
198
+ targetSlider.value = `${rightSliderValue}`;
199
+ _self.__updateBackgroundGradient();
200
+ _self.__updateColorIndicator(rangeSliderIndex);
201
+
202
+ return false;
203
+ } else {
204
+ _self.__updateBackgroundGradient();
205
+ _self.__updateColorIndicator(rangeSliderIndex);
206
+ return true;
207
+ }
208
+ };
209
+ }
210
+
211
+ private __colorChangeHandler(): (_evt: Event) => boolean {
212
+ const _self = this;
213
+ return (_evt: Event): boolean => {
214
+ // const colorInput : HTMLInputElement | null = evt.target;
215
+ const activeSliderIndex_raw = this.colorInput.dataset["activeSliderIndex"];
216
+ if (!activeSliderIndex_raw) {
217
+ console.warn("Cannot update color indicator; no active range slider set.");
218
+ return false;
219
+ }
220
+ const activeSliderIndex = Number.parseInt(activeSliderIndex_raw);
221
+ if (Number.isNaN(activeSliderIndex) || activeSliderIndex < 0 || activeSliderIndex >= _self.sliderElements.length) {
222
+ console.warn("Cannot update color indicator; active index invalid or out of bounds.", activeSliderIndex);
223
+ return false;
224
+ }
225
+
226
+ const newColor: string = _self.colorInput.value;
227
+ const rangeSlider: HTMLInputElement = _self.sliderElements[activeSliderIndex];
228
+ rangeSlider.dataset["colorValue"] = newColor;
229
+ // rangeSlider.dataset["colorValue"] = newColor;
230
+ this.colorIndicatorButton.style["background-color"] = newColor;
231
+ _self.__updateBackgroundGradient();
232
+
233
+ return true;
234
+ };
235
+ }
236
+
237
+ /**
238
+ * Updates the container's background to display the configured color gradient.
239
+ *
240
+ * @private
241
+ */
242
+ private __updateBackgroundGradient() {
243
+ const colorGradient = this.getColorGradient();
244
+ console.log(colorGradient);
245
+ this.container.style["background"] = colorGradient;
246
+ console.log(this.container);
247
+ // document.body.style["background-color"] = colorGradient;
248
+ }
249
+
250
+ private __updateColorIndicator(rangeSliderIndex: number) {
251
+ const colorValue = this.__getSliderColor(rangeSliderIndex, "grey");
252
+ const ratio = this.__getSliderPercentage(rangeSliderIndex);
253
+ this.colorIndicatorButton.style["left"] = `calc( ${ratio * 100}% + ${(1.0 - ratio) * this.indicatorWidth_num * 0.5}em - ${
254
+ ratio * this.indicatorWidth_num * 0.5
255
+ }em)`;
256
+
257
+ this.colorIndicatorButton.style["background-color"] = colorValue;
258
+ this.colorInput.value = colorValue;
259
+ this.colorInput.dataset["activeSliderIndex"] = `${rangeSliderIndex}`;
260
+ }
261
+
262
+ /**
263
+ * Get the value of the n-th rangel slider.
264
+ *
265
+ * @param {number} sliderIndex
266
+ * @param {number} fallback
267
+ * @returns
268
+ */
269
+ private __getSliderValue(sliderIndex: number, fallback: number): number {
270
+ if (sliderIndex < 0 || sliderIndex >= this.sliderElements.length) {
271
+ return fallback;
272
+ }
273
+ return Number.parseFloat(this.sliderElements[sliderIndex].value);
274
+ }
275
+
276
+ /**
277
+ * Get the slider's value in a mapped range of 0.0 ... 1.0.
278
+ *
279
+ * @param sliderIndex
280
+ * @returns
281
+ */
282
+ private __getSliderPercentage(sliderIndex): number {
283
+ const sliderValue: number = this.__getSliderValue(sliderIndex, 0.0);
284
+ const percentage: number = (this.sliderMin + sliderValue) / (this.sliderMax - this.sliderMin);
285
+ return percentage;
286
+ }
287
+
288
+ /**
289
+ * Get the configured color value of the n-th rangel slider.
290
+ *
291
+ * @param {number} sliderIndex
292
+ * @param {string} fallback
293
+ * @returns
294
+ */
295
+ private __getSliderColor(sliderIndex: number, fallback: string): string {
296
+ if (sliderIndex < 0 || sliderIndex >= this.sliderElements.length) {
297
+ return fallback;
298
+ }
299
+ const colorValue = this.sliderElements[sliderIndex].dataset["colorValue"];
300
+ return colorValue ? colorValue : fallback;
301
+ }
302
+
303
+ /**
304
+ * Adds custom styles (global STYLE tag).
305
+ *
306
+ * @private
307
+ */
308
+ private __addCustomStyles() {
309
+ const headElements = document.querySelector("head");
310
+ if (headElements) {
311
+ const thumbWidth = "0.5em";
312
+ const thumbHeight = "1.333em";
313
+ const styleElement = document.createElement("style");
314
+ // Thanks to Ana Tudor
315
+ // https://css-tricks.com/multi-thumb-sliders-particular-two-thumb-case/
316
+ styleElement.innerHTML = `
317
+ input[type='range'] {
318
+
319
+ -webkit-appearance: none;
320
+
321
+ grid-column: 1;
322
+ grid-row: 2;
323
+
324
+ /* same as before */
325
+ background: none; /* get rid of white Chrome background */
326
+ color: #000;
327
+ font: inherit; /* fix too small font-size in both Chrome & Firefox */
328
+ margin: 0;
329
+ pointer-events: none; /* let clicks pass through */
330
+ }
331
+
332
+ input[type='range']::-webkit-slider-runnable-track {
333
+ -webkit-appearance: none;
334
+
335
+ background: none; /* get rid of Firefox track background */
336
+ height: 100%;
337
+ width: 100%;
338
+
339
+ pointer-events: none;
340
+ }
341
+
342
+ input[type='range']::-webkit-slider-thumb {
343
+ -webkit-appearance: none;
344
+ background: currentcolor;
345
+ border: none; /* get rid of Firefox thumb border */
346
+ border-radius: 6px; /* get rid of Firefox corner rounding */
347
+ pointer-events: auto; /* catch clicks */
348
+ width: ${thumbWidth};
349
+ height: ${thumbHeight};
350
+ }
351
+
352
+ input[type='range']:focus::-webkit-slider-thumb {
353
+ border: 2px solid white;
354
+ }
355
+
356
+ input[type='range']::-moz-range-track {
357
+ -webkit-appearance: none;
358
+ background: none; /* get rid of Firefox track background */
359
+ height: 100%;
360
+ width: 100%;
361
+ pointer-events: none;
362
+ }
363
+
364
+ input[type='range']::-moz-range-thumb {
365
+ /* -webkit-appearance: none; */
366
+ background: currentcolor;
367
+ border: none; /* get rid of Firefox thumb border */
368
+ border-radius: 6px; /* get rid of Firefox corner rounding */
369
+ pointer-events: auto; /* catch clicks */
370
+ width: ${thumbWidth};
371
+ height: ${thumbHeight};
372
+ }
373
+
374
+ input[type='range']:focus::-moz-range-thumb {
375
+ border: 2px solid white;
376
+ }
377
+
378
+ input[type='range'] {
379
+ /* same as before */
380
+ z-index: 1;
381
+ }
382
+
383
+ input[type='range']:focus {
384
+ z-index: 2;
385
+ outline: dotted 1px orange;
386
+ color: darkorange;
387
+ }
388
+ `;
389
+ headElements.appendChild(styleElement);
390
+ }
391
+ }
392
+ }
@@ -29,7 +29,7 @@ const applyGuiSize = (gui: GUI, guiDoubleSize: boolean, cssProps: Record<string,
29
29
 
30
30
  const transform = cssProps && cssProps.hasOwnProperty("transform") ? cssProps["transform"] + " " : "";
31
31
 
32
- console.log("transform", transform);
32
+ // console.log("transform", transform);
33
33
  if (guiDoubleSize) {
34
34
  gui.domElement.style["transform"] = transform + "scale(2.0)";
35
35
  } else {
@@ -22,16 +22,21 @@
22
22
  * @modified 2021-03-31 Fixed the issue with the new AlloyFinger (Typescript).
23
23
  * @modified 2022-02-03 Changing the element to catch events (eventCatcher instead of canvas).
24
24
  * @modified 2024-03-10 Fixing some types for Typescript 5 compatibility.
25
- * @version 1.1.3
25
+ * @modified 2025-04-14 Added the `BezierPathInteractionHelper.drawHandleLines` method.
26
+ * @modified 2025-04-14 Fixing correct event types for touch events in `BezierPathInteractionHelper`.
27
+ * @modified 2025-04-14 BezierPathInteractionHelper: Changed default value of `HelperOptions.autoAdjustPaths` from `true` to `false`.
28
+ * @modified 2025-05-05 Added optional params `draw` and `fill` to BezierPathInteractionHelper.drawHandleLines` method.
29
+ * @modified 2025-05-05 Class `BezierPathInteractionHelper` now implementing `IShapeInteractionHelper`.
30
+ * @modified 2025-05-07 Tweaking performance of `BezierPathInteractionHelper`: only triggering redraw now when mouse move within given detect range.
31
+ * @version 1.2.1
26
32
  *
27
33
  * @file BezierPathInteractionHelper
28
34
  * @public
29
35
  **/
30
36
 
31
- // import { AlloyFinger } from "alloyfinger"; // node_modules
32
37
  // I would like to use AlloyFinger from the node_modules, but it seems
33
38
  // AlloyTeam has forgotten to publish their d.ts file.
34
- import { AlloyFinger } from "../../../../lib/alloy_finger";
39
+ import AlloyFinger from "alloyfinger-typescript";
35
40
  import { BezierPath } from "../../BezierPath";
36
41
  import { CubicBezierCurve } from "../../CubicBezierCurve";
37
42
  import { KeyHandler } from "../../KeyHandler";
@@ -40,7 +45,8 @@ import { PlotBoilerplate } from "../../PlotBoilerplate";
40
45
  import { VertListener } from "../../VertexListeners";
41
46
  import { Vertex } from "../../Vertex";
42
47
  import { XMouseEvent } from "../../MouseHandler";
43
- import { XYCoords } from "../../interfaces";
48
+ import { DrawLib, IShapeInteractionHelper, XYCoords } from "../../interfaces";
49
+ import { AFTouchEvent } from "alloyfinger-typescript/src/cjs/alloy_finger";
44
50
 
45
51
  /**
46
52
  * Handler type for mouse-pointer-moved listeners.
@@ -88,7 +94,7 @@ interface HelperOptions {
88
94
  *
89
95
  * @public
90
96
  **/
91
- export class BezierPathInteractionHelper {
97
+ export class BezierPathInteractionHelper implements IShapeInteractionHelper {
92
98
  /**
93
99
  * @member {PlotBoilerplate} pb
94
100
  * @memberof BezierPathInteractionHelper
@@ -153,7 +159,9 @@ export class BezierPathInteractionHelper {
153
159
  this.pb = pb;
154
160
  this.paths = [];
155
161
  this.onPointerMoved =
156
- typeof options.onPointerMoved === "function" ? options.onPointerMoved : (i: number, a: Vertex | null, b: Vertex | null, t: number) => {};
162
+ typeof options.onPointerMoved === "function"
163
+ ? options.onPointerMoved
164
+ : (i: number, a: Vertex | null, b: Vertex | null, t: number) => {};
157
165
  this.onVertexInserted =
158
166
  typeof options.onVertexInserted === "function"
159
167
  ? options.onVertexInserted
@@ -163,7 +171,7 @@ export class BezierPathInteractionHelper {
163
171
  ? options.onVerticesDeleted
164
172
  : (i: number, r: Array<number>, n: BezierPath, o: BezierPath) => {};
165
173
  this.onPathRemoved = typeof options.onPathRemoved === "function" ? options.onPathRemoved : (i: number, o: BezierPath) => {};
166
- this.autoAdjustPaths = typeof options.autoAdjustPaths === "boolean" ? options.autoAdjustPaths : true;
174
+ this.autoAdjustPaths = typeof options.autoAdjustPaths === "boolean" ? options.autoAdjustPaths : false; // true;
167
175
  this.allowPathRemoval = typeof options.allowPathRemoval === "boolean" ? options.allowPathRemoval : true;
168
176
  this.maxDetectDistance = typeof options.maxDetectDistance === "number" ? options.maxDetectDistance : Number.MAX_VALUE;
169
177
 
@@ -192,7 +200,9 @@ export class BezierPathInteractionHelper {
192
200
  this._keyHandler = this._installKeyListener();
193
201
 
194
202
  // Paths might have changed by auto-adjustment.
195
- if (this.autoAdjustPaths) pb.redraw();
203
+ if (this.autoAdjustPaths) {
204
+ pb.redraw();
205
+ }
196
206
  }
197
207
 
198
208
  /**
@@ -263,6 +273,28 @@ export class BezierPathInteractionHelper {
263
273
  this._handleMoveEvent(this.currentB.x, this.currentB.y);
264
274
  }
265
275
 
276
+ /**
277
+ * Draw grey handle lines.
278
+ *
279
+ * @param {DrawLib<any>} draw - (optional) The draw library to use. If not provided then `pb.draw` will be used.
280
+ * @param {DrawLib<any>} fill - (optional) The fill library to use. If not provided then `pb.fill` will be used.
281
+ */
282
+ drawHandleLines(draw?: DrawLib<any>, fill?: DrawLib<any>) {
283
+ draw = draw || this.pb.draw;
284
+ fill = fill || this.pb.fill;
285
+ this.paths.forEach((path: BezierPath) => {
286
+ path.bezierCurves.forEach((curve: CubicBezierCurve) => {
287
+ this.pb.draw.line(curve.startPoint, curve.startControlPoint, "rgba(64,192,128,0.333)", 1.0, {
288
+ dashOffset: 0.0,
289
+ dashArray: [4, 2]
290
+ });
291
+ this.pb.draw.line(curve.endPoint, curve.endControlPoint, "rgba(64,192,128,0.333)", 1.0, {
292
+ dashOffset: 0.0,
293
+ dashArray: [4, 2]
294
+ });
295
+ });
296
+ });
297
+ }
266
298
  /**
267
299
  * This function should invalidate any installed listeners and invalidate this object.
268
300
  * After calling this function the object might not hold valid data any more and
@@ -409,6 +441,9 @@ export class BezierPathInteractionHelper {
409
441
  // | Touch and mouse events should call this fuction when the pointer was moved.
410
442
  // +-------------------------------
411
443
  private _handleMoveEvent(posX: number, posY: number): void {
444
+ const oldA = this.currentA.clone();
445
+ const oldB = this.currentB.clone();
446
+ const oldDistance = this.currentDistance;
412
447
  const point: XYCoords = this.pb.transformMousePosition(posX, posY);
413
448
  this.currentB.set(point);
414
449
  this._updateMinDistance();
@@ -418,8 +453,14 @@ export class BezierPathInteractionHelper {
418
453
  } else {
419
454
  this.onPointerMoved(-1, null, null, 0.0);
420
455
  }
421
- // Always redraw even when moving outside the detection distance?
422
- this.pb.redraw();
456
+ // Only redraw when moving inside the detection distance
457
+ if (
458
+ (this.currentDistance <= this.maxDetectDistance ||
459
+ (this.currentDistance > this.maxDetectDistance && oldDistance <= this.maxDetectDistance)) &&
460
+ (!oldA.equals(this.currentA) || !oldB.equals(this.currentB))
461
+ ) {
462
+ this.pb.redraw();
463
+ }
423
464
  }
424
465
 
425
466
  // +---------------------------------------------------------------------------------
@@ -437,23 +478,24 @@ export class BezierPathInteractionHelper {
437
478
  private _installTouchListener(): AlloyFinger {
438
479
  var _self: BezierPathInteractionHelper = this;
439
480
  const afProps = {
440
- // Todo: which event types does AlloyFinger use?
441
- touchStart: function (_event: TouchEvent) {
481
+ touchStart: function (_event: AFTouchEvent<"touchStart">) {
442
482
  _self.mouseIsOver = true;
443
483
  },
444
- touchMove: function (event: TouchEvent) {
484
+ touchMove: function (event: AFTouchEvent<"touchMove">) {
445
485
  if (_self.pb.getDraggedElementCount() == 0 && event.touches.length > 0) {
446
- // console.log('touchmove');
447
486
  _self._handleMoveEvent(event.touches[0].clientX, event.touches[0].clientY);
448
487
  }
449
488
  },
450
- touchEnd: function (_event: TouchEvent) {
489
+ touchEnd: function (_event: AFTouchEvent<"touchEnd">) {
451
490
  _self.mouseIsOver = false;
452
491
  _self._clearMoveEvent();
453
492
  }
454
493
  };
455
494
  if (window["createAlloyFinger" as keyof Object]) {
456
- return (window["createAlloyFinger" as keyof Object] as any)(this.pb.eventCatcher ? this.pb.eventCatcher : this.pb.eventCatcher, afProps);
495
+ return (window["createAlloyFinger" as keyof Object] as any)(
496
+ this.pb.eventCatcher ? this.pb.eventCatcher : this.pb.eventCatcher,
497
+ afProps
498
+ );
457
499
  } else {
458
500
  return new AlloyFinger(this.pb.eventCatcher ? this.pb.eventCatcher : this.pb.eventCatcher, afProps);
459
501
  }
@@ -537,7 +579,9 @@ export class BezierPathInteractionHelper {
537
579
  // | Update the min distance from point `line.b` to the curve. And redraw.
538
580
  // +-------------------------------
539
581
  private _updateMinDistance(): void {
540
- if (this.paths.length == 0) return;
582
+ if (this.paths.length == 0) {
583
+ return;
584
+ }
541
585
  let pathIndex: number = -1;
542
586
  let minDist: number = Number.MAX_VALUE;
543
587
  let closestPoint: Vertex | null = null;
@@ -578,24 +622,6 @@ export class BezierPathInteractionHelper {
578
622
  path.updateArcLengths();
579
623
  }
580
624
 
581
- /**
582
- * A helper function to add drag-start-listener to given vertices.
583
- */
584
- /* private static _addVertsDragStartListener( verts:Array<Vertex>, dragStartListener:VertListener ) : void {
585
- for( var i in verts ) {
586
- verts[i].addDragStartListener( dragStartListener );
587
- }
588
- }; */
589
-
590
- /**
591
- * A helper function to remove drag-start-listener to given vertices.
592
- */
593
- /* private static _removeVertsDragStartListener( verts:Array<Vertex>, dragEndListener:VertListener ) : void {
594
- for( var i in verts ) {
595
- verts[i].removeDragStartListener( dragStartListener );
596
- }
597
- }; */
598
-
599
625
  /**
600
626
  * A helper function to add drag-start listeners to all vertices of the given path.
601
627
  *
@@ -10,17 +10,20 @@
10
10
  * @modified 2024-02-26 Removed the constructor param `pb` (unused).
11
11
  * @modified 2024-02-25 Added `circle` and `radiusPoint` attributes.
12
12
  * @modified 2024-03-10 Fixed some issues in the `destroy` method; listeners were not properly removed.
13
+ * @modified 2025-05-05 Class `BezierPathInteractionHelper` now implementing `IShapeInteractionHelper`.
13
14
  * @version 1.2.1
14
15
  **/
15
16
 
16
17
  import { Circle } from "../../Circle";
17
18
  import { VertEvent, VertListener } from "../../VertexListeners";
18
19
  import { Vertex } from "../../Vertex";
20
+ import { IShapeInteractionHelper } from "../../interfaces/core";
21
+ import { DrawLib } from "../../interfaces/DrawLib";
19
22
 
20
23
  /**
21
24
  * @classdesc A helper for handling circles with an additional radius-control-point.
22
25
  */
23
- export class CircleHelper {
26
+ export class CircleHelper implements IShapeInteractionHelper {
24
27
  circle: Circle;
25
28
  radiusPoint: Vertex;
26
29
 
@@ -40,8 +43,18 @@ export class CircleHelper {
40
43
  this.circle = circle;
41
44
  this.radiusPoint = radiusPoint;
42
45
 
43
- circle.center.listeners.addDragListener( this.centerHandler = this._handleDragCenter());
44
- radiusPoint.listeners.addDragListener(this.radiusHandler = this._handleDragRadiusPoint());
46
+ circle.center.listeners.addDragListener((this.centerHandler = this._handleDragCenter()));
47
+ radiusPoint.listeners.addDragListener((this.radiusHandler = this._handleDragRadiusPoint()));
48
+ }
49
+
50
+ //--- BEGIN --- Implement ISHapeInteractionHelper ---
51
+ /**
52
+ * Let this shape helper draw it's handle lines. It's up to the helper what they look like.
53
+ * @param {DrawLib<any>} draw - The draw library to use.
54
+ * @param {DrawLib<any>} fill - The fill library to use.
55
+ */
56
+ drawHandleLines(_draw: DrawLib<any>, _fill: DrawLib<any>): void {
57
+ // NOOP
45
58
  }
46
59
 
47
60
  /**
@@ -56,6 +69,7 @@ export class CircleHelper {
56
69
  this.circle.center.listeners.removeDragListener(this.centerHandler);
57
70
  this.radiusPoint.listeners.removeDragListener(this.radiusHandler);
58
71
  }
72
+ //--- END --- Implement ISHapeInteractionHelper ---
59
73
 
60
74
  /**
61
75
  * Creates a new drag handler for the circle's center point.