gridviz 2.0.37 → 2.0.39

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 (58) hide show
  1. package/README.md +119 -119
  2. package/dist/gridviz.js +33256 -33296
  3. package/dist/gridviz.min.js +1 -1
  4. package/package.json +78 -78
  5. package/src/App.js +698 -698
  6. package/src/BackgroundLayer.js +182 -182
  7. package/src/BackgroundLayerWMS.js +131 -131
  8. package/src/Dataset.js +76 -76
  9. package/src/DatasetComponent.js +103 -103
  10. package/src/GeoCanvas.js +419 -419
  11. package/src/LabelLayer.js +190 -190
  12. package/src/Layer.js +92 -92
  13. package/src/Legend.js +86 -86
  14. package/src/LineLayer.js +150 -150
  15. package/src/Style.js +114 -114
  16. package/src/Tooltip.js +168 -166
  17. package/src/dataset/COGeo.js +24 -24
  18. package/src/dataset/CSVGrid.js +104 -104
  19. package/src/dataset/GeoTIFF.js +127 -127
  20. package/src/dataset/GridTile.js +41 -41
  21. package/src/dataset/ParquetGrid.js +122 -122
  22. package/src/dataset/TiledGrid.js +296 -296
  23. package/src/index.js +177 -177
  24. package/src/legend/ColorCategoryLegend.js +124 -124
  25. package/src/legend/ColorDiscreteLegend.js +105 -105
  26. package/src/legend/ColorLegend.js +125 -125
  27. package/src/legend/SegmentOrientationLegend.js +87 -87
  28. package/src/legend/SegmentWidthLegend.js +97 -97
  29. package/src/legend/SizeLegend.js +141 -141
  30. package/src/style/CompositionStyle.js +300 -300
  31. package/src/style/ContourStyle.js +54 -54
  32. package/src/style/DotDensityStyle.js +156 -156
  33. package/src/style/JoyPlotStyle.js +135 -135
  34. package/src/style/KernelSmoothingOldStyle.js +221 -221
  35. package/src/style/KernelSmoothingStyle.js +115 -115
  36. package/src/style/KernelSmoothingWGLStyle.js +130 -130
  37. package/src/style/LegoStyle.js +112 -112
  38. package/src/style/MosaicStyle.js +107 -107
  39. package/src/style/NinjaStarStyle.js +124 -124
  40. package/src/style/PillarStyle.js +230 -230
  41. package/src/style/SegmentStyle.js +142 -142
  42. package/src/style/ShapeColorSizeStyle.js +126 -126
  43. package/src/style/SideCatStyle.js +172 -172
  44. package/src/style/SideStyle.js +218 -218
  45. package/src/style/SquareColorCatWGLStyle.js +120 -120
  46. package/src/style/SquareColorWGLStyle.js +146 -146
  47. package/src/style/StrokeStyle.js +131 -131
  48. package/src/style/TanakaStyle.js +160 -160
  49. package/src/style/TextStyle.js +132 -132
  50. package/src/utils/Utils.js +35 -35
  51. package/src/utils/WebGLRectangleColoring.js +106 -106
  52. package/src/utils/WebGLSquareColoring.js +118 -118
  53. package/src/utils/WebGLSquareColoringAdvanced.js +230 -230
  54. package/src/utils/WebGLSquareColoringCatAdvanced.js +133 -133
  55. package/src/utils/WebGLSquareColoringKS.js +153 -153
  56. package/src/utils/stretching.js +131 -131
  57. package/src/utils/webGLUtils.js +71 -71
  58. package/src/utils/zoomUtils.js +142 -142
@@ -1,221 +1,221 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- import { Style } from '../Style.js'
5
-
6
- /**
7
- * A style representing the cell as a smoothed layer, to smoothing local variations and show main trends across space.
8
- *
9
- * @author Julien Gaffuri
10
- */
11
- export class KernelSmoothingStyle extends Style {
12
- //bandwidth
13
- // https://observablehq.com/@uwdata/fast-kde
14
- // https://observablehq.com/d/3127b6d89ada959f
15
- //TODO use https://github.com/uwdata/fast-kde ?
16
- //TODO https://observablehq.com/@sahilchinoy/areal-interpolation-iii ?
17
-
18
- /** @param {object} opts */
19
- constructor(opts) {
20
- super(opts)
21
- opts = opts || {}
22
-
23
- /** A function specifying the value to consider for each cell. This is the value to smooth.
24
- * @type {function(import("../Dataset").Cell):number} */
25
- this.value = opts.value
26
-
27
- /** The smoothing parameter, in geo unit. The larger, the more smoothed.
28
- * @type {function(number,number):number}
29
- */
30
- this.sigma = opts.sigma // (r, zf)=>...
31
-
32
- /** The styles to represent the smoothed cells.
33
- * @type {Array.<Style>}
34
- */
35
- this.styles = opts.styles
36
- }
37
-
38
- /**
39
- * Compute the kernel matrix, that is the matrix of the weights.
40
- * One quadrant is necessary only, since it is symetrical (along both x and y axes).
41
- * @param {number} s Sigma (in grid pixel !)
42
- * @returns {Array.<Array<number>>}
43
- * @private
44
- */
45
- getKernelMatrix(s) {
46
- //the size of the kernel: lets limit that to ~3 times the standard deviation, as an approximation.
47
- const kernelSize = Math.floor(3.25 * s)
48
-
49
- //pre-compute coefficient for gaussian computation, to avoid computing them every time.
50
- const c2 = 2 * s * s
51
-
52
- /**
53
- * The gaussian function. TODO expose that function as a parameter, to use other kernels ?
54
- * @param {number} x
55
- * @param {number} y
56
- * @returns {number}
57
- */
58
- const gaussian = (x, y) => (c2 != 0 ? Math.exp(-(x * x + y * y) / c2) : x == 0 && y == 0 ? 1 : 0) //dirac case
59
-
60
- /** @type {Array.<Array<number>>} */
61
- const kw = []
62
- for (let wi = 0; wi <= kernelSize; wi++) {
63
- /** @type {Array<number>} */
64
- const col = []
65
- for (let wj = 0; wj <= kernelSize; wj++) {
66
- //compute weight at wi,wj
67
- col.push(gaussian(wi, wj))
68
- }
69
- kw.push(col)
70
- }
71
-
72
- /*
73
- //debug: show values
74
- for (let wj = kernelSize-1; wj >=0; wj--) {
75
- let st = "";
76
- for (let wi = 0; wi <= kernelSize; wi++) {
77
- st += " " + Math.floor(kw[wi][wj].w *1000) /1000
78
- }
79
- console.log(st)
80
- }*/
81
-
82
- return kw
83
- }
84
-
85
- /**
86
- * Compute kernel smoothing of some cells.
87
- *
88
- * @private
89
- * @param {Array.<import("../Dataset").Cell>} cells The cells to be smoothed.
90
- * @param {import("../Dataset").Envelope} e Geo envelope to consider.
91
- * @param {number} r Resolution, in geo unit.
92
- * @param {number} s Sigma (in grid pixel !)
93
- * @returns {Array.<import("../Dataset").Cell>} The list of cells, including the initial ones and the ones with smoothed values, in "ksmval" property.
94
- */
95
- kernelSmoothing(cells, e, r, s) {
96
- //filter
97
- if (this.filter) cells = cells.filter(this.filter)
98
-
99
- const wThr = 0.01 //gaussian weights below this value will be ignored
100
-
101
- //compute extent, in grid position
102
- const xMin = Math.floor(e.xMin / r) * r
103
- const xMax = Math.floor(e.xMax / r) * r
104
- const yMin = Math.floor(e.yMin / r) * r
105
- const yMax = Math.floor(e.yMax / r) * r
106
-
107
- //compute matrix dimensions
108
- const nbX = (xMax - xMin) / r + 1
109
- const nbY = (yMax - yMin) / r + 1
110
-
111
- //initialise smoothed value to 0
112
- for (const c of cells) c['ksmval'] = 0
113
-
114
- //make matrix. add input cells by i/j (grid position)
115
- const index = {}
116
- for (const c of cells) {
117
- // i,j of the cell
118
- const i = Math.floor((c.x - xMin) / r)
119
- const j = Math.floor((c.y - yMin) / r)
120
- if (!index[i]) index[i] = {}
121
- index[i][j] = c
122
- }
123
-
124
- /** Check that the cell i,j is within the frame */
125
- const isWithinFrame = (i, j) => i >= 0 && i < nbX && j >= 0 && j < nbY
126
-
127
- //get kernel matrix
128
- /** @type {Array.<Array.<number>>} */
129
- const kernelMatrix = this.getKernelMatrix(s)
130
- const kernelSize = kernelMatrix.length
131
-
132
- //compute summ of the weights over entire kernel window
133
- /** @type {number} */
134
- let sumWeights = 0
135
- for (let ki = 1 - kernelSize; ki < kernelSize; ki++) {
136
- for (let kj = 1 - kernelSize; kj < kernelSize; kj++) {
137
- let w = kernelMatrix[Math.abs(ki)][Math.abs(kj)]
138
- if (w < wThr) continue
139
- sumWeights += w
140
- }
141
- }
142
-
143
- /** Add v as a contribution to the cell i,j */
144
- const addContributionTo = (i, j, v) => {
145
- //get cell at (i,j)
146
- const c_ = index[i] ? index[i][j] : undefined
147
-
148
- if (c_) {
149
- //cell exists: add contribution
150
- if (c_.ksmval) c_.ksmval += v
151
- else c_.ksmval = v
152
- } else {
153
- //cell does not exist: create a new one with the smoothed value
154
- if (!index[i]) index[i] = {}
155
- index[i][j] = { x: xMin + i * r, y: yMin + j * r, ksmval: v }
156
- }
157
- }
158
-
159
- //compute smoothing, input cell by input cell
160
- for (const c of cells) {
161
- /** get value of cell c
162
- * @type {number} */
163
- const val = this.value(c)
164
- if (!val) continue
165
-
166
- //cell matrix coordinates
167
- const i = Math.floor((c.x - xMin) / r)
168
- const j = Math.floor((c.y - yMin) / r)
169
-
170
- //add contributions to smoothed values
171
- for (let ki = 1 - kernelSize; ki < kernelSize; ki++) {
172
- for (let kj = 1 - kernelSize; kj < kernelSize; kj++) {
173
- //check cell is within the frame
174
- if (!isWithinFrame(i + ki, j + kj)) continue
175
-
176
- //get contribution (ki,kj)
177
- let w = kernelMatrix[Math.abs(ki)][Math.abs(kj)]
178
- if (!w || w < wThr) continue
179
- let v = w * val
180
- if (!v) continue
181
- v /= sumWeights
182
- if (!v) continue
183
-
184
- //add contribution
185
- addContributionTo(i + ki, j + kj, v)
186
- }
187
- }
188
- }
189
-
190
- //make output list
191
- const out = []
192
- for (let i of Object.keys(index)) for (const j of Object.keys(index[i])) out.push(index[i][j])
193
-
194
- return out
195
- }
196
-
197
- /**
198
- * Draw the smoothed cells depending on the list of styles specified.
199
- *
200
- * @param {Array.<import("../Dataset").Cell>} cells
201
- * @param {number} r
202
- * @param {import("../GeoCanvas").GeoCanvas} cg
203
- */
204
- draw(cells, r, cg) {
205
- if (!cells || cells.length == 0) return
206
-
207
- //get smoothing param in geo unit
208
- /** @type {number} */
209
- const sG = this.sigma(r, cg.zf)
210
-
211
- //apply kernel smoothing
212
- cells = this.kernelSmoothing(cells, cg.extGeo, r, sG / r)
213
-
214
- //draw smoothed cells from styles
215
- for (let s of this.styles) s.draw(cells, r, cg)
216
-
217
- //update legends
218
- //for (let s of this.styles)
219
- // s.updateLegends({ style: s, r: r, zf: cg.getZf() });
220
- }
221
- }
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { Style } from '../Style.js'
5
+
6
+ /**
7
+ * A style representing the cell as a smoothed layer, to smoothing local variations and show main trends across space.
8
+ *
9
+ * @author Julien Gaffuri
10
+ */
11
+ export class KernelSmoothingStyle extends Style {
12
+ //bandwidth
13
+ // https://observablehq.com/@uwdata/fast-kde
14
+ // https://observablehq.com/d/3127b6d89ada959f
15
+ //TODO use https://github.com/uwdata/fast-kde ?
16
+ //TODO https://observablehq.com/@sahilchinoy/areal-interpolation-iii ?
17
+
18
+ /** @param {object} opts */
19
+ constructor(opts) {
20
+ super(opts)
21
+ opts = opts || {}
22
+
23
+ /** A function specifying the value to consider for each cell. This is the value to smooth.
24
+ * @type {function(import("../Dataset").Cell):number} */
25
+ this.value = opts.value
26
+
27
+ /** The smoothing parameter, in geo unit. The larger, the more smoothed.
28
+ * @type {function(number,number):number}
29
+ */
30
+ this.sigma = opts.sigma // (r, zf)=>...
31
+
32
+ /** The styles to represent the smoothed cells.
33
+ * @type {Array.<Style>}
34
+ */
35
+ this.styles = opts.styles
36
+ }
37
+
38
+ /**
39
+ * Compute the kernel matrix, that is the matrix of the weights.
40
+ * One quadrant is necessary only, since it is symetrical (along both x and y axes).
41
+ * @param {number} s Sigma (in grid pixel !)
42
+ * @returns {Array.<Array<number>>}
43
+ * @private
44
+ */
45
+ getKernelMatrix(s) {
46
+ //the size of the kernel: lets limit that to ~3 times the standard deviation, as an approximation.
47
+ const kernelSize = Math.floor(3.25 * s)
48
+
49
+ //pre-compute coefficient for gaussian computation, to avoid computing them every time.
50
+ const c2 = 2 * s * s
51
+
52
+ /**
53
+ * The gaussian function. TODO expose that function as a parameter, to use other kernels ?
54
+ * @param {number} x
55
+ * @param {number} y
56
+ * @returns {number}
57
+ */
58
+ const gaussian = (x, y) => (c2 != 0 ? Math.exp(-(x * x + y * y) / c2) : x == 0 && y == 0 ? 1 : 0) //dirac case
59
+
60
+ /** @type {Array.<Array<number>>} */
61
+ const kw = []
62
+ for (let wi = 0; wi <= kernelSize; wi++) {
63
+ /** @type {Array<number>} */
64
+ const col = []
65
+ for (let wj = 0; wj <= kernelSize; wj++) {
66
+ //compute weight at wi,wj
67
+ col.push(gaussian(wi, wj))
68
+ }
69
+ kw.push(col)
70
+ }
71
+
72
+ /*
73
+ //debug: show values
74
+ for (let wj = kernelSize-1; wj >=0; wj--) {
75
+ let st = "";
76
+ for (let wi = 0; wi <= kernelSize; wi++) {
77
+ st += " " + Math.floor(kw[wi][wj].w *1000) /1000
78
+ }
79
+ console.log(st)
80
+ }*/
81
+
82
+ return kw
83
+ }
84
+
85
+ /**
86
+ * Compute kernel smoothing of some cells.
87
+ *
88
+ * @private
89
+ * @param {Array.<import("../Dataset").Cell>} cells The cells to be smoothed.
90
+ * @param {import("../Dataset").Envelope} e Geo envelope to consider.
91
+ * @param {number} r Resolution, in geo unit.
92
+ * @param {number} s Sigma (in grid pixel !)
93
+ * @returns {Array.<import("../Dataset").Cell>} The list of cells, including the initial ones and the ones with smoothed values, in "ksmval" property.
94
+ */
95
+ kernelSmoothing(cells, e, r, s) {
96
+ //filter
97
+ if (this.filter) cells = cells.filter(this.filter)
98
+
99
+ const wThr = 0.01 //gaussian weights below this value will be ignored
100
+
101
+ //compute extent, in grid position
102
+ const xMin = Math.floor(e.xMin / r) * r
103
+ const xMax = Math.floor(e.xMax / r) * r
104
+ const yMin = Math.floor(e.yMin / r) * r
105
+ const yMax = Math.floor(e.yMax / r) * r
106
+
107
+ //compute matrix dimensions
108
+ const nbX = (xMax - xMin) / r + 1
109
+ const nbY = (yMax - yMin) / r + 1
110
+
111
+ //initialise smoothed value to 0
112
+ for (const c of cells) c['ksmval'] = 0
113
+
114
+ //make matrix. add input cells by i/j (grid position)
115
+ const index = {}
116
+ for (const c of cells) {
117
+ // i,j of the cell
118
+ const i = Math.floor((c.x - xMin) / r)
119
+ const j = Math.floor((c.y - yMin) / r)
120
+ if (!index[i]) index[i] = {}
121
+ index[i][j] = c
122
+ }
123
+
124
+ /** Check that the cell i,j is within the frame */
125
+ const isWithinFrame = (i, j) => i >= 0 && i < nbX && j >= 0 && j < nbY
126
+
127
+ //get kernel matrix
128
+ /** @type {Array.<Array.<number>>} */
129
+ const kernelMatrix = this.getKernelMatrix(s)
130
+ const kernelSize = kernelMatrix.length
131
+
132
+ //compute summ of the weights over entire kernel window
133
+ /** @type {number} */
134
+ let sumWeights = 0
135
+ for (let ki = 1 - kernelSize; ki < kernelSize; ki++) {
136
+ for (let kj = 1 - kernelSize; kj < kernelSize; kj++) {
137
+ let w = kernelMatrix[Math.abs(ki)][Math.abs(kj)]
138
+ if (w < wThr) continue
139
+ sumWeights += w
140
+ }
141
+ }
142
+
143
+ /** Add v as a contribution to the cell i,j */
144
+ const addContributionTo = (i, j, v) => {
145
+ //get cell at (i,j)
146
+ const c_ = index[i] ? index[i][j] : undefined
147
+
148
+ if (c_) {
149
+ //cell exists: add contribution
150
+ if (c_.ksmval) c_.ksmval += v
151
+ else c_.ksmval = v
152
+ } else {
153
+ //cell does not exist: create a new one with the smoothed value
154
+ if (!index[i]) index[i] = {}
155
+ index[i][j] = { x: xMin + i * r, y: yMin + j * r, ksmval: v }
156
+ }
157
+ }
158
+
159
+ //compute smoothing, input cell by input cell
160
+ for (const c of cells) {
161
+ /** get value of cell c
162
+ * @type {number} */
163
+ const val = this.value(c)
164
+ if (!val) continue
165
+
166
+ //cell matrix coordinates
167
+ const i = Math.floor((c.x - xMin) / r)
168
+ const j = Math.floor((c.y - yMin) / r)
169
+
170
+ //add contributions to smoothed values
171
+ for (let ki = 1 - kernelSize; ki < kernelSize; ki++) {
172
+ for (let kj = 1 - kernelSize; kj < kernelSize; kj++) {
173
+ //check cell is within the frame
174
+ if (!isWithinFrame(i + ki, j + kj)) continue
175
+
176
+ //get contribution (ki,kj)
177
+ let w = kernelMatrix[Math.abs(ki)][Math.abs(kj)]
178
+ if (!w || w < wThr) continue
179
+ let v = w * val
180
+ if (!v) continue
181
+ v /= sumWeights
182
+ if (!v) continue
183
+
184
+ //add contribution
185
+ addContributionTo(i + ki, j + kj, v)
186
+ }
187
+ }
188
+ }
189
+
190
+ //make output list
191
+ const out = []
192
+ for (let i of Object.keys(index)) for (const j of Object.keys(index[i])) out.push(index[i][j])
193
+
194
+ return out
195
+ }
196
+
197
+ /**
198
+ * Draw the smoothed cells depending on the list of styles specified.
199
+ *
200
+ * @param {Array.<import("../Dataset").Cell>} cells
201
+ * @param {number} r
202
+ * @param {import("../GeoCanvas").GeoCanvas} cg
203
+ */
204
+ draw(cells, r, cg) {
205
+ if (!cells || cells.length == 0) return
206
+
207
+ //get smoothing param in geo unit
208
+ /** @type {number} */
209
+ const sG = this.sigma(r, cg.zf)
210
+
211
+ //apply kernel smoothing
212
+ cells = this.kernelSmoothing(cells, cg.extGeo, r, sG / r)
213
+
214
+ //draw smoothed cells from styles
215
+ for (let s of this.styles) s.draw(cells, r, cg)
216
+
217
+ //update legends
218
+ //for (let s of this.styles)
219
+ // s.updateLegends({ style: s, r: r, zf: cg.getZf() });
220
+ }
221
+ }