gridviz 2.1.16 → 3.0.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 (67) hide show
  1. package/README.md +2 -3
  2. package/dist/gridviz.js +4971 -5654
  3. package/dist/gridviz.min.js +1 -1
  4. package/package.json +3 -2
  5. package/src/button/Button.js +14 -15
  6. package/src/button/FullscreenButton.js +14 -14
  7. package/src/button/ZoomButtons.js +2 -2
  8. package/src/{DatasetComponent.js → core/Dataset.js} +33 -12
  9. package/src/core/Drawable.js +60 -0
  10. package/src/{GeoCanvas.js → core/GeoCanvas.js} +65 -155
  11. package/src/core/Layer.js +24 -0
  12. package/src/{Legend.js → core/Legend.js} +24 -1
  13. package/src/core/Map.js +460 -0
  14. package/src/core/MultiResolutionDataset.js +96 -0
  15. package/src/core/Style.js +84 -0
  16. package/src/dataset/COGeo.js +5 -5
  17. package/src/dataset/CSVGrid.js +43 -41
  18. package/src/dataset/GeoTIFF.js +9 -14
  19. package/src/dataset/{LGrid.js → JSGrid.js} +9 -10
  20. package/src/dataset/TiledGrid.js +68 -45
  21. package/src/index.js +22 -29
  22. package/src/{BackgroundLayer.js → layer/BackgroundLayer.js} +27 -52
  23. package/src/{BackgroundLayerWMS.js → layer/BackgroundLayerWMS.js} +21 -45
  24. package/src/{LineLayer.js → layer/GeoJSONLayer.js} +22 -23
  25. package/src/layer/GridLayer.js +140 -0
  26. package/src/{LabelLayer.js → layer/LabelLayer.js} +25 -23
  27. package/src/legend/ColorCategoryLegend.js +9 -24
  28. package/src/legend/ColorDiscreteLegend.js +20 -24
  29. package/src/legend/ColorLegend.js +21 -33
  30. package/src/legend/OrientationLegend.js +90 -0
  31. package/src/legend/SizeLegend.js +153 -72
  32. package/src/style/CompositionStyle.js +71 -84
  33. package/src/style/ContourStyle.js +2 -36
  34. package/src/style/DotDensityStyle.js +50 -73
  35. package/src/style/IsoFenceStyle.js +59 -70
  36. package/src/style/JoyPlotStyle.js +41 -48
  37. package/src/style/LegoStyle.js +4 -4
  38. package/src/style/MosaicStyle.js +30 -39
  39. package/src/style/NinjaStarStyle.js +45 -68
  40. package/src/style/PillarStyle.js +70 -93
  41. package/src/style/SegmentStyle.js +37 -75
  42. package/src/style/ShapeColorSizeStyle.js +49 -98
  43. package/src/style/SideCategoryStyle.js +112 -0
  44. package/src/style/SideStyle.js +99 -133
  45. package/src/style/{SquareColorCatWGLStyle.js → SquareColorCategoryWebGLStyle.js} +28 -41
  46. package/src/style/{SquareColorWGLStyle.js → SquareColorWebGLStyle.js} +28 -49
  47. package/src/style/StrokeStyle.js +43 -70
  48. package/src/style/TanakaStyle.js +34 -132
  49. package/src/style/TextStyle.js +43 -64
  50. package/src/style/TimeSeriesStyle.js +44 -75
  51. package/src/utils/WebGLSquareColoringAdvanced.js +4 -4
  52. package/src/utils/scale.js +202 -0
  53. package/src/utils/stretching.js +86 -129
  54. package/src/utils/{Utils.js → utils.js} +15 -0
  55. package/src/utils/webGLUtils.js +4 -5
  56. package/src/utils/zoomUtils.js +30 -30
  57. package/src/App.js +0 -760
  58. package/src/Dataset.js +0 -76
  59. package/src/Layer.js +0 -103
  60. package/src/Style.js +0 -131
  61. package/src/dataset/GridTile.js +0 -41
  62. package/src/legend/SegmentOrientationLegend.js +0 -87
  63. package/src/legend/SegmentWidthLegend.js +0 -101
  64. package/src/style/CompositionStyle_.js +0 -293
  65. package/src/style/ShapeColorSizeStyle_.js +0 -108
  66. package/src/style/SideCatStyle.js +0 -172
  67. /package/src/{Tooltip.js → core/Tooltip.js} +0 -0
@@ -1,7 +1,7 @@
1
1
  //@ts-check
2
2
  'use strict'
3
3
 
4
- import { Style } from '../Style.js'
4
+ import { Style } from '../core/Style.js'
5
5
 
6
6
  /** @typedef {"first"|"bottom"|"center"|"top"|"last"} AnchorModeYEnum */
7
7
 
@@ -27,65 +27,46 @@ export class TimeSeriesStyle extends Style {
27
27
 
28
28
  //x
29
29
  /** in geo unit
30
- * @type {function(import("../Dataset.js").Cell,number,number):number} */
31
- this.offsetX = opts.offsetX || ((c, r, zf) => 0)
32
- /** @type {function(import("../Dataset.js").Cell,number,number):number} */
33
- this.width = opts.width || ((c, r, zf) => r)
30
+ * @type {function(import("../core/Dataset.js").Cell,number,number):number} */
31
+ this.offsetX = opts.offsetX || ((c, r, z) => 0)
32
+ /** @type {function(import("../core/Dataset.js").Cell,number,number):number} */
33
+ this.width = opts.width || ((c, r, z) => r)
34
34
 
35
35
  //y
36
36
  /** in geo unit
37
- * @type {function(import("../Dataset.js").Cell,number,number):number} */
38
- this.offsetY = opts.offsetY || ((c, r, zf) => 0)
39
- /** @type {function(import("../Dataset.js").Cell,number,number):number} */
40
- this.height = opts.height || ((c, r, zf) => r)
41
- /** @type {function(import("../Dataset.js").Cell,number,number):AnchorModeYEnum} */
42
- this.anchorModeY = opts.anchorModeY || ((c, r, zf) => "center")
43
-
44
-
45
- /**
46
- * @type {string} */
47
- this.lineWidthCol = opts.lineWidthCol
37
+ * @type {function(import("../core/Dataset.js").Cell,number,number):number} */
38
+ this.offsetY = opts.offsetY || ((c, r, z) => 0)
39
+ /** @type {function(import("../core/Dataset.js").Cell,number,number):number} */
40
+ this.height = opts.height || ((c, r, z) => r)
41
+ /** @type {function(import("../core/Dataset.js").Cell,number,number):AnchorModeYEnum} */
42
+ this.anchorModeY = opts.anchorModeY || ((c, r, z) => "center")
48
43
 
49
44
  /** A function returning the width of the line, in geo unit
50
- * @type {function(number,number,import("../Style.js").Stat|undefined,number):number} */
51
- this.lineWidth = opts.lineWidth || ((v, r, s, zf) => 1.5 * zf)
52
-
53
- /**
54
- * @type {string} */
55
- this.colorCol = opts.colorCol
56
-
57
- /** A function returning the color of the cell.
58
- * @type {function(number,number,import("../Style.js").Stat|undefined,number):string} */
59
- this.color = opts.color || ((v, r, s, zf) => 'black')
45
+ * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
46
+ this.lineWidth = opts.lineWidth || ((v, r, s, z) => 1.5 * z)
60
47
 
48
+ /** A function returning the color of the chart.
49
+ * @type {function(import('../core/Dataset.js').Cell, number, number, object):string} */
50
+ this.color = opts.color || (() => "black") //(c,r,z,vs) => {}
61
51
  }
62
52
 
63
53
  /**
64
54
  * Draw cells as text.
65
55
  *
66
- * @param {Array.<import("../Dataset.js").Cell>} cells
67
- * @param {number} r
68
- * @param {import("../GeoCanvas.js").GeoCanvas} cg
56
+ * @param {Array.<import("../core/Dataset.js").Cell>} cells
57
+ * @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
58
+ * @param {number} resolution
69
59
  */
70
- draw(cells, r, cg) {
60
+ draw(cells, geoCanvas, resolution) {
71
61
 
72
62
  //filter
73
63
  if (this.filter) cells = cells.filter(this.filter)
74
64
 
75
- //zoom factor
76
- const zf = cg.getZf()
65
+ //
66
+ const z = geoCanvas.view.z
77
67
 
78
- let statWidth
79
- if (this.lineWidthCol) {
80
- //and compute size variable statistics
81
- statWidth = Style.getStatistics(cells, (c) => c[this.lineWidthCol], true)
82
- }
83
-
84
- let statColor
85
- if (this.colorCol) {
86
- //compute color variable statistics
87
- statColor = Style.getStatistics(cells, (c) => c[this.colorCol], true)
88
- }
68
+ //get view scale
69
+ const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
89
70
 
90
71
  //compute cell amplitude
91
72
  const getAmplitude = c => {
@@ -111,40 +92,36 @@ export class TimeSeriesStyle extends Style {
111
92
 
112
93
  const nb = this.ts.length
113
94
 
114
- //draw with HTML canvas
115
- //in geo coordinates
116
- cg.setCanvasTransform()
117
-
118
- cg.ctx.lineCap = "butt"
95
+ geoCanvas.ctx.lineCap = "butt"
119
96
  for (let c of cells) {
120
97
 
121
98
  //line width
122
99
  /** @type {number|undefined} */
123
- const wG = this.lineWidth ? this.lineWidth(c[this.lineWidthCol], r, statWidth, zf) : undefined
100
+ const wG = this.lineWidth ? this.lineWidth(c, resolution, z, viewScale) : undefined
124
101
  if (!wG || wG < 0) continue
125
102
 
126
103
  //line color
127
104
  /** @type {string|undefined} */
128
- const col = this.color ? this.color(c[this.colorCol], r, statColor, zf) : undefined
105
+ const col = this.color ? this.color(c, resolution, z, viewScale) : undefined
129
106
  if (!col) continue
130
107
 
131
108
 
132
109
  //x
133
- const offX = this.offsetX ? this.offsetX(c, r, zf) : 0
110
+ const offX = this.offsetX ? this.offsetX(c, resolution, z) : 0
134
111
  if (offX == undefined || isNaN(offX)) continue
135
- const w = this.width ? this.width(c, r, zf) : r
112
+ const w = this.width ? this.width(c, resolution, z) : resolution
136
113
  if (w == undefined || isNaN(w)) continue
137
114
 
138
115
  //y
139
- const offY = this.offsetY ? this.offsetY(c, r, zf) : 0
116
+ const offY = this.offsetY ? this.offsetY(c, resolution, z) : 0
140
117
  if (offY == undefined || isNaN(offY)) continue
141
- const h = this.height ? this.height(c, r, zf) : r
118
+ const h = this.height ? this.height(c, resolution, z) : resolution
142
119
  if (h == undefined || isNaN(h)) continue
143
- const anchY = this.anchorModeY ? this.anchorModeY(c, r, zf) : "center"
120
+ const anchY = this.anchorModeY ? this.anchorModeY(c, resolution, z) : "center"
144
121
  if (!anchY) continue
145
122
 
146
- cg.ctx.lineWidth = wG
147
- cg.ctx.strokeStyle = col
123
+ geoCanvas.ctx.lineWidth = wG
124
+ geoCanvas.ctx.strokeStyle = col
148
125
 
149
126
  //compute anchor Y figures
150
127
  let val0, y0
@@ -171,7 +148,7 @@ export class TimeSeriesStyle extends Style {
171
148
  if (val == undefined) continue
172
149
  if (val0 == undefined || val > val0) val0 = val
173
150
  }
174
- y0 = r
151
+ y0 = resolution
175
152
  } else if (anchY === "center") {
176
153
  //get min and max
177
154
  let min, max
@@ -182,7 +159,7 @@ export class TimeSeriesStyle extends Style {
182
159
  if (max == undefined || val > max) max = val
183
160
  }
184
161
  val0 = (+max + +min) * 0.5
185
- y0 = r / 2
162
+ y0 = resolution / 2
186
163
  } else {
187
164
  console.log("Unexpected anchorModeY: " + anchY)
188
165
  continue;
@@ -209,8 +186,8 @@ export class TimeSeriesStyle extends Style {
209
186
  //handle first point
210
187
  let v0 = c[this.ts[0]]
211
188
  if (!this.noData(v0)) {
212
- cg.ctx.beginPath()
213
- cg.ctx.moveTo(c.x + offX, c.y + y0 + (v0 - val0) * h / ampMax + offY)
189
+ geoCanvas.ctx.beginPath()
190
+ geoCanvas.ctx.moveTo(c.x + offX, c.y + y0 + (v0 - val0) * h / ampMax + offY)
214
191
  }
215
192
  //console.log(v0, isNaN(v0))
216
193
 
@@ -225,18 +202,18 @@ export class TimeSeriesStyle extends Style {
225
202
 
226
203
  //second point 'no data'
227
204
  } else if (!this.noData(v0) && this.noData(v1)) {
228
- cg.ctx.stroke()
205
+ geoCanvas.ctx.stroke()
229
206
 
230
207
  //first point 'no data'
231
208
  } else if (this.noData(v0) && !this.noData(v1)) {
232
- cg.ctx.beginPath()
233
- cg.ctx.moveTo(c.x + i * sX + offX, c.y + y0 + (v1 - val0) * h / ampMax + offY)
209
+ geoCanvas.ctx.beginPath()
210
+ geoCanvas.ctx.moveTo(c.x + i * sX + offX, c.y + y0 + (v1 - val0) * h / ampMax + offY)
234
211
 
235
212
  //both points have data: trace line
236
213
  } else {
237
- cg.ctx.lineTo(c.x + i * sX + offX, c.y + y0 + (v1 - val0) * h / ampMax + offY)
214
+ geoCanvas.ctx.lineTo(c.x + i * sX + offX, c.y + y0 + (v1 - val0) * h / ampMax + offY)
238
215
  //if it is the last point, stroke
239
- if (i == nb - 1) cg.ctx.stroke()
216
+ if (i == nb - 1) geoCanvas.ctx.stroke()
240
217
  }
241
218
  v0 = v1
242
219
  }
@@ -244,15 +221,7 @@ export class TimeSeriesStyle extends Style {
244
221
  }
245
222
 
246
223
  //update legend, if any
247
- this.updateLegends({
248
- widthFun: this.lineWidth,
249
- r: r,
250
- zf: zf,
251
- sColor: statColor,
252
- //sLength: statLength,
253
- sWidth: statWidth,
254
- })
255
-
224
+ this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
256
225
  }
257
226
 
258
227
  }
@@ -70,7 +70,7 @@ export class WebGLSquareColoringAdvanced {
70
70
  if (stretching.fun == 'pow')
71
71
  //sPow = (t, alpha = 3) => Math.pow(t, alpha);
72
72
  fshString += ' float t = pow(vt, alpha);\n'
73
- else if (stretching.fun == 'powRev')
73
+ else if (stretching.fun == 'powInv')
74
74
  //sPowRev = (t, alpha = 3) => 1 - Math.pow(1 - t, 1 / alpha);
75
75
  fshString += ' float t = 1.0-pow(1.0-vt, 1.0/alpha);\n'
76
76
  else if (stretching.fun == 'exp')
@@ -79,13 +79,13 @@ export class WebGLSquareColoringAdvanced {
79
79
  stretching.alpha == 0
80
80
  ? `float t = vt;`
81
81
  : ' float t = (exp(vt * alpha) - 1.0) / (exp(alpha) - 1.0);\n'
82
- else if (stretching.fun == 'expRev')
82
+ else if (stretching.fun == 'log')
83
83
  //sExpRev = (t, alpha = 3) => alpha == 0 ? t : 1 - (1 / alpha) * Math.log(Math.exp(alpha) * (1 - t) + t);
84
84
  fshString +=
85
85
  stretching.alpha == 0
86
86
  ? `float t = vt;`
87
87
  : ' float t = 1.0 - (1.0 / alpha) * log(exp(alpha) * (1.0 - vt) + vt);\n'
88
- else if (stretching.fun == 'circleLow') {
88
+ else if (stretching.fun == 'circle') {
89
89
  if (stretching.alpha == 0)
90
90
  //if (alpha == 0) return t;
91
91
  fshString += ' float t = vt;\n'
@@ -99,7 +99,7 @@ export class WebGLSquareColoringAdvanced {
99
99
  ' float a = alpha / (1.0 - alpha);\n' +
100
100
  ' float t = sqrt(1.0 / (a * a) + vt * ( 2.0/a + 2.0 - vt )) - 1.0 / a;\n'
101
101
  }
102
- } else if (stretching.fun == 'circleHigh') {
102
+ } else if (stretching.fun == 'circleInv') {
103
103
  // 1 - sCircleLow(1 - t, alpha)
104
104
  if (stretching.alpha == 0)
105
105
  //if (alpha == 0) return t;
@@ -0,0 +1,202 @@
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
+
17
+ /**
18
+ * Generic function for view scale - continuous
19
+ *
20
+ * @param {{ valueFunction:function(import("../core/Dataset").Cell):number, minValue?:number, minSizePix?:number, maxSizeFactor?:number, range?:[number, number], domain?:[number, number], stretching?:function(number):number }} opts
21
+ * @returns {function(Array.<import("../core/Dataset").Cell>):Scale}
22
+ */
23
+ export const viewScale = (opts) => {
24
+ const valueFunction = opts.valueFunction
25
+ const minValue = opts.minValue || 0
26
+ const minSizePix = opts.minSizePix || 0
27
+ const maxSizeFactor = opts.maxSizeFactor || 1
28
+ const stretching = opts.stretching
29
+ const range_ = opts.range
30
+ const domain_ = opts.domain
31
+ return (cells, r, z) => {
32
+ const domain = domain_ || [minValue, max(cells, valueFunction)]
33
+ const range = range_ || [minSizePix * z, r * maxSizeFactor]
34
+ return t => {
35
+ //scale to [0,1]
36
+ t = (t - domain[0]) / (domain[1] - domain[0])
37
+ //stretch
38
+ if (stretching) t = stretching(t)
39
+ //scale to range
40
+ return range[0] + t * (range[1] - range[0])
41
+ }
42
+ }
43
+ }
44
+
45
+
46
+ /**
47
+ * Generic function for view scale - quantile
48
+ *
49
+ * @param {{ valueFunction:function(import("../core/Dataset").Cell):number, classNumber?:number, minSizePix?:number, maxSizeFactor?:number }} opts
50
+ * @returns {function(Array.<import("../core/Dataset").Cell>):Scale}
51
+ */
52
+ export const viewScaleQuantile = (opts) => {
53
+ const valueFunction = opts.valueFunction
54
+ const classNumber = opts.classNumber || 12
55
+ const minSizePix = opts.minSizePix || 1
56
+ const maxSizeFactor = opts.maxSizeFactor || 1
57
+ const scale = scaleQuantile()
58
+ return (cells, r, z) => {
59
+ scale.domain(cells.map(valueFunction))
60
+ const minSizeGeo = minSizePix * z, maxSizeGeo = r * maxSizeFactor
61
+ scale.range(Array.from({ length: classNumber }, (_, i) => minSizeGeo + i * (maxSizeGeo - minSizeGeo) / (classNumber - 1)))
62
+ scale.breaks = scale.quantiles()
63
+ scale.values = scale.range()
64
+ return scale;
65
+ }
66
+ }
67
+
68
+
69
+
70
+
71
+
72
+
73
+ /**
74
+ * Generic function for color view scale - continuous
75
+ *
76
+ * @param {{ valueFunction:function(import("../core/Dataset").Cell):number, colorScale?:function(number):string, stretching?:function(number):number }} opts
77
+ * @returns {function(Array.<import("../core/Dataset").Cell>):ColorScale}
78
+ */
79
+ export const viewScaleColor = (opts) => {
80
+ const valueFunction = opts.valueFunction
81
+ const colorScale = opts.colorScale || (() => "purple")
82
+ const stretching = opts.stretching
83
+ return (cells) => {
84
+ if (cells.length == 0 || !cells) return
85
+ /** @type {[undefined, undefined] | [number, number]} */
86
+ const domain = extent(cells, valueFunction)
87
+ if (domain[0] == undefined) return
88
+ const amplitude = domain[1] - domain[0]
89
+ const scale = t => {
90
+ //scale to [0,1]
91
+ t = (t - domain[0]) / amplitude
92
+ //stretch
93
+ if (stretching) t = stretching(t)
94
+ return colorScale(t)
95
+ }
96
+ //function that return the domain value from the [0,1] range.
97
+ scale.invert = t => {
98
+ if (stretching) t = stretching.invert(t)
99
+ return domain[0] + t * amplitude
100
+ }
101
+
102
+ return scale;
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Generic function for color view scale - quantile
108
+ *
109
+ * @param {{ valueFunction:function(import("../core/Dataset").Cell):number, classNumber?:number, colors?:Array.<string>, colorScale?:function(number):string }} opts
110
+ * @returns {function(Array.<import("../core/Dataset").Cell>):ColorScale}
111
+ */
112
+ export const viewScaleColorQuantile = (opts) => {
113
+ const valueFunction = opts.valueFunction
114
+ const classNumber = opts.classNumber || 12
115
+
116
+ let colors = opts.colors
117
+ if (opts.colorScale) colors = discreteColors(opts.colorScale, classNumber)
118
+ colors = colors || Array.from({ length: classNumber }, (_, i) => "rgb(" + Math.floor(255 * i / (classNumber - 1)) + ",150,150)")
119
+
120
+ const scale = scaleQuantile().range(colors)
121
+ return (cells) => {
122
+ scale.domain(cells.map(valueFunction));
123
+ scale.breaks = scale.quantiles()
124
+ scale.colors = colors
125
+ return scale;
126
+ }
127
+ }
128
+
129
+
130
+
131
+
132
+ /**
133
+ * combine view scale functions
134
+ *
135
+ * @param {*} obj
136
+ * @returns
137
+ */
138
+ export const viewScaleCombination = (obj) => {
139
+ //obj: prop and a function to call
140
+ return (cells, r, z) => {
141
+ const out = {}
142
+ for (const p in obj) { out[p] = obj[p](cells, r, z) }
143
+ return out
144
+ }
145
+ }
146
+
147
+
148
+
149
+
150
+
151
+
152
+ /**
153
+ * Return a classifier function from break values.
154
+ * The classifier function returns the class id (from 0 to breaks.length) from a value to classifiy.
155
+ * @param {Array.<number>} breaks the breaks
156
+ */
157
+ export function classifier(breaks) {
158
+ const bl = breaks.length
159
+ const classifier = value => {
160
+ let i = 0
161
+ while (i < bl) {
162
+ const break_ = breaks[i]
163
+ if (value <= break_) return i
164
+ i++
165
+ }
166
+ return i
167
+ }
168
+ classifier.breaks = breaks
169
+ return classifier
170
+ }
171
+
172
+
173
+
174
+ /**
175
+ * Return a color classifier function from break values.
176
+ * The classifier function returns the color from a value to classifiy.
177
+ * There should be one color more than break values.
178
+ * @param {Array.<number>} breaks the breaks
179
+ * @param {Array.<string>} colors the colors
180
+ */
181
+ export function colorClassifier(breaks, colors) {
182
+ const classifier_ = classifier(breaks)
183
+ const colorClassifier = value => colors[classifier_(value)]
184
+ colorClassifier.breaks = breaks
185
+ colorClassifier.colors = colors
186
+ return colorClassifier
187
+ }
188
+
189
+ /**
190
+ * Make array of colors from a colorScale.
191
+ * It is a kind of sampling, or un-interpolation
192
+ *
193
+ * @param {function(number):string} colorScale
194
+ * @param {number} nb
195
+ */
196
+ export function discreteColors(colorScale, nb) {
197
+ if (nb == 1) return [colorScale(0.5)]
198
+ const out = []
199
+ for (let i = 0; i < nb; i++)
200
+ out.push(colorScale(i / (nb - 1)))
201
+ return out
202
+ }