gridviz 3.0.23 → 3.0.24
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 +128 -128
- package/dist/gridviz.js +8618 -8579
- package/dist/gridviz.min.js +1 -1
- package/package.json +74 -74
- package/src/button/Button.js +67 -67
- package/src/button/FullscreenButton.js +121 -121
- package/src/button/ZoomButtons.js +103 -101
- package/src/core/Dataset.js +154 -154
- package/src/core/Drawable.js +78 -78
- package/src/core/GeoCanvas.js +437 -430
- package/src/core/Layer.js +23 -23
- package/src/core/Legend.js +108 -108
- package/src/core/Map.js +542 -516
- package/src/core/MultiResolutionDataset.js +93 -93
- package/src/core/Style.js +98 -98
- package/src/core/Tooltip.js +182 -182
- package/src/dataset/COGeo.js +25 -25
- package/src/dataset/CSVGrid.js +112 -112
- package/src/dataset/GeoTIFF.js +122 -122
- package/src/dataset/JSGrid.js +55 -55
- package/src/dataset/TiledGrid.js +302 -302
- package/src/dataset/worker.js +18 -18
- package/src/index.js +77 -77
- package/src/layer/BackgroundLayer.js +173 -173
- package/src/layer/BackgroundLayerImage.js +81 -81
- package/src/layer/BackgroundLayerWMS.js +104 -104
- package/src/layer/GeoJSONLayer.js +214 -214
- package/src/layer/GridLayer.js +148 -148
- package/src/layer/LabelLayer.js +194 -194
- package/src/legend/ColorCategoryLegend.js +109 -109
- package/src/legend/ColorDiscreteLegend.js +100 -100
- package/src/legend/ColorLegend.js +115 -115
- package/src/legend/OrientationLegend.js +89 -89
- package/src/legend/SizeLegend.js +224 -224
- package/src/legend/TernaryLegend.js +302 -302
- package/src/style/CompositionStyle.js +291 -291
- package/src/style/ContourStyle.js +21 -21
- package/src/style/DotDensityStyle.js +133 -133
- package/src/style/ImageStyle.js +100 -100
- package/src/style/IsoFenceStyle.js +217 -217
- package/src/style/JoyPlotStyle.js +127 -127
- package/src/style/LegoStyle.js +110 -110
- package/src/style/MosaicStyle.js +99 -99
- package/src/style/NinjaStarStyle.js +102 -102
- package/src/style/PillarStyle.js +207 -207
- package/src/style/SegmentStyle.js +105 -105
- package/src/style/ShapeColorSizeStyle.js +147 -147
- package/src/style/SideCategoryStyle.js +112 -112
- package/src/style/SideStyle.js +212 -212
- package/src/style/SquareColorCategoryWebGLStyle.js +107 -107
- package/src/style/SquareColorWebGLStyle.js +126 -126
- package/src/style/StrokeStyle.js +135 -135
- package/src/style/TanakaStyle.js +69 -69
- package/src/style/TextStyle.js +110 -110
- package/src/style/TimeSeriesStyle.js +222 -222
- package/src/utils/WebGLRectangleColoring.js +106 -106
- package/src/utils/WebGLSquareColoring.js +118 -118
- package/src/utils/WebGLSquareColoringAdvanced.js +230 -230
- package/src/utils/WebGLSquareColoringCatAdvanced.js +133 -133
- package/src/utils/WebGLSquareColoringKS.js +153 -153
- package/src/utils/scale.js +218 -218
- package/src/utils/stretching.js +120 -120
- package/src/utils/ternary.js +208 -208
- package/src/utils/utils.js +58 -58
- package/src/utils/webGLUtils.js +72 -72
- package/src/utils/zoomUtils.js +142 -142
package/src/utils/scale.js
CHANGED
|
@@ -1,218 +1,218 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
import { extent, max } from 'd3-array'
|
|
5
|
-
import { scaleQuantile } from 'd3-scale'
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* A scale is simply a function that map a domain to a range.
|
|
9
|
-
* @typedef {function(number):number} Scale */
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* A scale whose range is a color (string).
|
|
13
|
-
* @typedef {function(number):string} ColorScale */
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @module utils
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Generic function for view scale - continuous or discrete
|
|
21
|
-
*
|
|
22
|
-
* @param {{ valueFunction:function(import("../core/Dataset").Cell):number, minValue?:number, minSizePix?:number, maxSizeFactor?:number, range?:[number, number], domain?:[number, number], stretching?:function(number):number, classNumber?:number}} opts
|
|
23
|
-
* @returns {function(Array.<import("../core/Dataset").Cell>):Scale}
|
|
24
|
-
*/
|
|
25
|
-
export const viewScale = (opts) => {
|
|
26
|
-
const valueFunction = opts.valueFunction
|
|
27
|
-
const minValue = opts.minValue || 0
|
|
28
|
-
const minSizePix = opts.minSizePix || 0
|
|
29
|
-
const maxSizeFactor = opts.maxSizeFactor || 1
|
|
30
|
-
const stretching = opts.stretching
|
|
31
|
-
const range_ = opts.range
|
|
32
|
-
const domain_ = opts.domain
|
|
33
|
-
const classNumber = opts.classNumber
|
|
34
|
-
return (cells, resolution, z) => {
|
|
35
|
-
const domain = domain_ || [minValue, max(cells, valueFunction)]
|
|
36
|
-
const range = range_ || [minSizePix * z, resolution * maxSizeFactor]
|
|
37
|
-
const domainSize = domain[1] - domain[0],
|
|
38
|
-
domainMin = domain[0]
|
|
39
|
-
const rangeSize = range[1] - range[0],
|
|
40
|
-
rangeMin = range[0]
|
|
41
|
-
return (t) => {
|
|
42
|
-
//scale to [0,1]
|
|
43
|
-
t = (t - domainMin) / domainSize
|
|
44
|
-
//stretch
|
|
45
|
-
if (stretching) t = stretching(t)
|
|
46
|
-
//classify
|
|
47
|
-
if (classNumber) t = t == 1 ? 1 : Math.floor(t * classNumber) / (classNumber - 1)
|
|
48
|
-
//scale to range
|
|
49
|
-
return rangeMin + t * rangeSize
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Generic function for view scale - quantile
|
|
56
|
-
*
|
|
57
|
-
* @param {{ valueFunction:function(import("../core/Dataset").Cell):number, classNumber?:number, minSizePix?:number, maxSizeFactor?:number }} opts
|
|
58
|
-
* @returns {function(Array.<import("../core/Dataset").Cell>):Scale}
|
|
59
|
-
*/
|
|
60
|
-
export const viewScaleQuantile = (opts) => {
|
|
61
|
-
const valueFunction = opts.valueFunction
|
|
62
|
-
const classNumber = opts.classNumber || 12
|
|
63
|
-
const minSizePix = opts.minSizePix || 1
|
|
64
|
-
const maxSizeFactor = opts.maxSizeFactor || 1
|
|
65
|
-
const scale = scaleQuantile()
|
|
66
|
-
return (cells, resolution, z) => {
|
|
67
|
-
scale.domain(cells.map(valueFunction))
|
|
68
|
-
const minSizeGeo = minSizePix * z,
|
|
69
|
-
maxSizeGeo = resolution * maxSizeFactor
|
|
70
|
-
scale.range(
|
|
71
|
-
Array.from(
|
|
72
|
-
{ length: classNumber },
|
|
73
|
-
(_, i) => minSizeGeo + (i * (maxSizeGeo - minSizeGeo)) / (classNumber - 1)
|
|
74
|
-
)
|
|
75
|
-
)
|
|
76
|
-
scale.breaks = scale.quantiles()
|
|
77
|
-
scale.values = scale.range()
|
|
78
|
-
return scale
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Generic function for color view scale - continuous or discrete
|
|
84
|
-
*
|
|
85
|
-
* @param {{ valueFunction:function(import("../core/Dataset").Cell):number, colorScale?:function(number):string, colors?:Array.<string>, stretching?:function(number):number }} opts
|
|
86
|
-
* @returns {function(Array.<import("../core/Dataset").Cell>):ColorScale}
|
|
87
|
-
*/
|
|
88
|
-
export const viewScaleColor = (opts) => {
|
|
89
|
-
const valueFunction = opts.valueFunction
|
|
90
|
-
const stretching = opts.stretching
|
|
91
|
-
let colorScale = opts.colorScale || (() => 'purple')
|
|
92
|
-
|
|
93
|
-
//discrete colors case: build continuous color scale from discrete ones.
|
|
94
|
-
const nbClass = opts.colors?.length
|
|
95
|
-
if (opts.colors && nbClass)
|
|
96
|
-
colorScale = (t) => opts.colors[t == 1 ? nbClass - 1 : Math.floor(t * nbClass)]
|
|
97
|
-
|
|
98
|
-
return (cells) => {
|
|
99
|
-
if (cells.length == 0 || !cells) return
|
|
100
|
-
/** @type {[undefined, undefined] | [number, number]} */
|
|
101
|
-
const domain = extent(cells, valueFunction)
|
|
102
|
-
if (domain[0] == undefined) return
|
|
103
|
-
const domainSize = domain[1] - domain[0]
|
|
104
|
-
const scale = (t) => {
|
|
105
|
-
//scale to [0,1]
|
|
106
|
-
t = (t - domain[0]) / domainSize
|
|
107
|
-
//stretch
|
|
108
|
-
if (stretching) t = stretching(t)
|
|
109
|
-
return colorScale(t)
|
|
110
|
-
}
|
|
111
|
-
//function that return the domain value from the [0,1] range.
|
|
112
|
-
scale.invert = (t) => {
|
|
113
|
-
if (stretching) t = stretching.invert(t)
|
|
114
|
-
return domain[0] + t * domainSize
|
|
115
|
-
}
|
|
116
|
-
//discrete colors: return the breaks
|
|
117
|
-
if (opts.colors && nbClass) {
|
|
118
|
-
scale.breaks = []
|
|
119
|
-
for (let i = 1; i < nbClass; i++) scale.breaks.push(scale.invert(i / nbClass))
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return scale
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Generic function for color view scale - quantile
|
|
128
|
-
*
|
|
129
|
-
* @param {{ valueFunction:function(import("../core/Dataset").Cell):number, classNumber?:number, colors?:Array.<string>, colorScale?:function(number):string }} opts
|
|
130
|
-
* @returns {function(Array.<import("../core/Dataset").Cell>):ColorScale}
|
|
131
|
-
*/
|
|
132
|
-
export const viewScaleColorQuantile = (opts) => {
|
|
133
|
-
const valueFunction = opts.valueFunction
|
|
134
|
-
const classNumber = opts.classNumber || 12
|
|
135
|
-
|
|
136
|
-
let colors = opts.colors
|
|
137
|
-
if (opts.colorScale) colors = discreteColors(opts.colorScale, classNumber)
|
|
138
|
-
colors =
|
|
139
|
-
colors ||
|
|
140
|
-
Array.from(
|
|
141
|
-
{ length: classNumber },
|
|
142
|
-
(_, i) => 'rgb(' + Math.floor((255 * i) / (classNumber - 1)) + ',150,150)'
|
|
143
|
-
)
|
|
144
|
-
|
|
145
|
-
const scale = scaleQuantile().range(colors)
|
|
146
|
-
return (cells) => {
|
|
147
|
-
scale.domain(cells.map(valueFunction))
|
|
148
|
-
scale.breaks = scale.quantiles()
|
|
149
|
-
scale.colors = colors
|
|
150
|
-
return scale
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Combine view scale functions
|
|
156
|
-
*
|
|
157
|
-
* @param {*} obj
|
|
158
|
-
* @returns {function}
|
|
159
|
-
*/
|
|
160
|
-
export const viewScaleCombination = (obj) => {
|
|
161
|
-
//obj: prop and a function to call
|
|
162
|
-
return (cells, resolution, z) => {
|
|
163
|
-
const out = {}
|
|
164
|
-
for (const p in obj) {
|
|
165
|
-
out[p] = obj[p](cells, resolution, z)
|
|
166
|
-
}
|
|
167
|
-
return out
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Return a classifier function from break values.
|
|
173
|
-
* The classifier function returns the class id (from 0 to breaks.length) from a value to classifiy.
|
|
174
|
-
* @param {Array.<number>} breaks the breaks
|
|
175
|
-
*/
|
|
176
|
-
export function classifier(breaks) {
|
|
177
|
-
const bl = breaks.length
|
|
178
|
-
const classifier = (value) => {
|
|
179
|
-
let i = 0
|
|
180
|
-
while (i < bl) {
|
|
181
|
-
const break_ = breaks[i]
|
|
182
|
-
if (value <= break_) return i
|
|
183
|
-
i++
|
|
184
|
-
}
|
|
185
|
-
return i
|
|
186
|
-
}
|
|
187
|
-
classifier.breaks = breaks
|
|
188
|
-
return classifier
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Return a color classifier function from break values.
|
|
193
|
-
* The classifier function returns the color from a value to classifiy.
|
|
194
|
-
* There should be one color more than break values.
|
|
195
|
-
* @param {Array.<number>} breaks the breaks
|
|
196
|
-
* @param {Array.<string>} colors the colors
|
|
197
|
-
*/
|
|
198
|
-
export function colorClassifier(breaks, colors) {
|
|
199
|
-
const classifier_ = classifier(breaks)
|
|
200
|
-
const colorClassifier = (value) => colors[classifier_(value)]
|
|
201
|
-
colorClassifier.breaks = breaks
|
|
202
|
-
colorClassifier.colors = colors
|
|
203
|
-
return colorClassifier
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Make array of colors from a colorScale.
|
|
208
|
-
* It is a kind of sampling, or un-interpolation
|
|
209
|
-
*
|
|
210
|
-
* @param {function(number):string} colorScale
|
|
211
|
-
* @param {number} nb
|
|
212
|
-
*/
|
|
213
|
-
export function discreteColors(colorScale, nb) {
|
|
214
|
-
if (nb == 1) return [colorScale(0.5)]
|
|
215
|
-
const out = []
|
|
216
|
-
for (let i = 0; i < nb; i++) out.push(colorScale(i / (nb - 1)))
|
|
217
|
-
return out
|
|
218
|
-
}
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
import { extent, max } from 'd3-array'
|
|
5
|
+
import { scaleQuantile } from 'd3-scale'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A scale is simply a function that map a domain to a range.
|
|
9
|
+
* @typedef {function(number):number} Scale */
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A scale whose range is a color (string).
|
|
13
|
+
* @typedef {function(number):string} ColorScale */
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @module utils
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Generic function for view scale - continuous or discrete
|
|
21
|
+
*
|
|
22
|
+
* @param {{ valueFunction:function(import("../core/Dataset").Cell):number, minValue?:number, minSizePix?:number, maxSizeFactor?:number, range?:[number, number], domain?:[number, number], stretching?:function(number):number, classNumber?:number}} opts
|
|
23
|
+
* @returns {function(Array.<import("../core/Dataset").Cell>):Scale}
|
|
24
|
+
*/
|
|
25
|
+
export const viewScale = (opts) => {
|
|
26
|
+
const valueFunction = opts.valueFunction
|
|
27
|
+
const minValue = opts.minValue || 0
|
|
28
|
+
const minSizePix = opts.minSizePix || 0
|
|
29
|
+
const maxSizeFactor = opts.maxSizeFactor || 1
|
|
30
|
+
const stretching = opts.stretching
|
|
31
|
+
const range_ = opts.range
|
|
32
|
+
const domain_ = opts.domain
|
|
33
|
+
const classNumber = opts.classNumber
|
|
34
|
+
return (cells, resolution, z) => {
|
|
35
|
+
const domain = domain_ || [minValue, max(cells, valueFunction)]
|
|
36
|
+
const range = range_ || [minSizePix * z, resolution * maxSizeFactor]
|
|
37
|
+
const domainSize = domain[1] - domain[0],
|
|
38
|
+
domainMin = domain[0]
|
|
39
|
+
const rangeSize = range[1] - range[0],
|
|
40
|
+
rangeMin = range[0]
|
|
41
|
+
return (t) => {
|
|
42
|
+
//scale to [0,1]
|
|
43
|
+
t = (t - domainMin) / domainSize
|
|
44
|
+
//stretch
|
|
45
|
+
if (stretching) t = stretching(t)
|
|
46
|
+
//classify
|
|
47
|
+
if (classNumber) t = t == 1 ? 1 : Math.floor(t * classNumber) / (classNumber - 1)
|
|
48
|
+
//scale to range
|
|
49
|
+
return rangeMin + t * rangeSize
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Generic function for view scale - quantile
|
|
56
|
+
*
|
|
57
|
+
* @param {{ valueFunction:function(import("../core/Dataset").Cell):number, classNumber?:number, minSizePix?:number, maxSizeFactor?:number }} opts
|
|
58
|
+
* @returns {function(Array.<import("../core/Dataset").Cell>):Scale}
|
|
59
|
+
*/
|
|
60
|
+
export const viewScaleQuantile = (opts) => {
|
|
61
|
+
const valueFunction = opts.valueFunction
|
|
62
|
+
const classNumber = opts.classNumber || 12
|
|
63
|
+
const minSizePix = opts.minSizePix || 1
|
|
64
|
+
const maxSizeFactor = opts.maxSizeFactor || 1
|
|
65
|
+
const scale = scaleQuantile()
|
|
66
|
+
return (cells, resolution, z) => {
|
|
67
|
+
scale.domain(cells.map(valueFunction))
|
|
68
|
+
const minSizeGeo = minSizePix * z,
|
|
69
|
+
maxSizeGeo = resolution * maxSizeFactor
|
|
70
|
+
scale.range(
|
|
71
|
+
Array.from(
|
|
72
|
+
{ length: classNumber },
|
|
73
|
+
(_, i) => minSizeGeo + (i * (maxSizeGeo - minSizeGeo)) / (classNumber - 1)
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
scale.breaks = scale.quantiles()
|
|
77
|
+
scale.values = scale.range()
|
|
78
|
+
return scale
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Generic function for color view scale - continuous or discrete
|
|
84
|
+
*
|
|
85
|
+
* @param {{ valueFunction:function(import("../core/Dataset").Cell):number, colorScale?:function(number):string, colors?:Array.<string>, stretching?:function(number):number }} opts
|
|
86
|
+
* @returns {function(Array.<import("../core/Dataset").Cell>):ColorScale}
|
|
87
|
+
*/
|
|
88
|
+
export const viewScaleColor = (opts) => {
|
|
89
|
+
const valueFunction = opts.valueFunction
|
|
90
|
+
const stretching = opts.stretching
|
|
91
|
+
let colorScale = opts.colorScale || (() => 'purple')
|
|
92
|
+
|
|
93
|
+
//discrete colors case: build continuous color scale from discrete ones.
|
|
94
|
+
const nbClass = opts.colors?.length
|
|
95
|
+
if (opts.colors && nbClass)
|
|
96
|
+
colorScale = (t) => opts.colors[t == 1 ? nbClass - 1 : Math.floor(t * nbClass)]
|
|
97
|
+
|
|
98
|
+
return (cells) => {
|
|
99
|
+
if (cells.length == 0 || !cells) return
|
|
100
|
+
/** @type {[undefined, undefined] | [number, number]} */
|
|
101
|
+
const domain = extent(cells, valueFunction)
|
|
102
|
+
if (domain[0] == undefined) return
|
|
103
|
+
const domainSize = domain[1] - domain[0]
|
|
104
|
+
const scale = (t) => {
|
|
105
|
+
//scale to [0,1]
|
|
106
|
+
t = (t - domain[0]) / domainSize
|
|
107
|
+
//stretch
|
|
108
|
+
if (stretching) t = stretching(t)
|
|
109
|
+
return colorScale(t)
|
|
110
|
+
}
|
|
111
|
+
//function that return the domain value from the [0,1] range.
|
|
112
|
+
scale.invert = (t) => {
|
|
113
|
+
if (stretching) t = stretching.invert(t)
|
|
114
|
+
return domain[0] + t * domainSize
|
|
115
|
+
}
|
|
116
|
+
//discrete colors: return the breaks
|
|
117
|
+
if (opts.colors && nbClass) {
|
|
118
|
+
scale.breaks = []
|
|
119
|
+
for (let i = 1; i < nbClass; i++) scale.breaks.push(scale.invert(i / nbClass))
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return scale
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Generic function for color view scale - quantile
|
|
128
|
+
*
|
|
129
|
+
* @param {{ valueFunction:function(import("../core/Dataset").Cell):number, classNumber?:number, colors?:Array.<string>, colorScale?:function(number):string }} opts
|
|
130
|
+
* @returns {function(Array.<import("../core/Dataset").Cell>):ColorScale}
|
|
131
|
+
*/
|
|
132
|
+
export const viewScaleColorQuantile = (opts) => {
|
|
133
|
+
const valueFunction = opts.valueFunction
|
|
134
|
+
const classNumber = opts.classNumber || 12
|
|
135
|
+
|
|
136
|
+
let colors = opts.colors
|
|
137
|
+
if (opts.colorScale) colors = discreteColors(opts.colorScale, classNumber)
|
|
138
|
+
colors =
|
|
139
|
+
colors ||
|
|
140
|
+
Array.from(
|
|
141
|
+
{ length: classNumber },
|
|
142
|
+
(_, i) => 'rgb(' + Math.floor((255 * i) / (classNumber - 1)) + ',150,150)'
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
const scale = scaleQuantile().range(colors)
|
|
146
|
+
return (cells) => {
|
|
147
|
+
scale.domain(cells.map(valueFunction))
|
|
148
|
+
scale.breaks = scale.quantiles()
|
|
149
|
+
scale.colors = colors
|
|
150
|
+
return scale
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Combine view scale functions
|
|
156
|
+
*
|
|
157
|
+
* @param {*} obj
|
|
158
|
+
* @returns {function}
|
|
159
|
+
*/
|
|
160
|
+
export const viewScaleCombination = (obj) => {
|
|
161
|
+
//obj: prop and a function to call
|
|
162
|
+
return (cells, resolution, z) => {
|
|
163
|
+
const out = {}
|
|
164
|
+
for (const p in obj) {
|
|
165
|
+
out[p] = obj[p](cells, resolution, z)
|
|
166
|
+
}
|
|
167
|
+
return out
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Return a classifier function from break values.
|
|
173
|
+
* The classifier function returns the class id (from 0 to breaks.length) from a value to classifiy.
|
|
174
|
+
* @param {Array.<number>} breaks the breaks
|
|
175
|
+
*/
|
|
176
|
+
export function classifier(breaks) {
|
|
177
|
+
const bl = breaks.length
|
|
178
|
+
const classifier = (value) => {
|
|
179
|
+
let i = 0
|
|
180
|
+
while (i < bl) {
|
|
181
|
+
const break_ = breaks[i]
|
|
182
|
+
if (value <= break_) return i
|
|
183
|
+
i++
|
|
184
|
+
}
|
|
185
|
+
return i
|
|
186
|
+
}
|
|
187
|
+
classifier.breaks = breaks
|
|
188
|
+
return classifier
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Return a color classifier function from break values.
|
|
193
|
+
* The classifier function returns the color from a value to classifiy.
|
|
194
|
+
* There should be one color more than break values.
|
|
195
|
+
* @param {Array.<number>} breaks the breaks
|
|
196
|
+
* @param {Array.<string>} colors the colors
|
|
197
|
+
*/
|
|
198
|
+
export function colorClassifier(breaks, colors) {
|
|
199
|
+
const classifier_ = classifier(breaks)
|
|
200
|
+
const colorClassifier = (value) => colors[classifier_(value)]
|
|
201
|
+
colorClassifier.breaks = breaks
|
|
202
|
+
colorClassifier.colors = colors
|
|
203
|
+
return colorClassifier
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Make array of colors from a colorScale.
|
|
208
|
+
* It is a kind of sampling, or un-interpolation
|
|
209
|
+
*
|
|
210
|
+
* @param {function(number):string} colorScale
|
|
211
|
+
* @param {number} nb
|
|
212
|
+
*/
|
|
213
|
+
export function discreteColors(colorScale, nb) {
|
|
214
|
+
if (nb == 1) return [colorScale(0.5)]
|
|
215
|
+
const out = []
|
|
216
|
+
for (let i = 0; i < nb; i++) out.push(colorScale(i / (nb - 1)))
|
|
217
|
+
return out
|
|
218
|
+
}
|
package/src/utils/stretching.js
CHANGED
|
@@ -1,120 +1,120 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @module utils
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
//TODO invert for circular
|
|
9
|
-
//TODO use Math.sqrt
|
|
10
|
-
//TODO validate
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Some function [0,1]->[0,1] to stretch range of values.
|
|
14
|
-
* @see https://github.com/eurostat/gridviz/blob/master/docs/reference.md#stretching
|
|
15
|
-
* @see https://observablehq.com/@jgaffuri/stretching
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
//identity function
|
|
19
|
-
const identity = (t) => t
|
|
20
|
-
identity.invert = identity
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* @param {number} base
|
|
24
|
-
* @returns {function(number):number}
|
|
25
|
-
*/
|
|
26
|
-
export const exponentialScale = (base = 3) => {
|
|
27
|
-
if (base == 0) return identity
|
|
28
|
-
const a = Math.exp(base) - 1
|
|
29
|
-
const f = (t) => (Math.exp(t * base) - 1) / a
|
|
30
|
-
f.invert = (t) => Math.log(a * t + 1) / base
|
|
31
|
-
return f
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* @param {number} base
|
|
36
|
-
* @returns {function(number):number}
|
|
37
|
-
*/
|
|
38
|
-
export const logarithmicScale = (base = 3) => {
|
|
39
|
-
if (base == 0) return identity
|
|
40
|
-
const a = Math.exp(base),
|
|
41
|
-
b = 1 - a
|
|
42
|
-
const f = (t) => 1 - Math.log(a + t * b) / base
|
|
43
|
-
f.invert = (t) => (Math.exp((1 - t) * base) - a) / b
|
|
44
|
-
return f
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* @param {number} exponent
|
|
49
|
-
* @returns {function(number):number}
|
|
50
|
-
*/
|
|
51
|
-
export const powerScale = (exponent = 3) => {
|
|
52
|
-
if (exponent == 1) return identity
|
|
53
|
-
//TODO if (exponent == 0.5) return Math.sqrt
|
|
54
|
-
const f = (t) => Math.pow(t, exponent)
|
|
55
|
-
const a = 1 / exponent
|
|
56
|
-
f.invert = (t) => Math.pow(t, a)
|
|
57
|
-
return f
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* @param {number} exponent
|
|
62
|
-
* @returns {function(number):number}
|
|
63
|
-
*/
|
|
64
|
-
export const powerInverseScale = (exponent = 3) => {
|
|
65
|
-
if (exponent == 1) return identity
|
|
66
|
-
//TODO if (exponent == 2) return t => 1 - Math.sqrt(1 - t)
|
|
67
|
-
const a = 1 / exponent
|
|
68
|
-
const f = (t) => 1 - Math.pow(1 - t, a)
|
|
69
|
-
f.invert = (t) => 1 - Math.pow(1 - t, exponent)
|
|
70
|
-
return f
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* @param {number} circularity
|
|
75
|
-
* @returns {function(number):number}
|
|
76
|
-
*/
|
|
77
|
-
export const circularScale = (circularity = 0.8) => {
|
|
78
|
-
if (circularity == 0) return identity
|
|
79
|
-
if (circularity == 1) return (t) => Math.sqrt(t * (2 - t))
|
|
80
|
-
else {
|
|
81
|
-
const a = circularity / (1 - circularity)
|
|
82
|
-
return (t) => Math.sqrt(1 / (a * a) + t * (2 / a + 2 - t)) - 1 / a
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* @param {number} circularity
|
|
88
|
-
* @returns {function(number):number}
|
|
89
|
-
*/
|
|
90
|
-
export const circularInverseScale = (circularity = 0.8) => {
|
|
91
|
-
if (circularity == 0) return identity
|
|
92
|
-
const f = circularScale(circularity)
|
|
93
|
-
return (t) => 1 - f(1 - t)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
//test
|
|
97
|
-
/*
|
|
98
|
-
const test = (f, fun, a, err = 1e-12) => {
|
|
99
|
-
for (let t = 0; t <= 1; t += 1 / 50) {
|
|
100
|
-
const er = t - f.invert(f(t))
|
|
101
|
-
if (Math.abs(er) < err) continue
|
|
102
|
-
console.log(fun, a, er)
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
for (let fun of [powerScale, powerInverseScale])
|
|
107
|
-
for (let exp = -30; exp <= 50; exp += 1) {
|
|
108
|
-
if (exp == 0) continue
|
|
109
|
-
const f = fun(exp)
|
|
110
|
-
test(f, fun, exp)
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
for (let fun of [exponentialScale, logarithmicScale])
|
|
115
|
-
for (let base = -20; base <= 20; base += 1) {
|
|
116
|
-
//if (exp == 0) continue
|
|
117
|
-
const f = fun(base)
|
|
118
|
-
test(f, fun, base, 1e-10)
|
|
119
|
-
}
|
|
120
|
-
*/
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @module utils
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
//TODO invert for circular
|
|
9
|
+
//TODO use Math.sqrt
|
|
10
|
+
//TODO validate
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Some function [0,1]->[0,1] to stretch range of values.
|
|
14
|
+
* @see https://github.com/eurostat/gridviz/blob/master/docs/reference.md#stretching
|
|
15
|
+
* @see https://observablehq.com/@jgaffuri/stretching
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
//identity function
|
|
19
|
+
const identity = (t) => t
|
|
20
|
+
identity.invert = identity
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {number} base
|
|
24
|
+
* @returns {function(number):number}
|
|
25
|
+
*/
|
|
26
|
+
export const exponentialScale = (base = 3) => {
|
|
27
|
+
if (base == 0) return identity
|
|
28
|
+
const a = Math.exp(base) - 1
|
|
29
|
+
const f = (t) => (Math.exp(t * base) - 1) / a
|
|
30
|
+
f.invert = (t) => Math.log(a * t + 1) / base
|
|
31
|
+
return f
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {number} base
|
|
36
|
+
* @returns {function(number):number}
|
|
37
|
+
*/
|
|
38
|
+
export const logarithmicScale = (base = 3) => {
|
|
39
|
+
if (base == 0) return identity
|
|
40
|
+
const a = Math.exp(base),
|
|
41
|
+
b = 1 - a
|
|
42
|
+
const f = (t) => 1 - Math.log(a + t * b) / base
|
|
43
|
+
f.invert = (t) => (Math.exp((1 - t) * base) - a) / b
|
|
44
|
+
return f
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @param {number} exponent
|
|
49
|
+
* @returns {function(number):number}
|
|
50
|
+
*/
|
|
51
|
+
export const powerScale = (exponent = 3) => {
|
|
52
|
+
if (exponent == 1) return identity
|
|
53
|
+
//TODO if (exponent == 0.5) return Math.sqrt
|
|
54
|
+
const f = (t) => Math.pow(t, exponent)
|
|
55
|
+
const a = 1 / exponent
|
|
56
|
+
f.invert = (t) => Math.pow(t, a)
|
|
57
|
+
return f
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @param {number} exponent
|
|
62
|
+
* @returns {function(number):number}
|
|
63
|
+
*/
|
|
64
|
+
export const powerInverseScale = (exponent = 3) => {
|
|
65
|
+
if (exponent == 1) return identity
|
|
66
|
+
//TODO if (exponent == 2) return t => 1 - Math.sqrt(1 - t)
|
|
67
|
+
const a = 1 / exponent
|
|
68
|
+
const f = (t) => 1 - Math.pow(1 - t, a)
|
|
69
|
+
f.invert = (t) => 1 - Math.pow(1 - t, exponent)
|
|
70
|
+
return f
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @param {number} circularity
|
|
75
|
+
* @returns {function(number):number}
|
|
76
|
+
*/
|
|
77
|
+
export const circularScale = (circularity = 0.8) => {
|
|
78
|
+
if (circularity == 0) return identity
|
|
79
|
+
if (circularity == 1) return (t) => Math.sqrt(t * (2 - t))
|
|
80
|
+
else {
|
|
81
|
+
const a = circularity / (1 - circularity)
|
|
82
|
+
return (t) => Math.sqrt(1 / (a * a) + t * (2 / a + 2 - t)) - 1 / a
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @param {number} circularity
|
|
88
|
+
* @returns {function(number):number}
|
|
89
|
+
*/
|
|
90
|
+
export const circularInverseScale = (circularity = 0.8) => {
|
|
91
|
+
if (circularity == 0) return identity
|
|
92
|
+
const f = circularScale(circularity)
|
|
93
|
+
return (t) => 1 - f(1 - t)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
//test
|
|
97
|
+
/*
|
|
98
|
+
const test = (f, fun, a, err = 1e-12) => {
|
|
99
|
+
for (let t = 0; t <= 1; t += 1 / 50) {
|
|
100
|
+
const er = t - f.invert(f(t))
|
|
101
|
+
if (Math.abs(er) < err) continue
|
|
102
|
+
console.log(fun, a, er)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
for (let fun of [powerScale, powerInverseScale])
|
|
107
|
+
for (let exp = -30; exp <= 50; exp += 1) {
|
|
108
|
+
if (exp == 0) continue
|
|
109
|
+
const f = fun(exp)
|
|
110
|
+
test(f, fun, exp)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
for (let fun of [exponentialScale, logarithmicScale])
|
|
115
|
+
for (let base = -20; base <= 20; base += 1) {
|
|
116
|
+
//if (exp == 0) continue
|
|
117
|
+
const f = fun(base)
|
|
118
|
+
test(f, fun, base, 1e-10)
|
|
119
|
+
}
|
|
120
|
+
*/
|