gridviz 2.1.9 → 2.1.10

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 (57) hide show
  1. package/README.md +125 -125
  2. package/dist/gridviz.js +8036 -8024
  3. package/dist/gridviz.min.js +1 -1
  4. package/package.json +77 -77
  5. package/src/App.js +705 -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 -101
  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/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/LGrid.js +54 -54
  22. package/src/dataset/TiledGrid.js +264 -264
  23. package/src/index.js +71 -71
  24. package/src/legend/ColorCategoryLegend.js +124 -124
  25. package/src/legend/ColorDiscreteLegend.js +103 -103
  26. package/src/legend/ColorLegend.js +124 -124
  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/IsoFenceStyle.js +262 -262
  34. package/src/style/JoyPlotStyle.js +135 -135
  35. package/src/style/LegoStyle.js +112 -112
  36. package/src/style/MosaicStyle.js +107 -107
  37. package/src/style/NinjaStarStyle.js +125 -125
  38. package/src/style/PillarStyle.js +230 -230
  39. package/src/style/SegmentStyle.js +142 -142
  40. package/src/style/ShapeColorSizeStyle.js +126 -126
  41. package/src/style/SideCatStyle.js +172 -172
  42. package/src/style/SideStyle.js +216 -216
  43. package/src/style/SquareColorCatWGLStyle.js +120 -120
  44. package/src/style/SquareColorWGLStyle.js +146 -146
  45. package/src/style/StrokeStyle.js +131 -131
  46. package/src/style/TanakaStyle.js +160 -160
  47. package/src/style/TextStyle.js +132 -132
  48. package/src/style/TimeSeriesStyle.js +250 -250
  49. package/src/utils/Utils.js +35 -35
  50. package/src/utils/WebGLRectangleColoring.js +106 -106
  51. package/src/utils/WebGLSquareColoring.js +118 -118
  52. package/src/utils/WebGLSquareColoringAdvanced.js +230 -230
  53. package/src/utils/WebGLSquareColoringCatAdvanced.js +133 -133
  54. package/src/utils/WebGLSquareColoringKS.js +153 -153
  55. package/src/utils/stretching.js +131 -131
  56. package/src/utils/webGLUtils.js +71 -71
  57. package/src/utils/zoomUtils.js +142 -142
@@ -1,250 +1,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
- /**
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
+ /**
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,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
+ }