gridviz 3.0.15 → 3.0.17

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 (55) hide show
  1. package/README.md +127 -128
  2. package/dist/gridviz.js +7958 -7861
  3. package/dist/gridviz.min.js +1 -1
  4. package/package.json +74 -74
  5. package/src/button/ZoomButtons.js +101 -96
  6. package/src/core/Dataset.js +154 -157
  7. package/src/core/Drawable.js +60 -61
  8. package/src/core/GeoCanvas.js +409 -370
  9. package/src/core/Layer.js +23 -25
  10. package/src/core/Legend.js +108 -110
  11. package/src/core/Map.js +494 -495
  12. package/src/core/MultiResolutionDataset.js +93 -97
  13. package/src/core/Style.js +98 -99
  14. package/src/dataset/CSVGrid.js +112 -112
  15. package/src/dataset/GeoTIFF.js +122 -123
  16. package/src/dataset/JSGrid.js +55 -54
  17. package/src/dataset/TiledGrid.js +289 -288
  18. package/src/dataset/worker.js +18 -0
  19. package/src/index.js +77 -71
  20. package/src/layer/BackgroundLayer.js +162 -158
  21. package/src/layer/BackgroundLayerImage.js +81 -84
  22. package/src/layer/BackgroundLayerWMS.js +104 -108
  23. package/src/layer/GeoJSONLayer.js +214 -220
  24. package/src/layer/GridLayer.js +148 -157
  25. package/src/layer/LabelLayer.js +194 -193
  26. package/src/legend/ColorCategoryLegend.js +109 -110
  27. package/src/legend/ColorDiscreteLegend.js +100 -102
  28. package/src/legend/ColorLegend.js +115 -118
  29. package/src/legend/OrientationLegend.js +89 -91
  30. package/src/legend/SizeLegend.js +224 -224
  31. package/src/legend/TernaryLegend.js +302 -210
  32. package/src/style/CompositionStyle.js +291 -288
  33. package/src/style/DotDensityStyle.js +133 -134
  34. package/src/style/ImageStyle.js +100 -102
  35. package/src/style/IsoFenceStyle.js +217 -203
  36. package/src/style/JoyPlotStyle.js +127 -128
  37. package/src/style/LegoStyle.js +110 -110
  38. package/src/style/MosaicStyle.js +99 -99
  39. package/src/style/NinjaStarStyle.js +102 -102
  40. package/src/style/PillarStyle.js +207 -208
  41. package/src/style/SegmentStyle.js +105 -105
  42. package/src/style/ShapeColorSizeStyle.js +147 -132
  43. package/src/style/SideCategoryStyle.js +112 -114
  44. package/src/style/SideStyle.js +212 -205
  45. package/src/style/SquareColorCategoryWebGLStyle.js +107 -108
  46. package/src/style/SquareColorWebGLStyle.js +126 -126
  47. package/src/style/StrokeStyle.js +135 -136
  48. package/src/style/TanakaStyle.js +69 -68
  49. package/src/style/TextStyle.js +110 -111
  50. package/src/style/TimeSeriesStyle.js +222 -229
  51. package/src/utils/scale.js +218 -228
  52. package/src/utils/stretching.js +120 -133
  53. package/src/utils/ternary.js +203 -204
  54. package/src/utils/utils.js +58 -63
  55. package/src/utils/webGLUtils.js +72 -70
@@ -1,204 +1,203 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- import { interpolateLab } from "d3-interpolate"
5
-
6
-
7
-
8
- export const ternaryClassifier = (properties, totalFunction, opts = {}) => {
9
-
10
- //the three properties
11
- const p0 = properties[0], p1 = properties[1], p2 = properties[2]
12
-
13
- //the classifier center point. sum must be equal to 1
14
- const [c0, c1, c2] = opts.center || [1 / 3, 1 / 3, 1 / 3]
15
-
16
- //parameter to decide wether to use mixed classes m0, m1, m2.
17
- const withMixedClasses = opts.withMixedClasses != undefined ? opts.withMixedClasses : true
18
-
19
- //paramerter decide wether to use a central class, and the size of this central class.
20
- //set to 0 or undefined for not showing any central class. Set to 1 for a central class that contains the mix classes
21
- const cc = opts.centerCoefficient ? 1 - opts.centerCoefficient : undefined
22
-
23
- //the output classifier method
24
- const fun = c => {
25
- //get total
26
- const tot = totalFunction(c)
27
- if (!tot) return undefined
28
- //compute shares
29
- const [s0, s1, s2] = [+c[p0] / tot, +c[p1] / tot, +c[p2] / tot]
30
-
31
- //class 0
32
- if (s0 >= c0 && s1 <= c1 && s2 <= c2) {
33
- //central class near class 0
34
- if (cc != undefined && (s2 - c2) * (c1 - cc * c1) >= (s1 - cc * c1) * (cc * c2 - c2))
35
- return "center"
36
- return "0"
37
- }
38
- //class 1
39
- if (s0 <= c0 && s1 >= c1 && s2 <= c2) {
40
- //central class near class 1
41
- if (cc != undefined && (s2 - c2) * (c0 - cc * c0) >= (s0 - cc * c0) * (cc * c2 - c2))
42
- return "center"
43
- return "1"
44
- }
45
- //class 2
46
- if (s0 <= c0 && s1 <= c1 && s2 >= c2) {
47
- //central class near class 2
48
- if (cc != undefined && (s1 - c1) * (c0 - cc * c0) >= (s0 - cc * c0) * (cc * c1 - c1))
49
- return "center"
50
- return "2"
51
- }
52
- //middle class 0 - intersection class 1 and 2
53
- if (s0 <= c0 && s1 >= c1 && s2 >= c2) {
54
- //central class
55
- if (cc != undefined && s0 > cc * c0) return "center"
56
- if (withMixedClasses) return "m12"
57
- return s1 > s2 ? "1" : "2"
58
- }
59
- //middle class 1 - intersection class 0 and 1
60
- if (s0 >= c0 && s1 <= c1 && s2 >= c2) {
61
- //central class
62
- if (cc != undefined && s1 > cc * c1) return "center"
63
- if (withMixedClasses) return "m02"
64
- return s0 > s2 ? "0" : "2"
65
- }
66
- //middle class 2 - intersection class 0 and 1
67
- if (s0 >= c0 && s1 >= c1 && s2 <= c2) {
68
- //central class
69
- if (cc != undefined && s2 > cc * c2) return "center"
70
- if (withMixedClasses) return "m01"
71
- return s1 > s0 ? "1" : "0"
72
- }
73
- //should not happen
74
- return "unknown"
75
- }
76
-
77
- //attach information to output function
78
- fun.center = [c0, c1, c2]
79
- fun.centerCoefficient = opts.centerCoefficient
80
-
81
- return fun
82
- }
83
-
84
-
85
-
86
- export const ternaryColorClassifier = (properties, totalFunction, colors, opts = {}) => {
87
-
88
- //the three colors
89
- const [color0, color1, color2] = colors || ["red", "green", "blue"]
90
-
91
- //the color interpolation function
92
- const colorInterpolation = opts.colorInterpolation || interpolateLab
93
-
94
- //parameter to decide wether to use mixed classes.
95
- const withMixedClasses = opts.withMixedClasses != undefined ? opts.withMixedClasses : true
96
- //https://d3js.org/d3-interpolate/color
97
- const mixColorFunction = (color1, color2) => colorInterpolation(color1, color2)(0.5)
98
- //the colors corresponding to the mixed classes
99
- const [mixColor0, mixColor1, mixColor2] = opts.mixedColors || withMixedClasses ? [mixColorFunction(color1, color2), mixColorFunction(color0, color2), mixColorFunction(color0, color1)] : []
100
-
101
- //the central color, used for the central class, if any. The central class is the class of relatively balanced values, around the center point
102
- const centerColor = opts.centerColor || colorInterpolation(mixColorFunction(color0, color1), color2)(0.333)
103
-
104
- //make classifier
105
- const classifier = ternaryClassifier(properties, totalFunction, opts)
106
-
107
- //the output color classifier method
108
- const fun = c => {
109
- const cla = classifier(c)
110
- if (cla == "0") return color0
111
- if (cla == "1") return color1
112
- if (cla == "2") return color2
113
- if (cla == "m12") return mixColor0
114
- if (cla == "m02") return mixColor1
115
- if (cla == "m01") return mixColor2
116
- if (cla == "center") return centerColor
117
- return opts.defaultColor || "black"
118
- }
119
- fun.center = classifier.center
120
- fun.centerCoefficient = opts.centerCoefficient
121
- fun.colors = [color0, color1, color2]
122
- fun.mixColors = [mixColor0, mixColor1, mixColor2]
123
- fun.centerColor = centerColor
124
- fun.classifier = classifier
125
-
126
- return fun
127
- }
128
-
129
-
130
-
131
-
132
-
133
-
134
- /*
135
- const orderedIndexesDec = arr => [...arr.keys()].sort((a, b) => arr[b] - arr[a]);
136
- const orderedIndexesInc = arr => [...arr.keys()].sort((a, b) => arr[a] - arr[b]);
137
-
138
- export const ternaryClassifier = (properties, totalFunction, opts = {}) => {
139
- const lowThreshold = opts.lowThreshold || [1 / 3, 1 / 3, 1 / 3]
140
- const highThreshold = opts.highThreshold || [2 / 3, 2 / 3, 2 / 3]
141
- const colors = opts.colors || ["red", "green", "blue"]
142
- const colorInterpolation = opts.colorInterpolation || interpolateLab
143
-
144
- //https://d3js.org/d3-interpolate/color
145
- const middleColorFunction = (color1, color2) => colorInterpolation(color1, color2)(0.5)
146
- const middleColors = opts.middleColors || [middleColorFunction(colors[1], colors[2]), middleColorFunction(colors[0], colors[2]), middleColorFunction(colors[0], colors[1])]
147
- const centerColor = opts.centerColor || colorInterpolation(middleColors[2], colors[2])(0.333)
148
-
149
- const high_ = orderedIndexesDec(highThreshold)
150
- const low_ = orderedIndexesInc(lowThreshold)
151
-
152
- const p0 = properties[0], p1 = properties[1], p2 = properties[2]
153
- const fun = c => {
154
- //get total
155
- const tot = totalFunction(c)
156
- if (!tot) return undefined
157
- //compute shares
158
- const shares = [+c[p0] / tot, +c[p1] / tot, +c[p2] / tot]
159
- //return colors
160
- //start first with the extreme high (triangles): from the larger value (small triangle) to the lower value (large triangle)
161
- for (let i of high_) if (shares[i] > highThreshold[i]) return colors[i]
162
- //then draw the extreme low (trapeziums): from the lower value (small trapeziums) to the larger values (large trapezium)
163
- for (let i of low_) if (shares[i] < lowThreshold[i]) return middleColors[i]
164
- //else central color
165
- return centerColor
166
- }
167
- fun.lowThreshold = lowThreshold
168
- fun.highThreshold = highThreshold
169
- fun.colors = colors
170
- fun.middleColors = middleColors
171
- fun.centerColor = centerColor
172
- fun.lowIndex = low_
173
- fun.highIndex = high_
174
- return fun
175
- }
176
- */
177
-
178
- /*
179
- export const ternaryClassifier3 = (properties, totalFunction, opts = {}) => {
180
- const [a01, a12, a20] = opts.thresholds || [1/3, 1/3, 1/3]
181
- const [c0, c1, c2] = opts.colors || ["red", "green", "blue"]
182
- const centerColor = opts.centerColor || "gray"
183
-
184
- const fff = a => a == 1 ? Infinity : a / (1 - a)
185
- const c01 = fff(a01), c12 = fff(a12), c20 = fff(a20)
186
-
187
- const p0 = properties[0], p1 = properties[1], p2 = properties[2]
188
- const fun = c => {
189
- //get total
190
- const tot = totalFunction(c)
191
- if (!tot) return undefined
192
- //compute shares
193
- const [s0, s1, s2] = [+c[p0] / tot, +c[p1] / tot, +c[p2] / tot]
194
- //return colors
195
- if (s0 * c01 > s1 && s0 > s2 * c20) return c0
196
- else if (s1 > s0 * c01 && s1 * c12 > s2) return c1
197
- else if (s2 * c20 > s0 && s2 > s1 * c12) return c2
198
- else return centerColor
199
- }
200
- fun.colors = [c0, c1, c2]
201
- fun.centerColor = centerColor
202
- return fun
203
- }
204
- */
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { interpolateLab } from 'd3-interpolate'
5
+
6
+ export const ternaryClassifier = (properties, totalFunction, opts = {}) => {
7
+ //the three properties
8
+ const p0 = properties[0],
9
+ p1 = properties[1],
10
+ p2 = properties[2]
11
+
12
+ //the classifier center point. sum must be equal to 1
13
+ const [c0, c1, c2] = opts.center || [1 / 3, 1 / 3, 1 / 3]
14
+
15
+ //parameter to decide wether to use mixed classes m0, m1, m2.
16
+ const withMixedClasses = opts.withMixedClasses != undefined ? opts.withMixedClasses : true
17
+
18
+ //paramerter decide wether to use a central class, and the size of this central class.
19
+ //set to 0 or undefined for not showing any central class. Set to 1 for a central class that contains the mix classes
20
+ const cc = opts.centerCoefficient ? 1 - opts.centerCoefficient : undefined
21
+
22
+ //the output classifier method
23
+ const fun = (c) => {
24
+ //get total
25
+ const tot = totalFunction(c)
26
+ if (!tot) return undefined
27
+ //compute shares
28
+ const [s0, s1, s2] = [+c[p0] / tot, +c[p1] / tot, +c[p2] / tot]
29
+
30
+ //class 0
31
+ if (s0 >= c0 && s1 <= c1 && s2 <= c2) {
32
+ //central class near class 0
33
+ if (cc != undefined && (s2 - c2) * (c1 - cc * c1) >= (s1 - cc * c1) * (cc * c2 - c2))
34
+ return 'center'
35
+ return '0'
36
+ }
37
+ //class 1
38
+ if (s0 <= c0 && s1 >= c1 && s2 <= c2) {
39
+ //central class near class 1
40
+ if (cc != undefined && (s2 - c2) * (c0 - cc * c0) >= (s0 - cc * c0) * (cc * c2 - c2))
41
+ return 'center'
42
+ return '1'
43
+ }
44
+ //class 2
45
+ if (s0 <= c0 && s1 <= c1 && s2 >= c2) {
46
+ //central class near class 2
47
+ if (cc != undefined && (s1 - c1) * (c0 - cc * c0) >= (s0 - cc * c0) * (cc * c1 - c1))
48
+ return 'center'
49
+ return '2'
50
+ }
51
+ //middle class 0 - intersection class 1 and 2
52
+ if (s0 <= c0 && s1 >= c1 && s2 >= c2) {
53
+ //central class
54
+ if (cc != undefined && s0 > cc * c0) return 'center'
55
+ if (withMixedClasses) return 'm12'
56
+ return s1 > s2 ? '1' : '2'
57
+ }
58
+ //middle class 1 - intersection class 0 and 1
59
+ if (s0 >= c0 && s1 <= c1 && s2 >= c2) {
60
+ //central class
61
+ if (cc != undefined && s1 > cc * c1) return 'center'
62
+ if (withMixedClasses) return 'm02'
63
+ return s0 > s2 ? '0' : '2'
64
+ }
65
+ //middle class 2 - intersection class 0 and 1
66
+ if (s0 >= c0 && s1 >= c1 && s2 <= c2) {
67
+ //central class
68
+ if (cc != undefined && s2 > cc * c2) return 'center'
69
+ if (withMixedClasses) return 'm01'
70
+ return s1 > s0 ? '1' : '0'
71
+ }
72
+ //should not happen
73
+ return 'unknown'
74
+ }
75
+
76
+ //attach information to output function
77
+ fun.center = [c0, c1, c2]
78
+ fun.centerCoefficient = opts.centerCoefficient
79
+
80
+ return fun
81
+ }
82
+
83
+ export const ternaryColorClassifier = (properties, totalFunction, colors, opts = {}) => {
84
+ //the three colors
85
+ const [color0, color1, color2] = colors || ['red', 'green', 'blue']
86
+
87
+ //the color interpolation function
88
+ const colorInterpolation = opts.colorInterpolation || interpolateLab
89
+
90
+ //parameter to decide wether to use mixed classes.
91
+ const withMixedClasses = opts.withMixedClasses != undefined ? opts.withMixedClasses : true
92
+ //https://d3js.org/d3-interpolate/color
93
+ const mixColorFunction = (color1, color2) => colorInterpolation(color1, color2)(0.5)
94
+ //the colors corresponding to the mixed classes
95
+ const [mixColor0, mixColor1, mixColor2] =
96
+ opts.mixedColors || withMixedClasses
97
+ ? [
98
+ mixColorFunction(color1, color2),
99
+ mixColorFunction(color0, color2),
100
+ mixColorFunction(color0, color1),
101
+ ]
102
+ : []
103
+
104
+ //the central color, used for the central class, if any. The central class is the class of relatively balanced values, around the center point
105
+ const centerColor =
106
+ opts.centerColor || colorInterpolation(mixColorFunction(color0, color1), color2)(0.333)
107
+
108
+ //make classifier
109
+ const classifier = ternaryClassifier(properties, totalFunction, opts)
110
+
111
+ //the output color classifier method
112
+ const fun = (c) => {
113
+ const cla = classifier(c)
114
+ if (cla == '0') return color0
115
+ if (cla == '1') return color1
116
+ if (cla == '2') return color2
117
+ if (cla == 'm12') return mixColor0
118
+ if (cla == 'm02') return mixColor1
119
+ if (cla == 'm01') return mixColor2
120
+ if (cla == 'center') return centerColor
121
+ return opts.defaultColor || 'black'
122
+ }
123
+ fun.center = classifier.center
124
+ fun.centerCoefficient = opts.centerCoefficient
125
+ fun.colors = [color0, color1, color2]
126
+ fun.mixColors = [mixColor0, mixColor1, mixColor2]
127
+ fun.centerColor = centerColor
128
+ fun.classifier = classifier
129
+
130
+ return fun
131
+ }
132
+
133
+ /*
134
+ const orderedIndexesDec = arr => [...arr.keys()].sort((a, b) => arr[b] - arr[a]);
135
+ const orderedIndexesInc = arr => [...arr.keys()].sort((a, b) => arr[a] - arr[b]);
136
+
137
+ export const ternaryClassifier = (properties, totalFunction, opts = {}) => {
138
+ const lowThreshold = opts.lowThreshold || [1 / 3, 1 / 3, 1 / 3]
139
+ const highThreshold = opts.highThreshold || [2 / 3, 2 / 3, 2 / 3]
140
+ const colors = opts.colors || ["red", "green", "blue"]
141
+ const colorInterpolation = opts.colorInterpolation || interpolateLab
142
+
143
+ //https://d3js.org/d3-interpolate/color
144
+ const middleColorFunction = (color1, color2) => colorInterpolation(color1, color2)(0.5)
145
+ const middleColors = opts.middleColors || [middleColorFunction(colors[1], colors[2]), middleColorFunction(colors[0], colors[2]), middleColorFunction(colors[0], colors[1])]
146
+ const centerColor = opts.centerColor || colorInterpolation(middleColors[2], colors[2])(0.333)
147
+
148
+ const high_ = orderedIndexesDec(highThreshold)
149
+ const low_ = orderedIndexesInc(lowThreshold)
150
+
151
+ const p0 = properties[0], p1 = properties[1], p2 = properties[2]
152
+ const fun = c => {
153
+ //get total
154
+ const tot = totalFunction(c)
155
+ if (!tot) return undefined
156
+ //compute shares
157
+ const shares = [+c[p0] / tot, +c[p1] / tot, +c[p2] / tot]
158
+ //return colors
159
+ //start first with the extreme high (triangles): from the larger value (small triangle) to the lower value (large triangle)
160
+ for (let i of high_) if (shares[i] > highThreshold[i]) return colors[i]
161
+ //then draw the extreme low (trapeziums): from the lower value (small trapeziums) to the larger values (large trapezium)
162
+ for (let i of low_) if (shares[i] < lowThreshold[i]) return middleColors[i]
163
+ //else central color
164
+ return centerColor
165
+ }
166
+ fun.lowThreshold = lowThreshold
167
+ fun.highThreshold = highThreshold
168
+ fun.colors = colors
169
+ fun.middleColors = middleColors
170
+ fun.centerColor = centerColor
171
+ fun.lowIndex = low_
172
+ fun.highIndex = high_
173
+ return fun
174
+ }
175
+ */
176
+
177
+ /*
178
+ export const ternaryClassifier3 = (properties, totalFunction, opts = {}) => {
179
+ const [a01, a12, a20] = opts.thresholds || [1/3, 1/3, 1/3]
180
+ const [c0, c1, c2] = opts.colors || ["red", "green", "blue"]
181
+ const centerColor = opts.centerColor || "gray"
182
+
183
+ const fff = a => a == 1 ? Infinity : a / (1 - a)
184
+ const c01 = fff(a01), c12 = fff(a12), c20 = fff(a20)
185
+
186
+ const p0 = properties[0], p1 = properties[1], p2 = properties[2]
187
+ const fun = c => {
188
+ //get total
189
+ const tot = totalFunction(c)
190
+ if (!tot) return undefined
191
+ //compute shares
192
+ const [s0, s1, s2] = [+c[p0] / tot, +c[p1] / tot, +c[p2] / tot]
193
+ //return colors
194
+ if (s0 * c01 > s1 && s0 > s2 * c20) return c0
195
+ else if (s1 > s0 * c01 && s1 * c12 > s2) return c1
196
+ else if (s2 * c20 > s0 && s2 > s1 * c12) return c2
197
+ else return centerColor
198
+ }
199
+ fun.colors = [c0, c1, c2]
200
+ fun.centerColor = centerColor
201
+ return fun
202
+ }
203
+ */
@@ -1,63 +1,58 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- /**
5
- * Get the class id from a value and class break values
6
- *
7
- * @param {number} v the value
8
- * @param {Array.<number>} breaks the breaks
9
- * @returns The class id, from 0 to breaks.length
10
- * @deprecated use getClassifier instead
11
- */
12
- export function getClass(v, breaks) {
13
- if (!breaks) return
14
- if (breaks.length == 0) return 0
15
- if (v <= breaks[0]) return 0
16
- for (let i = 1; i < breaks.length; i++) if (breaks[i - 1] < v && v <= breaks[i]) return i
17
- return breaks.length
18
- }
19
-
20
-
21
-
22
- //take 'nice' value (power of ten, or multiple)
23
- export function nice(v, multiples = [8, 6, 5, 4, 2.5, 2]) {
24
- //compute bigger power of ten below
25
- const v_ = Math.pow(10, Math.floor(Math.log10(v)))
26
- for (let multiple of multiples)
27
- if (v_ * multiple <= v) return v_ * multiple
28
- return v_
29
- }
30
-
31
-
32
- /*
33
- //no longer used
34
- export function loadImage(src) {
35
- return new Promise((resolve, reject) => {
36
- const img = new Image();
37
- img.onload = function () { resolve(img); };
38
- img.onerror = function () { reject(new Error('Error loading image')); };
39
- img.src = src;
40
- });
41
- }
42
- */
43
-
44
-
45
- /*
46
- export let monitor = false
47
-
48
- let previousDate
49
- export function monitorDuration(message) {
50
- const nowDate = Date.now()
51
-
52
- //first call
53
- if (!previousDate) {
54
- previousDate = nowDate
55
- console.log(previousDate, message)
56
- return
57
- }
58
-
59
- const d = nowDate - previousDate
60
- previousDate = nowDate
61
- console.log(d, message)
62
- }
63
- */
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ /**
5
+ * Get the class id from a value and class break values
6
+ *
7
+ * @param {number} v the value
8
+ * @param {Array.<number>} breaks the breaks
9
+ * @returns The class id, from 0 to breaks.length
10
+ * @deprecated use getClassifier instead.
11
+ */
12
+ export function getClass(v, breaks) {
13
+ if (!breaks) return
14
+ if (breaks.length == 0) return 0
15
+ if (v <= breaks[0]) return 0
16
+ for (let i = 1; i < breaks.length; i++) if (breaks[i - 1] < v && v <= breaks[i]) return i
17
+ return breaks.length
18
+ }
19
+
20
+ //take 'nice' value (power of ten, or multiple)
21
+ export function nice(v, multiples = [8, 6, 5, 4, 2.5, 2]) {
22
+ //compute bigger power of ten below
23
+ const v_ = Math.pow(10, Math.floor(Math.log10(v)))
24
+ for (let multiple of multiples) if (v_ * multiple <= v) return v_ * multiple
25
+ return v_
26
+ }
27
+
28
+ /*
29
+ //no longer used
30
+ export function loadImage(src) {
31
+ return new Promise((resolve, reject) => {
32
+ const img = new Image();
33
+ img.onload = function () { resolve(img); };
34
+ img.onerror = function () { reject(new Error('Error loading image')); };
35
+ img.src = src;
36
+ });
37
+ }
38
+ */
39
+
40
+ /*
41
+ export let monitor = false
42
+
43
+ let previousDate
44
+ export function monitorDuration(message) {
45
+ const nowDate = Date.now()
46
+
47
+ //first call
48
+ if (!previousDate) {
49
+ previousDate = nowDate
50
+ console.log(previousDate, message)
51
+ return
52
+ }
53
+
54
+ const d = nowDate - previousDate
55
+ previousDate = nowDate
56
+ console.log(d, message)
57
+ }
58
+ */