gridviz 2.1.11 → 2.1.13

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 (60) hide show
  1. package/README.md +125 -125
  2. package/dist/gridviz.js +8254 -7887
  3. package/dist/gridviz.min.js +1 -1
  4. package/package.json +77 -77
  5. package/src/App.js +758 -705
  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 +113 -113
  10. package/src/GeoCanvas.js +420 -420
  11. package/src/LabelLayer.js +190 -190
  12. package/src/Layer.js +103 -103
  13. package/src/Legend.js +86 -86
  14. package/src/LineLayer.js +150 -150
  15. package/src/Style.js +129 -129
  16. package/src/Tooltip.js +180 -180
  17. package/src/button/Button.js +54 -0
  18. package/src/button/FullscreenButton.js +98 -0
  19. package/src/button/ZoomButtons.js +72 -0
  20. package/src/dataset/COGeo.js +24 -24
  21. package/src/dataset/CSVGrid.js +104 -104
  22. package/src/dataset/GeoTIFF.js +127 -127
  23. package/src/dataset/GridTile.js +41 -41
  24. package/src/dataset/LGrid.js +54 -54
  25. package/src/dataset/TiledGrid.js +264 -264
  26. package/src/index.js +71 -71
  27. package/src/legend/ColorCategoryLegend.js +124 -124
  28. package/src/legend/ColorDiscreteLegend.js +103 -103
  29. package/src/legend/ColorLegend.js +128 -124
  30. package/src/legend/SegmentOrientationLegend.js +87 -87
  31. package/src/legend/SegmentWidthLegend.js +101 -97
  32. package/src/legend/SizeLegend.js +141 -141
  33. package/src/style/CompositionStyle.js +300 -300
  34. package/src/style/ContourStyle.js +54 -54
  35. package/src/style/DotDensityStyle.js +156 -156
  36. package/src/style/IsoFenceStyle.js +262 -262
  37. package/src/style/JoyPlotStyle.js +135 -135
  38. package/src/style/LegoStyle.js +112 -112
  39. package/src/style/MosaicStyle.js +107 -107
  40. package/src/style/NinjaStarStyle.js +125 -125
  41. package/src/style/PillarStyle.js +230 -230
  42. package/src/style/SegmentStyle.js +142 -142
  43. package/src/style/ShapeColorSizeStyle.js +152 -126
  44. package/src/style/SideCatStyle.js +172 -172
  45. package/src/style/SideStyle.js +216 -216
  46. package/src/style/SquareColorCatWGLStyle.js +120 -120
  47. package/src/style/SquareColorWGLStyle.js +146 -146
  48. package/src/style/StrokeStyle.js +131 -131
  49. package/src/style/TanakaStyle.js +160 -160
  50. package/src/style/TextStyle.js +132 -132
  51. package/src/style/TimeSeriesStyle.js +259 -250
  52. package/src/utils/Utils.js +35 -35
  53. package/src/utils/WebGLRectangleColoring.js +106 -106
  54. package/src/utils/WebGLSquareColoring.js +118 -118
  55. package/src/utils/WebGLSquareColoringAdvanced.js +230 -230
  56. package/src/utils/WebGLSquareColoringCatAdvanced.js +133 -133
  57. package/src/utils/WebGLSquareColoringKS.js +153 -153
  58. package/src/utils/stretching.js +131 -131
  59. package/src/utils/webGLUtils.js +71 -71
  60. package/src/utils/zoomUtils.js +142 -142
@@ -1,250 +1,259 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- import { Style } from '../Style.js'
5
-
6
- /** @typedef {"first"|"bottom"|"center"|"top"|"last"} AnchorModeYEnum */
7
-
8
- /**
9
- * Show cell as timeseries chart
10
- * Can be used for sparkline map of https://datagistips.hypotheses.org/488
11
- *
12
- * @author Julien Gaffuri
13
- */
14
- export class TimeSeriesStyle extends Style {
15
- /** @param {object} opts */
16
- constructor(opts) {
17
- super(opts)
18
- opts = opts || {}
19
-
20
- /** The columns of the time series, ordered in chronological order.
21
- * @type {Array.<string>} */
22
- this.ts = opts.ts
23
-
24
- /** A function specifying when a value should be considered as "no data" and thus not ignored. The line will have a break at these values.
25
- * @type {function(string):boolean} */
26
- this.noData = opts.noData || ((v) => v === undefined || v == "" || v === null || isNaN(+v))
27
-
28
- //x
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)
34
-
35
- //y
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
48
-
49
- /** 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
- /**
55
- * @type {string} */
56
- this.colorCol = opts.colorCol
57
-
58
- /** A function returning the color of the cell.
59
- * @type {function(number,number,import("../Style.js").Stat|undefined,number):string} */
60
- this.color = opts.color || ((v, r, s, zf) => 'black')
61
-
62
- }
63
-
64
- /**
65
- * Draw cells as text.
66
- *
67
- * @param {Array.<import("../Dataset.js").Cell>} cells
68
- * @param {number} r
69
- * @param {import("../GeoCanvas.js").GeoCanvas} cg
70
- */
71
- draw(cells, r, cg) {
72
-
73
- //filter
74
- if (this.filter) cells = cells.filter(this.filter)
75
-
76
- //zoom factor
77
- const zf = cg.getZf()
78
-
79
- let statWidth
80
- if (this.lineWidthCol) {
81
- //and compute size variable statistics
82
- statWidth = Style.getStatistics(cells, (c) => c[this.lineWidthCol], true)
83
- }
84
-
85
- let statColor
86
- if (this.colorCol) {
87
- //compute color variable statistics
88
- statColor = Style.getStatistics(cells, (c) => c[this.colorCol], true)
89
- }
90
-
91
- //compute cell amplitude
92
- const getAmplitude = c => {
93
- let min, max
94
- for (let t of this.ts) {
95
- const val = c[t];
96
- if (val == undefined) continue
97
- if (min == undefined || val < min) min = val
98
- if (max == undefined || val > max) max = val
99
- }
100
- if (min == undefined) return undefined
101
- return max - min
102
- }
103
-
104
- //compute max amplitude
105
- let ampMax
106
- for (let c of cells) {
107
- const amp = getAmplitude(c)
108
- if (amp == undefined) continue
109
- if (ampMax == undefined || amp > ampMax) ampMax = amp
110
- }
111
- if (!ampMax) return
112
-
113
- const nb = this.ts.length
114
-
115
- //draw with HTML canvas
116
- //in geo coordinates
117
- cg.setCanvasTransform()
118
-
119
- cg.ctx.lineCap = "butt"
120
- for (let c of cells) {
121
-
122
- //line width
123
- /** @type {number|undefined} */
124
- const wG = this.lineWidth ? this.lineWidth(c[this.lineWidthCol], r, statWidth, zf) : undefined
125
- if (!wG || wG < 0) continue
126
-
127
- //line color
128
- /** @type {string|undefined} */
129
- const col = this.color ? this.color(c[this.colorCol], r, statColor, zf) : undefined
130
- if (!col) continue
131
-
132
-
133
- //x
134
- const offX = this.offsetX ? this.offsetX(c, r, zf) : 0
135
- if (offX == undefined || isNaN(offX)) continue
136
- const w = this.width ? this.width(c, r, zf) : r
137
- if (w == undefined || isNaN(w)) continue
138
-
139
- //y
140
- const offY = this.offsetY ? this.offsetY(c, r, zf) : 0
141
- if (offY == undefined || isNaN(offY)) continue
142
- const h = this.height ? this.height(c, r, zf) : r
143
- if (h == undefined || isNaN(h)) continue
144
- const anchY = this.anchorModeY ? this.anchorModeY(c, r, zf) : "center"
145
- if (!anchY) continue
146
-
147
- cg.ctx.lineWidth = wG
148
- cg.ctx.strokeStyle = col
149
-
150
- //compute anchor Y figures
151
- let val0, y0
152
- if (anchY === "first") {
153
- //get first value
154
- val0 = c[this.ts[0]]
155
- y0 = 0
156
- } else if (anchY === "last") {
157
- //get last value
158
- val0 = c[this.ts[this.ts.length - 1]]
159
- y0 = 0
160
- } else if (anchY === "bottom") {
161
- //get min
162
- for (let t of this.ts) {
163
- const val = +c[t];
164
- if (val == undefined) continue
165
- if (val0 == undefined || val < val0) val0 = val
166
- }
167
- y0 = 0
168
- } else if (anchY === "top") {
169
- //get max
170
- for (let t of this.ts) {
171
- const val = +c[t];
172
- if (val == undefined) continue
173
- if (val0 == undefined || val > val0) val0 = val
174
- }
175
- y0 = r
176
- } else if (anchY === "center") {
177
- //get min and max
178
- let min, max
179
- for (let t of this.ts) {
180
- const val = c[t];
181
- if (val == undefined) continue
182
- if (min == undefined || val < min) min = val
183
- if (max == undefined || val > max) max = val
184
- }
185
- val0 = (+max + +min) * 0.5
186
- y0 = r / 2
187
- } else {
188
- console.log("Unexpected anchorModeY: " + anchY)
189
- continue;
190
- }
191
-
192
- /*/draw line
193
- if (val0 == undefined || isNaN(val0)) continue
194
- cg.ctx.beginPath()
195
- const sX = w / (nb - 1)
196
- for (let i = 0; i < nb; i++) {
197
- const val = c[this.ts[i]]
198
- if (val == undefined || isNaN(val)) break
199
- if (i == 0)
200
- cg.ctx.moveTo(c.x + i * sX + offX, c.y + y0 + (val - val0) * h / ampMax + offY)
201
- else
202
- cg.ctx.lineTo(c.x + i * sX + offX, c.y + y0 + (val - val0) * h / ampMax + offY)
203
- }
204
- cg.ctx.stroke()*/
205
-
206
-
207
- //draw line, segment by segment
208
- const sX = w / (nb - 1)
209
-
210
- //handle first point
211
- let v0 = c[this.ts[0]]
212
- if (!this.noData(v0)) {
213
- cg.ctx.beginPath()
214
- cg.ctx.moveTo(c.x + offX, c.y + y0 + (v0 - val0) * h / ampMax + offY)
215
- }
216
- //console.log(v0, isNaN(v0))
217
-
218
- let v1
219
- for (let i = 1; i < nb; i++) {
220
- v1 = c[this.ts[i]]
221
-
222
- //draw segment from v0 to v1
223
-
224
- //both points 'no data'
225
- if (this.noData(v0) && this.noData(v1)) {
226
-
227
- //second point 'no data'
228
- } else if (!this.noData(v0) && this.noData(v1)) {
229
- cg.ctx.stroke()
230
-
231
- //first point 'no data'
232
- } else if (this.noData(v0) && !this.noData(v1)) {
233
- cg.ctx.beginPath()
234
- cg.ctx.moveTo(c.x + i * sX + offX, c.y + y0 + (v1 - val0) * h / ampMax + offY)
235
-
236
- //both points have data: trace line
237
- } else {
238
- cg.ctx.lineTo(c.x + i * sX + offX, c.y + y0 + (v1 - val0) * h / ampMax + offY)
239
- //if it is the last point, stroke
240
- if (i == nb - 1) cg.ctx.stroke()
241
- }
242
- v0 = v1
243
- }
244
-
245
- }
246
-
247
- }
248
-
249
- }
250
-
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { Style } from '../Style.js'
5
+
6
+ /** @typedef {"first"|"bottom"|"center"|"top"|"last"} AnchorModeYEnum */
7
+
8
+ /**
9
+ * Show cell as timeseries chart
10
+ * Can be used for sparkline map of https://datagistips.hypotheses.org/488
11
+ *
12
+ * @author Julien Gaffuri
13
+ */
14
+ export class TimeSeriesStyle extends Style {
15
+ /** @param {object} opts */
16
+ constructor(opts) {
17
+ super(opts)
18
+ opts = opts || {}
19
+
20
+ /** The columns of the time series, ordered in chronological order.
21
+ * @type {Array.<string>} */
22
+ this.ts = opts.ts
23
+
24
+ /** A function specifying when a value should be considered as "no data" and thus not ignored. The line will have a break at these values.
25
+ * @type {function(string):boolean} */
26
+ this.noData = opts.noData || ((v) => v === undefined || v == "" || v === null || isNaN(+v))
27
+
28
+ //x
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)
34
+
35
+ //y
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
48
+
49
+ /** 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')
60
+
61
+ }
62
+
63
+ /**
64
+ * Draw cells as text.
65
+ *
66
+ * @param {Array.<import("../Dataset.js").Cell>} cells
67
+ * @param {number} r
68
+ * @param {import("../GeoCanvas.js").GeoCanvas} cg
69
+ */
70
+ draw(cells, r, cg) {
71
+
72
+ //filter
73
+ if (this.filter) cells = cells.filter(this.filter)
74
+
75
+ //zoom factor
76
+ const zf = cg.getZf()
77
+
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
+ }
89
+
90
+ //compute cell amplitude
91
+ const getAmplitude = c => {
92
+ let min, max
93
+ for (let t of this.ts) {
94
+ const val = c[t];
95
+ if (val == undefined) continue
96
+ if (min == undefined || val < min) min = val
97
+ if (max == undefined || val > max) max = val
98
+ }
99
+ if (min == undefined) return undefined
100
+ return max - min
101
+ }
102
+
103
+ //compute max amplitude
104
+ let ampMax
105
+ for (let c of cells) {
106
+ const amp = getAmplitude(c)
107
+ if (amp == undefined) continue
108
+ if (ampMax == undefined || amp > ampMax) ampMax = amp
109
+ }
110
+ if (!ampMax) return
111
+
112
+ const nb = this.ts.length
113
+
114
+ //draw with HTML canvas
115
+ //in geo coordinates
116
+ cg.setCanvasTransform()
117
+
118
+ cg.ctx.lineCap = "butt"
119
+ for (let c of cells) {
120
+
121
+ //line width
122
+ /** @type {number|undefined} */
123
+ const wG = this.lineWidth ? this.lineWidth(c[this.lineWidthCol], r, statWidth, zf) : undefined
124
+ if (!wG || wG < 0) continue
125
+
126
+ //line color
127
+ /** @type {string|undefined} */
128
+ const col = this.color ? this.color(c[this.colorCol], r, statColor, zf) : undefined
129
+ if (!col) continue
130
+
131
+
132
+ //x
133
+ const offX = this.offsetX ? this.offsetX(c, r, zf) : 0
134
+ if (offX == undefined || isNaN(offX)) continue
135
+ const w = this.width ? this.width(c, r, zf) : r
136
+ if (w == undefined || isNaN(w)) continue
137
+
138
+ //y
139
+ const offY = this.offsetY ? this.offsetY(c, r, zf) : 0
140
+ if (offY == undefined || isNaN(offY)) continue
141
+ const h = this.height ? this.height(c, r, zf) : r
142
+ if (h == undefined || isNaN(h)) continue
143
+ const anchY = this.anchorModeY ? this.anchorModeY(c, r, zf) : "center"
144
+ if (!anchY) continue
145
+
146
+ cg.ctx.lineWidth = wG
147
+ cg.ctx.strokeStyle = col
148
+
149
+ //compute anchor Y figures
150
+ let val0, y0
151
+ if (anchY === "first") {
152
+ //get first value
153
+ val0 = c[this.ts[0]]
154
+ y0 = 0
155
+ } else if (anchY === "last") {
156
+ //get last value
157
+ val0 = c[this.ts[this.ts.length - 1]]
158
+ y0 = 0
159
+ } else if (anchY === "bottom") {
160
+ //get min
161
+ for (let t of this.ts) {
162
+ const val = +c[t];
163
+ if (val == undefined) continue
164
+ if (val0 == undefined || val < val0) val0 = val
165
+ }
166
+ y0 = 0
167
+ } else if (anchY === "top") {
168
+ //get max
169
+ for (let t of this.ts) {
170
+ const val = +c[t];
171
+ if (val == undefined) continue
172
+ if (val0 == undefined || val > val0) val0 = val
173
+ }
174
+ y0 = r
175
+ } else if (anchY === "center") {
176
+ //get min and max
177
+ let min, max
178
+ for (let t of this.ts) {
179
+ const val = c[t];
180
+ if (val == undefined) continue
181
+ if (min == undefined || val < min) min = val
182
+ if (max == undefined || val > max) max = val
183
+ }
184
+ val0 = (+max + +min) * 0.5
185
+ y0 = r / 2
186
+ } else {
187
+ console.log("Unexpected anchorModeY: " + anchY)
188
+ continue;
189
+ }
190
+
191
+ /*/draw line
192
+ if (val0 == undefined || isNaN(val0)) continue
193
+ cg.ctx.beginPath()
194
+ const sX = w / (nb - 1)
195
+ for (let i = 0; i < nb; i++) {
196
+ const val = c[this.ts[i]]
197
+ if (val == undefined || isNaN(val)) break
198
+ if (i == 0)
199
+ cg.ctx.moveTo(c.x + i * sX + offX, c.y + y0 + (val - val0) * h / ampMax + offY)
200
+ else
201
+ cg.ctx.lineTo(c.x + i * sX + offX, c.y + y0 + (val - val0) * h / ampMax + offY)
202
+ }
203
+ cg.ctx.stroke()*/
204
+
205
+
206
+ //draw line, segment by segment
207
+ const sX = w / (nb - 1)
208
+
209
+ //handle first point
210
+ let v0 = c[this.ts[0]]
211
+ if (!this.noData(v0)) {
212
+ cg.ctx.beginPath()
213
+ cg.ctx.moveTo(c.x + offX, c.y + y0 + (v0 - val0) * h / ampMax + offY)
214
+ }
215
+ //console.log(v0, isNaN(v0))
216
+
217
+ let v1
218
+ for (let i = 1; i < nb; i++) {
219
+ v1 = c[this.ts[i]]
220
+
221
+ //draw segment from v0 to v1
222
+
223
+ //both points 'no data'
224
+ if (this.noData(v0) && this.noData(v1)) {
225
+
226
+ //second point 'no data'
227
+ } else if (!this.noData(v0) && this.noData(v1)) {
228
+ cg.ctx.stroke()
229
+
230
+ //first point 'no data'
231
+ } 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)
234
+
235
+ //both points have data: trace line
236
+ } else {
237
+ cg.ctx.lineTo(c.x + i * sX + offX, c.y + y0 + (v1 - val0) * h / ampMax + offY)
238
+ //if it is the last point, stroke
239
+ if (i == nb - 1) cg.ctx.stroke()
240
+ }
241
+ v0 = v1
242
+ }
243
+
244
+ }
245
+
246
+ //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
+
256
+ }
257
+
258
+ }
259
+
@@ -1,35 +1,35 @@
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
- */
11
- export function getClass(v, breaks) {
12
- if (!breaks) return
13
- if (breaks.length == 0) return 0
14
- if (v <= breaks[0]) return 0
15
- for (let i = 1; i < breaks.length; i++) if (breaks[i - 1] < v && v <= breaks[i]) return i
16
- return breaks.length
17
- }
18
-
19
- export let monitor = false
20
-
21
- let previousDate
22
- export function monitorDuration(message) {
23
- const nowDate = Date.now()
24
-
25
- //first call
26
- if (!previousDate) {
27
- previousDate = nowDate
28
- console.log(previousDate, message)
29
- return
30
- }
31
-
32
- const d = nowDate - previousDate
33
- previousDate = nowDate
34
- console.log(d, message)
35
- }
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
+ */
11
+ export function getClass(v, breaks) {
12
+ if (!breaks) return
13
+ if (breaks.length == 0) return 0
14
+ if (v <= breaks[0]) return 0
15
+ for (let i = 1; i < breaks.length; i++) if (breaks[i - 1] < v && v <= breaks[i]) return i
16
+ return breaks.length
17
+ }
18
+
19
+ export let monitor = false
20
+
21
+ let previousDate
22
+ export function monitorDuration(message) {
23
+ const nowDate = Date.now()
24
+
25
+ //first call
26
+ if (!previousDate) {
27
+ previousDate = nowDate
28
+ console.log(previousDate, message)
29
+ return
30
+ }
31
+
32
+ const d = nowDate - previousDate
33
+ previousDate = nowDate
34
+ console.log(d, message)
35
+ }