plotboilerplate 1.24.0 → 1.26.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.
- package/README.md +14 -1
- package/dist/index.esm.js +433 -162
- package/dist/index.esm.js.map +1 -1
- package/dist/index.esm.min.js +1 -1
- package/dist/index.esm.min.js.map +1 -1
- package/dist/plotboilerplate.browser.min.js +1 -1
- package/dist/plotboilerplate.browser.min.js.map +1 -1
- package/dist/plotboilerplate.js +12312 -12041
- package/dist/plotboilerplate.min.js +1 -1
- package/package.json +9 -5
- package/src/cjs/Bounds.d.ts +79 -25
- package/src/cjs/Bounds.js +102 -29
- package/src/cjs/Bounds.js.map +1 -1
- package/src/cjs/CircleSector.d.ts +3 -0
- package/src/cjs/CircleSector.js +28 -1
- package/src/cjs/CircleSector.js.map +1 -1
- package/src/cjs/PlotBoilerplate.d.ts +37 -6
- package/src/cjs/PlotBoilerplate.js +222 -116
- package/src/cjs/PlotBoilerplate.js.map +1 -1
- package/src/cjs/Polygon.d.ts +26 -7
- package/src/cjs/Polygon.js +56 -10
- package/src/cjs/Polygon.js.map +1 -1
- package/src/cjs/Triangle.js +2 -2
- package/src/cjs/Triangle.js.map +1 -1
- package/src/cjs/Vertex.d.ts +15 -3
- package/src/cjs/Vertex.js +18 -1
- package/src/cjs/Vertex.js.map +1 -1
- package/src/cjs/drawutilssvg.d.ts +2 -1
- package/src/cjs/drawutilssvg.js +9 -3
- package/src/cjs/drawutilssvg.js.map +1 -1
- package/src/cjs/interfaces/core.d.ts +28 -0
- package/src/cjs/interfaces/core.js +2 -0
- package/src/cjs/interfaces/core.js.map +1 -1
- package/src/cjs/utils/LissajousFigure.d.ts +34 -0
- package/src/cjs/utils/LissajousFigure.js +100 -0
- package/src/cjs/utils/LissajousFigure.js.map +1 -0
- package/src/cjs/utils/PerlinNoise.d.ts +19 -0
- package/src/cjs/utils/PerlinNoise.js +352 -0
- package/src/cjs/utils/PerlinNoise.js.map +1 -0
- package/src/cjs/utils/SVGPathUtils.d.ts +22 -0
- package/src/cjs/utils/SVGPathUtils.js +45 -0
- package/src/cjs/utils/SVGPathUtils.js.map +1 -0
- package/src/cjs/utils/algorithms/pixelCornersToRoundPaths.d.ts +23 -0
- package/src/cjs/utils/algorithms/pixelCornersToRoundPaths.js +270 -0
- package/src/cjs/utils/algorithms/pixelCornersToRoundPaths.js.map +1 -0
- package/src/cjs/utils/datastructures/Color.d.ts +147 -1
- package/src/cjs/utils/datastructures/Color.js +385 -41
- package/src/cjs/utils/datastructures/Color.js.map +1 -1
- package/src/cjs/utils/datastructures/ColorGradient.d.ts +79 -0
- package/src/cjs/utils/datastructures/ColorGradient.js +171 -0
- package/src/cjs/utils/datastructures/ColorGradient.js.map +1 -0
- package/src/cjs/utils/datastructures/DataGrid2d.d.ts +6 -0
- package/src/cjs/utils/datastructures/DataGrid2dArrayMatrix.d.ts +88 -0
- package/src/cjs/utils/datastructures/DataGrid2dArrayMatrix.js +155 -0
- package/src/cjs/utils/datastructures/DataGrid2dArrayMatrix.js.map +1 -0
- package/src/cjs/utils/datastructures/DataGrid2dListAdapter.d.ts +1 -7
- package/src/cjs/utils/datastructures/DataGrid2dListAdapter.js +3 -3
- package/src/cjs/utils/datastructures/DataGrid2dListAdapter.js.map +1 -1
- package/src/cjs/utils/datastructures/GeometryMesh.d.ts +49 -0
- package/src/cjs/utils/datastructures/GeometryMesh.js +58 -0
- package/src/cjs/utils/datastructures/GeometryMesh.js.map +1 -0
- package/src/cjs/utils/detectDarkMode.js +16 -7
- package/src/cjs/utils/detectDarkMode.js.map +1 -1
- package/src/cjs/utils/dom/components/ColorGradientPicker.d.ts +246 -0
- package/src/cjs/utils/dom/components/ColorGradientPicker.js +667 -0
- package/src/cjs/utils/dom/components/ColorGradientPicker.js.map +1 -0
- package/src/cjs/utils/dom/components/ColorGradientPickerJSX.d.ts +129 -0
- package/src/cjs/utils/dom/components/ColorGradientPickerJSX.js +520 -0
- package/src/cjs/utils/dom/components/ColorGradientPickerJSX.js.map +1 -0
- package/src/cjs/utils/dom/components/ColorGradientSelector.d.ts +118 -0
- package/src/cjs/utils/dom/components/ColorGradientSelector.js +327 -0
- package/src/cjs/utils/dom/components/ColorGradientSelector.js.map +1 -0
- package/src/cjs/utils/dom/components/Test.d.ts +7 -0
- package/src/cjs/utils/dom/components/Test.js +30 -0
- package/src/cjs/utils/dom/components/Test.js.map +1 -0
- package/src/cjs/utils/dom/guiSizeToggler.js +1 -1
- package/src/cjs/utils/dom/guiSizeToggler.js.map +1 -1
- package/src/cjs/utils/helpers/BezierPathInteractionHelper.d.ts +9 -3
- package/src/cjs/utils/helpers/BezierPathInteractionHelper.js +20 -13
- package/src/cjs/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
- package/src/cjs/utils/helpers/CircleHelper.d.ts +10 -1
- package/src/cjs/utils/helpers/CircleHelper.js +13 -2
- package/src/cjs/utils/helpers/CircleHelper.js.map +1 -1
- package/src/cjs/utils/helpers/CircleSectorHelper.d.ts +2 -2
- package/src/cjs/utils/helpers/CircleSectorHelper.js +1 -0
- package/src/cjs/utils/helpers/CircleSectorHelper.js.map +1 -1
- package/src/cjs/utils/helpers/TriangleHelper.d.ts +57 -0
- package/src/cjs/utils/helpers/TriangleHelper.js +83 -0
- package/src/cjs/utils/helpers/TriangleHelper.js.map +1 -0
- package/src/cjs/utils/helpers/VEllipseHelper.d.ts +6 -4
- package/src/cjs/utils/helpers/VEllipseHelper.js +4 -2
- package/src/cjs/utils/helpers/VEllipseHelper.js.map +1 -1
- package/src/cjs/utils/helpers/VEllipseSectorHelper.d.ts +3 -2
- package/src/cjs/utils/helpers/VEllipseSectorHelper.js +1 -0
- package/src/cjs/utils/helpers/VEllipseSectorHelper.js.map +1 -1
- package/src/cjs/utils/parsers/LinearColorGradientParser.d.ts +78 -0
- package/src/cjs/utils/parsers/LinearColorGradientParser.js +224 -0
- package/src/cjs/utils/parsers/LinearColorGradientParser.js.map +1 -0
- package/src/cjs/utils/parsers/svg/types.d.ts +8 -8
- package/src/createDemoDrawables.js +1 -0
- package/src/esm/Bounds.d.ts +79 -25
- package/src/esm/Bounds.js +102 -29
- package/src/esm/Bounds.js.map +1 -1
- package/src/esm/CircleSector.d.ts +3 -0
- package/src/esm/CircleSector.js +28 -1
- package/src/esm/CircleSector.js.map +1 -1
- package/src/esm/PlotBoilerplate.d.ts +37 -6
- package/src/esm/PlotBoilerplate.js +222 -116
- package/src/esm/PlotBoilerplate.js.map +1 -1
- package/src/esm/Polygon.d.ts +26 -7
- package/src/esm/Polygon.js +53 -10
- package/src/esm/Polygon.js.map +1 -1
- package/src/esm/Triangle.js +2 -2
- package/src/esm/Triangle.js.map +1 -1
- package/src/esm/Vertex.d.ts +15 -3
- package/src/esm/Vertex.js +18 -1
- package/src/esm/Vertex.js.map +1 -1
- package/src/esm/drawutilssvg.d.ts +2 -1
- package/src/esm/drawutilssvg.js +9 -3
- package/src/esm/drawutilssvg.js.map +1 -1
- package/src/esm/interfaces/core.d.ts +28 -0
- package/src/esm/interfaces/core.js +2 -0
- package/src/esm/interfaces/core.js.map +1 -1
- package/src/esm/utils/LissajousFigure.d.ts +34 -0
- package/src/esm/utils/LissajousFigure.js +95 -0
- package/src/esm/utils/LissajousFigure.js.map +1 -0
- package/src/esm/utils/PerlinNoise.d.ts +19 -0
- package/src/esm/utils/PerlinNoise.js +346 -0
- package/src/esm/utils/PerlinNoise.js.map +1 -0
- package/src/esm/utils/SVGPathUtils.d.ts +22 -0
- package/src/esm/utils/SVGPathUtils.js +42 -0
- package/src/esm/utils/SVGPathUtils.js.map +1 -0
- package/src/esm/utils/algorithms/pixelCornersToRoundPaths.d.ts +23 -0
- package/src/esm/utils/algorithms/pixelCornersToRoundPaths.js +266 -0
- package/src/esm/utils/algorithms/pixelCornersToRoundPaths.js.map +1 -0
- package/src/esm/utils/datastructures/Color.d.ts +147 -1
- package/src/esm/utils/datastructures/Color.js +386 -42
- package/src/esm/utils/datastructures/Color.js.map +1 -1
- package/src/esm/utils/datastructures/ColorGradient.d.ts +79 -0
- package/src/esm/utils/datastructures/ColorGradient.js +166 -0
- package/src/esm/utils/datastructures/ColorGradient.js.map +1 -0
- package/src/esm/utils/datastructures/DataGrid2d.d.ts +6 -0
- package/src/esm/utils/datastructures/DataGrid2dArrayMatrix.d.ts +88 -0
- package/src/esm/utils/datastructures/DataGrid2dArrayMatrix.js +150 -0
- package/src/esm/utils/datastructures/DataGrid2dArrayMatrix.js.map +1 -0
- package/src/esm/utils/datastructures/DataGrid2dListAdapter.d.ts +1 -7
- package/src/esm/utils/datastructures/DataGrid2dListAdapter.js +3 -3
- package/src/esm/utils/datastructures/DataGrid2dListAdapter.js.map +1 -1
- package/src/esm/utils/datastructures/GeometryMesh.d.ts +49 -0
- package/src/esm/utils/datastructures/GeometryMesh.js +53 -0
- package/src/esm/utils/datastructures/GeometryMesh.js.map +1 -0
- package/src/esm/utils/detectDarkMode.js +16 -7
- package/src/esm/utils/detectDarkMode.js.map +1 -1
- package/src/esm/utils/dom/components/ColorGradientPicker.d.ts +246 -0
- package/src/esm/utils/dom/components/ColorGradientPicker.js +743 -0
- package/src/esm/utils/dom/components/ColorGradientPicker.js.map +1 -0
- package/src/esm/utils/dom/components/ColorGradientPickerJSX.d.ts +129 -0
- package/src/esm/utils/dom/components/ColorGradientPickerJSX.js +582 -0
- package/src/esm/utils/dom/components/ColorGradientPickerJSX.js.map +1 -0
- package/src/esm/utils/dom/components/ColorGradientSelector.d.ts +118 -0
- package/src/esm/utils/dom/components/ColorGradientSelector.js +339 -0
- package/src/esm/utils/dom/components/ColorGradientSelector.js.map +1 -0
- package/src/esm/utils/dom/components/Test.d.ts +7 -0
- package/src/esm/utils/dom/components/Test.js +26 -0
- package/src/esm/utils/dom/components/Test.js.map +1 -0
- package/src/esm/utils/dom/guiSizeToggler.js +1 -1
- package/src/esm/utils/dom/guiSizeToggler.js.map +1 -1
- package/src/esm/utils/helpers/BezierPathInteractionHelper.d.ts +9 -3
- package/src/esm/utils/helpers/BezierPathInteractionHelper.js +20 -13
- package/src/esm/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
- package/src/esm/utils/helpers/CircleHelper.d.ts +10 -1
- package/src/esm/utils/helpers/CircleHelper.js +13 -2
- package/src/esm/utils/helpers/CircleHelper.js.map +1 -1
- package/src/esm/utils/helpers/CircleSectorHelper.d.ts +2 -2
- package/src/esm/utils/helpers/CircleSectorHelper.js +1 -0
- package/src/esm/utils/helpers/CircleSectorHelper.js.map +1 -1
- package/src/esm/utils/helpers/TriangleHelper.d.ts +57 -0
- package/src/esm/utils/helpers/TriangleHelper.js +78 -0
- package/src/esm/utils/helpers/TriangleHelper.js.map +1 -0
- package/src/esm/utils/helpers/VEllipseHelper.d.ts +6 -4
- package/src/esm/utils/helpers/VEllipseHelper.js +4 -2
- package/src/esm/utils/helpers/VEllipseHelper.js.map +1 -1
- package/src/esm/utils/helpers/VEllipseSectorHelper.d.ts +3 -2
- package/src/esm/utils/helpers/VEllipseSectorHelper.js +1 -0
- package/src/esm/utils/helpers/VEllipseSectorHelper.js.map +1 -1
- package/src/esm/utils/parsers/LinearColorGradientParser.d.ts +78 -0
- package/src/esm/utils/parsers/LinearColorGradientParser.js +217 -0
- package/src/esm/utils/parsers/LinearColorGradientParser.js.map +1 -0
- package/src/esm/utils/parsers/svg/types.d.ts +8 -8
- package/src/external.d.ts +9 -0
- package/src/ts/Bounds.ts +107 -22
- package/src/ts/CircleSector.ts +39 -6
- package/src/ts/PlotBoilerplate.ts +233 -105
- package/src/ts/Polygon.ts +68 -14
- package/src/ts/Triangle.ts +2 -2
- package/src/ts/Vertex.ts +21 -3
- package/src/ts/drawutilssvg.ts +8 -3
- package/src/ts/interfaces/core.ts +31 -0
- package/src/ts/utils/LissajousFigure.ts +110 -0
- package/src/ts/utils/PerlinNoise.ts +368 -0
- package/src/ts/utils/SVGPathUtils.ts +55 -0
- package/src/ts/utils/algorithms/pixelCornersToRoundPaths.ts +379 -0
- package/src/ts/utils/datastructures/Color.ts +423 -44
- package/src/ts/utils/datastructures/ColorGradient.ts +196 -0
- package/src/ts/utils/datastructures/DataGrid2d.ts +7 -0
- package/src/ts/utils/datastructures/DataGrid2dArrayMatrix.ts +182 -0
- package/src/ts/utils/datastructures/DataGrid2dListAdapter.ts +4 -11
- package/src/ts/utils/datastructures/GeometryMesh.ts +79 -0
- package/src/ts/utils/detectDarkMode.ts +17 -8
- package/src/ts/utils/dom/components/ColorGradientPicker.tsx +889 -0
- package/src/ts/utils/dom/components/ColorGradientSelector.tsx +452 -0
- package/src/ts/utils/dom/components/Test.tsx +44 -0
- package/src/ts/utils/dom/components/_ColorGradientPicker_raw.ts_ +392 -0
- package/src/ts/utils/dom/guiSizeToggler.ts +1 -1
- package/src/ts/utils/helpers/BezierPathInteractionHelper.ts +25 -15
- package/src/ts/utils/helpers/CircleHelper.ts +17 -3
- package/src/ts/utils/helpers/CircleSectorHelper.ts +4 -2
- package/src/ts/utils/helpers/TriangleHelper.ts +102 -0
- package/src/ts/utils/helpers/VEllipseHelper.ts +6 -4
- package/src/ts/utils/helpers/VEllipseSectorHelper.ts +3 -2
- package/src/ts/utils/parsers/LinearColorGradientParser.ts +297 -0
- package/src/ts/utils/parsers/svg/types.ts +8 -8
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A simple linear color gradient implementation.
|
|
3
|
+
*
|
|
4
|
+
* A color gradient is just an array of color objects paired with position values on the gradient.
|
|
5
|
+
*
|
|
6
|
+
* TODO: add `angle`
|
|
7
|
+
*
|
|
8
|
+
* @author Ikaros Kappler
|
|
9
|
+
* @version 1.0.0
|
|
10
|
+
* @date 2025-08-05
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { Color } from "./Color";
|
|
14
|
+
|
|
15
|
+
const RAD_TO_DEG: number = 180.0 / Math.PI;
|
|
16
|
+
|
|
17
|
+
export type ColorGradientRotation = number | `${number}deg` | `${number}turn` | `to top` | "to bottom" | "to left" | "to right";
|
|
18
|
+
|
|
19
|
+
const DEFAULT_COLORSET: Array<ColorGradientItem> = [
|
|
20
|
+
{ color: Color.Red, ratio: 0.0 },
|
|
21
|
+
{ color: Color.Gold, ratio: 0.2 },
|
|
22
|
+
{ color: Color.Yellow, ratio: 0.4 },
|
|
23
|
+
{ color: Color.LimeGreen, ratio: 0.6 },
|
|
24
|
+
{ color: Color.MediumBlue, ratio: 0.8 },
|
|
25
|
+
{ color: Color.Purple, ratio: 1.0 }
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
export interface ColorGradientItem {
|
|
29
|
+
color: Color;
|
|
30
|
+
ratio: number; // Ideally a percentage value in [0.0 .. 1.0]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class ColorGradient {
|
|
34
|
+
values: Array<ColorGradientItem>;
|
|
35
|
+
angle: ColorGradientRotation;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Creates a new ColorGradient with the given values. Please be sure that the values appear in the correct
|
|
39
|
+
* order regarding the `ratio` information. This will not be validated.
|
|
40
|
+
*
|
|
41
|
+
* @param {Array<ColorGradientItem>} values - The values to use.
|
|
42
|
+
* @param {number?} angle - (optional) An optional angle for the gradient; if no specified `PI/2.0` will be used (vertical from left to right).
|
|
43
|
+
*/
|
|
44
|
+
constructor(values: Array<ColorGradientItem>, angle?: ColorGradientRotation) {
|
|
45
|
+
this.values = values;
|
|
46
|
+
// Default: left to right
|
|
47
|
+
this.angle = typeof angle === "undefined" ? Math.PI / 2.0 : angle;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get a color gradient CSS value string from these gradient settings.
|
|
52
|
+
*
|
|
53
|
+
* @instance
|
|
54
|
+
* @memberof ColorGradientPicker
|
|
55
|
+
* @returns {string}
|
|
56
|
+
*/
|
|
57
|
+
public toColorGradientString(): string {
|
|
58
|
+
// Example:
|
|
59
|
+
// 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%)
|
|
60
|
+
|
|
61
|
+
// const buffer: Array<string | undefined> = [`linear-gradient( ${RAD_TO_DEG * this.angle}deg, `];
|
|
62
|
+
const buffer: Array<string | undefined> = [
|
|
63
|
+
`linear-gradient( ${typeof this.angle === "number" ? `${this.angle * RAD_TO_DEG}deg` : this.angle}, `
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
for (var i = 0; i < this.values.length; i++) {
|
|
67
|
+
if (i > 0) {
|
|
68
|
+
buffer.push(",");
|
|
69
|
+
}
|
|
70
|
+
const colorValue: string = this.values[i] ? this.values[i].color.cssRGBA() : null;
|
|
71
|
+
buffer.push(colorValue);
|
|
72
|
+
const percentage = this.values[i].ratio;
|
|
73
|
+
buffer.push(`${typeof percentage === "number" ? `${percentage * 100}%` : percentage}`);
|
|
74
|
+
}
|
|
75
|
+
buffer.push(")");
|
|
76
|
+
|
|
77
|
+
return buffer.join(" ");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get the color at the specific relative position.
|
|
82
|
+
*
|
|
83
|
+
* @param {number} ratio - Any value between 0.0 and 1.0.
|
|
84
|
+
*/
|
|
85
|
+
getColorAt(ratio: number): Color {
|
|
86
|
+
// Locate interval first
|
|
87
|
+
const intervalLocation: [number, ColorGradientItem] = this.locateClosestRatio(ratio);
|
|
88
|
+
const leftItem: ColorGradientItem = this.values[intervalLocation[0]];
|
|
89
|
+
const rightItem: ColorGradientItem = this.values[intervalLocation[0] + 1];
|
|
90
|
+
const relativeInnerIntervalPosition: number = (ratio - leftItem.ratio) / (rightItem.ratio - leftItem.ratio);
|
|
91
|
+
return leftItem.color.clone().interpolate(rightItem.color, relativeInnerIntervalPosition);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Find that gradient record (index) that's value is closest to the given relative value. The function will return
|
|
96
|
+
* the closest value and the left index, indicating the containing interval index.
|
|
97
|
+
*
|
|
98
|
+
* @param {number} ratio - The value to look for.
|
|
99
|
+
* @returns {[number,number]} A pair of left interval boundary index and closest value.
|
|
100
|
+
*/
|
|
101
|
+
locateClosestRatio(ratio: number): [number, ColorGradientItem] {
|
|
102
|
+
if (this.values.length === 0) {
|
|
103
|
+
console.warn("[Warn] All slider values array is empty. This should not happen, cannot proceed.");
|
|
104
|
+
return [NaN, null]; // This should not happen: at least two values must be present in a gradient
|
|
105
|
+
}
|
|
106
|
+
// console.log("__locateClosestSliderValue", "allSliderValues", allSliderValues);
|
|
107
|
+
let leftSliderIndex: number = 0;
|
|
108
|
+
let closestSliderValue: ColorGradientItem = this.values[leftSliderIndex];
|
|
109
|
+
for (var i = 1; i < this.values.length; i++) {
|
|
110
|
+
const curVal: ColorGradientItem = this.values[i];
|
|
111
|
+
if (Math.abs(curVal.ratio - ratio) < Math.abs(closestSliderValue.ratio - ratio)) {
|
|
112
|
+
closestSliderValue = curVal;
|
|
113
|
+
if (curVal.ratio > ratio) {
|
|
114
|
+
leftSliderIndex = i - 1;
|
|
115
|
+
} else {
|
|
116
|
+
leftSliderIndex = i;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return [leftSliderIndex, closestSliderValue];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Try to convert the given anonymous item (usually and object) to a ColorGradient. This method should be used
|
|
125
|
+
* to restore items from JSON parse results to convert them into proper ColorGradient instances.
|
|
126
|
+
*
|
|
127
|
+
* @param {any} item
|
|
128
|
+
* @returns {ColorGradient}
|
|
129
|
+
*/
|
|
130
|
+
public static fromObject(item: any): ColorGradient {
|
|
131
|
+
if (typeof item !== "object") {
|
|
132
|
+
throw new Error(`Cannot instantiate ColorGradient from item: must be an object. (${typeof item})`);
|
|
133
|
+
}
|
|
134
|
+
if (!item.hasOwnProperty("values")) {
|
|
135
|
+
throw new Error("Cannot instantiate ColorGradient from object: missing property 'values'.");
|
|
136
|
+
}
|
|
137
|
+
const valuesObj: Array<object> = item.values;
|
|
138
|
+
if (!Array.isArray(valuesObj)) {
|
|
139
|
+
throw new Error("Cannot instantiate ColorGradient from object: property 'values' is not an array.");
|
|
140
|
+
}
|
|
141
|
+
const values: Array<ColorGradientItem> = valuesObj.map((element: object, index: number) => {
|
|
142
|
+
if (typeof element !== "object") {
|
|
143
|
+
throw new Error(`Cannot instantiate ColorGradient from object: item at index ${index} is not an object.`);
|
|
144
|
+
}
|
|
145
|
+
if (!element.hasOwnProperty("color") || !element.hasOwnProperty("ratio")) {
|
|
146
|
+
throw new Error(
|
|
147
|
+
`Cannot instantiate ColorGradient from object: item at index ${index} is missing 'color' or 'ratio' property.`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
const tmpElement = element as ColorGradientItem;
|
|
151
|
+
return { color: Color.makeRGB(tmpElement.color.r, tmpElement.color.g, tmpElement.color.b), ratio: tmpElement.ratio };
|
|
152
|
+
});
|
|
153
|
+
// More checks possible here ...
|
|
154
|
+
return new ColorGradient(values, item.angle);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Clone this linear color gradient. Returns a deep clone.
|
|
159
|
+
*
|
|
160
|
+
* @returns {ColorGradient}
|
|
161
|
+
*/
|
|
162
|
+
public clone(): ColorGradient {
|
|
163
|
+
return new ColorGradient(
|
|
164
|
+
this.values.map((item: ColorGradientItem) => {
|
|
165
|
+
return { color: item.color, ratio: item.ratio };
|
|
166
|
+
}),
|
|
167
|
+
this.angle
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Create a default color gradient with six color: red, orange, yellow, green, blue, purple.
|
|
173
|
+
* @returns
|
|
174
|
+
*/
|
|
175
|
+
public static createDefault(): ColorGradient {
|
|
176
|
+
return new ColorGradient(DEFAULT_COLORSET.map((item: ColorGradientItem) => ({ color: item.color, ratio: item.ratio })));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Create a basic color gradient from only two colors.
|
|
181
|
+
*
|
|
182
|
+
* @param {Color} startColor - The leftmost color.
|
|
183
|
+
* @param {Color} endColor - The rightmost color.
|
|
184
|
+
* @param {number?} angleInRadians - (optional) An optional angle for the gradient; if no specified `PI/2.0` will be used (vertical from left to right).
|
|
185
|
+
* @returns
|
|
186
|
+
*/
|
|
187
|
+
public static createFrom(startColor: Color, endColor: Color, angleInRadians?: number): ColorGradient {
|
|
188
|
+
return new ColorGradient(
|
|
189
|
+
[
|
|
190
|
+
{ ratio: 0.0, color: startColor },
|
|
191
|
+
{ ratio: 1.0, color: endColor }
|
|
192
|
+
],
|
|
193
|
+
angleInRadians
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
@@ -18,6 +18,13 @@
|
|
|
18
18
|
|
|
19
19
|
export type DataGridFace4<T> = [[T | null, T | null], [T | null, T | null]];
|
|
20
20
|
|
|
21
|
+
export type RasterPosition = {
|
|
22
|
+
xIndex: number;
|
|
23
|
+
yIndex: number;
|
|
24
|
+
xRel?: number;
|
|
25
|
+
yRel?: number;
|
|
26
|
+
};
|
|
27
|
+
|
|
21
28
|
export interface IDataGrid2d<T> {
|
|
22
29
|
readonly xSegmentCount: number;
|
|
23
30
|
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A DataGrid2d implementation on 2 dimensional arrays.
|
|
3
|
+
*
|
|
4
|
+
* @author Ikaros Kappler
|
|
5
|
+
* @date 2025-10-16
|
|
6
|
+
* @modified 2025-10-28 Added `DataGrid2dArrayMatrix.setAll(function)`.
|
|
7
|
+
* @modified 2025-10-28 Fixed a bug in the `DataGrid2dArrayMatrix.toString()` method.
|
|
8
|
+
* @version 1.0.0
|
|
9
|
+
**/
|
|
10
|
+
|
|
11
|
+
import { arrayFill } from "../algorithms/arrayFill";
|
|
12
|
+
import { DataGridFace4, IDataGrid2d, RasterPosition } from "./DataGrid2d";
|
|
13
|
+
|
|
14
|
+
export class DataGrid2dArrayMatrix<T> implements IDataGrid2d<T> {
|
|
15
|
+
/**
|
|
16
|
+
* @override
|
|
17
|
+
*/
|
|
18
|
+
readonly xSegmentCount: number;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @override
|
|
22
|
+
*/
|
|
23
|
+
readonly ySegmentCount: number;
|
|
24
|
+
|
|
25
|
+
// This is not really useful here ...
|
|
26
|
+
minDataValue: T;
|
|
27
|
+
maxDataValue: T;
|
|
28
|
+
|
|
29
|
+
private _matrix: Array<Array<T>>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Create a new DataGrid2d from the given
|
|
33
|
+
* @throws Error if xSegmentCount*ySegmentCount is larger than the capacity of the array/list.
|
|
34
|
+
* @param list
|
|
35
|
+
* @param xSegmentCount
|
|
36
|
+
* @param ySegmentCount
|
|
37
|
+
*/
|
|
38
|
+
constructor(xSegmentCount: number, ySegmentCount: number, initialValue: T) {
|
|
39
|
+
if (xSegmentCount <= 0) {
|
|
40
|
+
throw `Cannot create DataGrid2dArray, xSegmentCount (${xSegmentCount}) must be > 0.`;
|
|
41
|
+
}
|
|
42
|
+
if (ySegmentCount <= 0) {
|
|
43
|
+
throw `Cannot create DataGrid2dArray, ySegmentCount (${ySegmentCount}) must be > 0.`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// this.canvas = document.getElementById(canvasId);
|
|
47
|
+
this.xSegmentCount = xSegmentCount;
|
|
48
|
+
this.ySegmentCount = ySegmentCount;
|
|
49
|
+
|
|
50
|
+
this._matrix = [];
|
|
51
|
+
for (var i = 0; i < ySegmentCount; i++) {
|
|
52
|
+
this._matrix.push(arrayFill(xSegmentCount, initialValue));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Set the matrix value at the given (x,y) position to a new value.
|
|
58
|
+
*
|
|
59
|
+
* @param {number} xIndex - The horizontal matrix position to set.
|
|
60
|
+
* @param {number} yIndex - The vertical matrix position to set.
|
|
61
|
+
* @param {T} value - The new value.
|
|
62
|
+
*/
|
|
63
|
+
public set(xIndex: number, yIndex: number, value: T) {
|
|
64
|
+
this._matrix[yIndex][xIndex] = value;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Getthe matrix value at the given (x,y) position.
|
|
69
|
+
*
|
|
70
|
+
* @param {number} xIndex - The horizontal matrix position to set.
|
|
71
|
+
* @param {number} yIndex - The vertical matrix position to set.
|
|
72
|
+
* @return {T} value - The new value.
|
|
73
|
+
*/
|
|
74
|
+
public get(xIndex: number, yIndex: number): T {
|
|
75
|
+
return this.getDataValueAt(xIndex, yIndex);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Set all matrix values. The passed factory function must accept respective (x,y) positions.
|
|
80
|
+
*
|
|
81
|
+
* @param {Function} factory - The factory function to determine the new values to set.
|
|
82
|
+
* @return {DataGrid2dArrayMatrix<T>} this - for chaning.
|
|
83
|
+
*/
|
|
84
|
+
public setAll(factory: (xIndex: number, yIndex: number) => T): DataGrid2dArrayMatrix<T> {
|
|
85
|
+
for (var x = 0; x < this.xSegmentCount; x++) {
|
|
86
|
+
for (var y = 0; y < this.ySegmentCount; y++) {
|
|
87
|
+
this.set(x, y, factory(x, y));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public find(
|
|
94
|
+
condition: (value: T, xIndex: number, yIndex: number, sourceMatrix: DataGrid2dArrayMatrix<T>) => boolean
|
|
95
|
+
): RasterPosition {
|
|
96
|
+
for (var x = 0; x < this.xSegmentCount; x++) {
|
|
97
|
+
for (var y = 0; y < this.ySegmentCount; y++) {
|
|
98
|
+
if (condition(this.get(x, y), x, y, this)) {
|
|
99
|
+
return {
|
|
100
|
+
xIndex: x,
|
|
101
|
+
yIndex: y,
|
|
102
|
+
xRel: x / this.xSegmentCount,
|
|
103
|
+
yRel: y / this.ySegmentCount
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @override
|
|
113
|
+
*/
|
|
114
|
+
getMinDataValue(): T {
|
|
115
|
+
return this.minDataValue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @override
|
|
120
|
+
*/
|
|
121
|
+
getMaxDataValue(): T {
|
|
122
|
+
return this.maxDataValue;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @override
|
|
127
|
+
*/
|
|
128
|
+
getDataValueAt(xIndex: number, yIndex: number, isDebug?: boolean): T | null {
|
|
129
|
+
return this._matrix[yIndex][xIndex];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @override
|
|
134
|
+
*/
|
|
135
|
+
getDataFace4At(xIndex: number, yIndex: number, buffer: DataGridFace4<T>) {
|
|
136
|
+
// buffer: array[2][2]
|
|
137
|
+
buffer[0][0] = this.getDataValueAt(xIndex, yIndex);
|
|
138
|
+
buffer[1][0] = this.getDataValueAt(xIndex + 1, yIndex);
|
|
139
|
+
buffer[1][1] = this.getDataValueAt(xIndex + 1, yIndex + 1);
|
|
140
|
+
buffer[0][1] = this.getDataValueAt(xIndex, yIndex + 1);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* A helper method to convert a boolean matrix to a parsable string.
|
|
145
|
+
*
|
|
146
|
+
* @param {DataGrid2dArrayMatrix<boolean>} matrix
|
|
147
|
+
* @returns {string}
|
|
148
|
+
*/
|
|
149
|
+
static toString(matrix: DataGrid2dArrayMatrix<boolean>): string {
|
|
150
|
+
const buffer: Array<string> = [];
|
|
151
|
+
for (var y = 0; y < matrix.ySegmentCount; y++) {
|
|
152
|
+
for (var x = 0; x < matrix.xSegmentCount; x++) {
|
|
153
|
+
buffer.push(matrix.get(x, y) ? "X" : ".");
|
|
154
|
+
}
|
|
155
|
+
buffer.push("\n");
|
|
156
|
+
}
|
|
157
|
+
return buffer.join("");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Simple way to parse a data matrix from a string. `false` should be coded as '.' character,
|
|
162
|
+
* `true` must be coded as 'X' character.
|
|
163
|
+
*
|
|
164
|
+
* @param {string} str - The input string.
|
|
165
|
+
* @param {number} width - The desired width of the matrix (xSegmentCount).
|
|
166
|
+
* @param {number} height - The desired height of the matrix (ySegmentCount).
|
|
167
|
+
* @returns {DataGrid2dArrayMatrix<boolean>}
|
|
168
|
+
*/
|
|
169
|
+
static parseBooleanMatrix(str: string, width: number, height: number): DataGrid2dArrayMatrix<boolean> {
|
|
170
|
+
const matrix = new DataGrid2dArrayMatrix<boolean>(width, height, false);
|
|
171
|
+
const lines: String[] = str.trim().split("\n");
|
|
172
|
+
for (var y = 0; y < lines.length && y < height; y++) {
|
|
173
|
+
lines[y] = lines[y].trim();
|
|
174
|
+
for (var x = 0; x < lines[y].length && x < width; x++) {
|
|
175
|
+
if (y < height && x < width && lines[y].charAt(x) === "X") {
|
|
176
|
+
matrix.set(x, y, true);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return matrix;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @version 1.0.0
|
|
8
8
|
**/
|
|
9
9
|
|
|
10
|
-
import { DataGridFace4, IDataGrid2d } from "./DataGrid2d";
|
|
10
|
+
import { DataGridFace4, IDataGrid2d, RasterPosition } from "./DataGrid2d";
|
|
11
11
|
|
|
12
12
|
type Triplet<T> = {
|
|
13
13
|
x: T;
|
|
@@ -15,13 +15,6 @@ type Triplet<T> = {
|
|
|
15
15
|
z: T;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
type RasterPosition = {
|
|
19
|
-
xIndex: number;
|
|
20
|
-
yIndex: number;
|
|
21
|
-
xRel?: number;
|
|
22
|
-
yRel?: number;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
18
|
export class DataGrid2dListAdapter<T> implements IDataGrid2d<T> {
|
|
26
19
|
/**
|
|
27
20
|
* @override
|
|
@@ -96,9 +89,9 @@ export class DataGrid2dListAdapter<T> implements IDataGrid2d<T> {
|
|
|
96
89
|
getDataValueAt(xIndex: number, yIndex: number, isDebug?: boolean): T | null {
|
|
97
90
|
// var bufferIndex = yIndex * this.xSegmentCount + xIndex;
|
|
98
91
|
var bufferIndex = this.coordinateIndicesToBufferIndex(xIndex, yIndex);
|
|
99
|
-
if (isDebug) {
|
|
100
|
-
|
|
101
|
-
}
|
|
92
|
+
// if (isDebug) {
|
|
93
|
+
// console.log("xIndex", xIndex, "yIndex", yIndex, "bufferIndex", bufferIndex);
|
|
94
|
+
// }
|
|
102
95
|
if (bufferIndex > this._dataList.length) {
|
|
103
96
|
console.error("ERR buffer index is out of bounds! xIndex", xIndex, "yIndex", yIndex, "bufferIndex", bufferIndex);
|
|
104
97
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapted from the 3D geometry datastuctured from demo-33 (depth mesh).
|
|
3
|
+
*
|
|
4
|
+
* Refactored the strucure into a class.
|
|
5
|
+
*
|
|
6
|
+
* @author Ikaros Kappler
|
|
7
|
+
* @date 2025-11-14
|
|
8
|
+
* @modified 2025-11-17 Moved `getBounds` and `normalizeGeometry` from helper functions to this class.
|
|
9
|
+
* @version 1.0.0
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export type Vertex2 = { x: number; y: number };
|
|
13
|
+
export type Vertex3 = { x: number; y: number; z: number };
|
|
14
|
+
|
|
15
|
+
export class GeometryMesh<T extends Vertex2 | Vertex3> {
|
|
16
|
+
/**
|
|
17
|
+
* A set (array) of vertices (points) used in this mesh. Can be 2d or 3d.
|
|
18
|
+
*
|
|
19
|
+
* @member {Array<T>}
|
|
20
|
+
* @memberof GeometryMesh
|
|
21
|
+
* @type {Array<T>}
|
|
22
|
+
* @instance
|
|
23
|
+
*/
|
|
24
|
+
vertices: Array<T>;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A set (array) of edges used in this mesh.
|
|
28
|
+
* Each edge consist of two indices indicating the vertex position.
|
|
29
|
+
*
|
|
30
|
+
* @member {Array<T>}
|
|
31
|
+
* @memberof GeometryMesh
|
|
32
|
+
* @type {Array<T>}
|
|
33
|
+
* @instance
|
|
34
|
+
*/
|
|
35
|
+
edges: Array<[number, number]>;
|
|
36
|
+
|
|
37
|
+
constructor(vertices?: Array<T>, edges?: Array<[number, number]>) {
|
|
38
|
+
this.vertices = vertices || [];
|
|
39
|
+
this.edges = edges || [];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
normalize() {
|
|
43
|
+
// Desired bounds is a max bounding box. The object will be scaled keeping aspect ratio
|
|
44
|
+
// in that way that the largest axis size touches the desired bounds.
|
|
45
|
+
var desiredBounds = { min: { x: -1, y: -1, z: -1 }, max: { x: 1, y: 1, z: 1 } };
|
|
46
|
+
var bounds = this.getGeometryBounds();
|
|
47
|
+
var sizeX = bounds.max.x - bounds.min.x;
|
|
48
|
+
var sizeY = bounds.max.y - bounds.min.y;
|
|
49
|
+
var sizeZ = bounds.max.z - bounds.min.z;
|
|
50
|
+
// Scale uniform so the dimension with the max expansion fits into [-1,1]
|
|
51
|
+
var maxDimension = Math.max(sizeX, sizeY, sizeZ);
|
|
52
|
+
var desiredSizeX = (desiredBounds.max.x - desiredBounds.min.x) / maxDimension;
|
|
53
|
+
var desiredSizeY = (desiredBounds.max.y - desiredBounds.min.y) / maxDimension;
|
|
54
|
+
var desiredSizeZ = (desiredBounds.max.z - desiredBounds.min.z) / maxDimension;
|
|
55
|
+
for (var i in this.vertices) {
|
|
56
|
+
var vert = this.vertices[i] as Vertex3; // TODO: Check if this is safe
|
|
57
|
+
vert.x = desiredBounds.min.x + (bounds.max.x - vert.x) * desiredSizeX;
|
|
58
|
+
vert.y = desiredBounds.min.y + (bounds.max.y - vert.y) * desiredSizeY;
|
|
59
|
+
vert.z = desiredBounds.min.z + (bounds.max.z - vert.z) * desiredSizeZ;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
getGeometryBounds(): { min: Vertex3; max: Vertex3; width: number; height: number; depth: number } {
|
|
64
|
+
// var min = new Vert3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
|
|
65
|
+
// var max = new Vert3(Number.MIN_VALUE, Number.MIN_VALUE, Number.MIN_VALUE);
|
|
66
|
+
var min = { x: Number.MAX_VALUE, y: Number.MAX_VALUE, z: Number.MAX_VALUE };
|
|
67
|
+
var max = { x: Number.MIN_VALUE, y: Number.MIN_VALUE, z: Number.MIN_VALUE };
|
|
68
|
+
for (var i in this.vertices) {
|
|
69
|
+
var vert = this.vertices[i] as Vertex3;
|
|
70
|
+
min.x = Math.min(vert.x, min.x);
|
|
71
|
+
min.y = Math.min(vert.y, min.y);
|
|
72
|
+
min.z = Math.min(vert.z, min.z);
|
|
73
|
+
max.x = Math.max(vert.x, max.x);
|
|
74
|
+
max.y = Math.max(vert.y, max.y);
|
|
75
|
+
max.z = Math.max(vert.z, max.z);
|
|
76
|
+
}
|
|
77
|
+
return { min: min, max: max, width: max.x - min.x, height: max.y - min.y, depth: max.z - min.z };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -9,20 +9,29 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
export const detectDarkMode = (GUP?: Record<string, string>): boolean => {
|
|
12
|
+
var isDarkmode: boolean = false;
|
|
12
13
|
// Respect overrides
|
|
13
14
|
if (typeof GUP !== "undefined" && GUP.hasOwnProperty("darkmode") && GUP["darkmode"]) {
|
|
14
15
|
// const overrideValue = PlotBoilerplate.utils.fetch.bool(GUP, "darkmode", null);
|
|
15
16
|
const overrideValue = !!JSON.parse(GUP["darkmode"]);
|
|
16
17
|
if (overrideValue !== null) {
|
|
17
|
-
|
|
18
|
+
isDarkmode = overrideValue;
|
|
18
19
|
}
|
|
19
|
-
}
|
|
20
|
-
if (globalThis.matchMedia && globalThis.matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
20
|
+
} else if (globalThis.matchMedia && globalThis.matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
21
21
|
// dark mode by system
|
|
22
|
-
|
|
22
|
+
isDarkmode = true;
|
|
23
|
+
} else {
|
|
24
|
+
// else: dark mode by daytime
|
|
25
|
+
const hours = new Date().getHours();
|
|
26
|
+
const isDayTime = hours > 6 && hours < 18;
|
|
27
|
+
isDarkmode = !isDayTime;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// console.log("Adding darkmode to <body>", isDarkmode);
|
|
31
|
+
if (isDarkmode && document.body) {
|
|
32
|
+
// Add darkmode class to <body> tag
|
|
33
|
+
document.body.classList.add("darkmode");
|
|
23
34
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const isDayTime = hours > 6 && hours < 18;
|
|
27
|
-
return !isDayTime;
|
|
35
|
+
|
|
36
|
+
return isDarkmode;
|
|
28
37
|
};
|