gridviz 3.0.15 → 3.0.16

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 (55) hide show
  1. package/README.md +127 -128
  2. package/dist/gridviz.js +7959 -7861
  3. package/dist/gridviz.min.js +1 -1
  4. package/package.json +74 -74
  5. package/src/button/ZoomButtons.js +101 -96
  6. package/src/core/Dataset.js +154 -157
  7. package/src/core/Drawable.js +60 -61
  8. package/src/core/GeoCanvas.js +409 -370
  9. package/src/core/Layer.js +23 -25
  10. package/src/core/Legend.js +108 -110
  11. package/src/core/Map.js +495 -495
  12. package/src/core/MultiResolutionDataset.js +93 -97
  13. package/src/core/Style.js +98 -99
  14. package/src/dataset/CSVGrid.js +112 -112
  15. package/src/dataset/GeoTIFF.js +122 -123
  16. package/src/dataset/JSGrid.js +55 -54
  17. package/src/dataset/TiledGrid.js +289 -288
  18. package/src/dataset/worker.js +18 -0
  19. package/src/index.js +77 -71
  20. package/src/layer/BackgroundLayer.js +162 -158
  21. package/src/layer/BackgroundLayerImage.js +81 -84
  22. package/src/layer/BackgroundLayerWMS.js +104 -108
  23. package/src/layer/GeoJSONLayer.js +214 -220
  24. package/src/layer/GridLayer.js +148 -157
  25. package/src/layer/LabelLayer.js +194 -193
  26. package/src/legend/ColorCategoryLegend.js +109 -110
  27. package/src/legend/ColorDiscreteLegend.js +100 -102
  28. package/src/legend/ColorLegend.js +115 -118
  29. package/src/legend/OrientationLegend.js +89 -91
  30. package/src/legend/SizeLegend.js +224 -224
  31. package/src/legend/TernaryLegend.js +302 -210
  32. package/src/style/CompositionStyle.js +291 -288
  33. package/src/style/DotDensityStyle.js +133 -134
  34. package/src/style/ImageStyle.js +100 -102
  35. package/src/style/IsoFenceStyle.js +217 -203
  36. package/src/style/JoyPlotStyle.js +127 -128
  37. package/src/style/LegoStyle.js +110 -110
  38. package/src/style/MosaicStyle.js +99 -99
  39. package/src/style/NinjaStarStyle.js +102 -102
  40. package/src/style/PillarStyle.js +207 -208
  41. package/src/style/SegmentStyle.js +105 -105
  42. package/src/style/ShapeColorSizeStyle.js +147 -132
  43. package/src/style/SideCategoryStyle.js +112 -114
  44. package/src/style/SideStyle.js +212 -205
  45. package/src/style/SquareColorCategoryWebGLStyle.js +107 -108
  46. package/src/style/SquareColorWebGLStyle.js +126 -126
  47. package/src/style/StrokeStyle.js +135 -136
  48. package/src/style/TanakaStyle.js +69 -68
  49. package/src/style/TextStyle.js +110 -111
  50. package/src/style/TimeSeriesStyle.js +222 -229
  51. package/src/utils/scale.js +218 -228
  52. package/src/utils/stretching.js +120 -133
  53. package/src/utils/ternary.js +203 -204
  54. package/src/utils/utils.js +58 -63
  55. package/src/utils/webGLUtils.js +72 -70
@@ -1,229 +1,222 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- import { Style } from '../core/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
- * @module style
13
- * @author Julien Gaffuri
14
- */
15
- export class TimeSeriesStyle extends Style {
16
- /** @param {object} opts */
17
- constructor(opts) {
18
- super(opts)
19
- opts = opts || {}
20
-
21
- /** The columns of the time series, ordered in chronological order.
22
- * @type {Array.<string>} */
23
- this.ts = opts.ts
24
-
25
- /** 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.
26
- * @type {function(string):boolean} */
27
- this.noData = opts.noData || ((v) => v === undefined || v == "" || v === null || isNaN(+v))
28
-
29
- //x
30
- /** in geo unit
31
- * @type {function(import("../core/Dataset.js").Cell,number,number):number} */
32
- this.offsetX = opts.offsetX || ((c, r, z) => 0)
33
- /** @type {function(import("../core/Dataset.js").Cell,number,number):number} */
34
- this.width = opts.width || ((c, r, z) => r)
35
-
36
- //y
37
- /** in geo unit
38
- * @type {function(import("../core/Dataset.js").Cell,number,number):number} */
39
- this.offsetY = opts.offsetY || ((c, r, z) => 0)
40
- /** @type {function(import("../core/Dataset.js").Cell,number,number):number} */
41
- this.height = opts.height || ((c, r, z) => r)
42
- /** @type {function(import("../core/Dataset.js").Cell,number,number):AnchorModeYEnum} */
43
- this.anchorModeY = opts.anchorModeY || ((c, r, z) => "center")
44
-
45
- /** A function returning the width of the line, in geo unit
46
- * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
47
- this.lineWidth = opts.lineWidth || ((v, r, s, z) => 1.5 * z)
48
-
49
- /** A function returning the color of the chart.
50
- * @type {function(import('../core/Dataset.js').Cell, number, number, object):string} */
51
- this.color = opts.color || (() => "black") //(c,r,z,vs) => {}
52
- }
53
-
54
- /**
55
- * Draw cells as text.
56
- *
57
- * @param {Array.<import("../core/Dataset.js").Cell>} cells
58
- * @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
59
- * @param {number} resolution
60
- */
61
- draw(cells, geoCanvas, resolution) {
62
-
63
- //filter
64
- if (this.filter) cells = cells.filter(this.filter)
65
-
66
- //
67
- const z = geoCanvas.view.z
68
-
69
- //get view scale
70
- const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
71
-
72
- //compute cell amplitude
73
- const getAmplitude = c => {
74
- let min, max
75
- for (let t of this.ts) {
76
- const val = c[t];
77
- if (val == undefined) continue
78
- if (min == undefined || val < min) min = val
79
- if (max == undefined || val > max) max = val
80
- }
81
- if (min == undefined) return undefined
82
- return max - min
83
- }
84
-
85
- //compute max amplitude
86
- let ampMax
87
- for (let c of cells) {
88
- const amp = getAmplitude(c)
89
- if (amp == undefined) continue
90
- if (ampMax == undefined || amp > ampMax) ampMax = amp
91
- }
92
- if (!ampMax) return
93
-
94
- const nb = this.ts.length
95
-
96
- geoCanvas.ctx.lineCap = "butt"
97
- for (let c of cells) {
98
-
99
- //line width
100
- /** @type {number|undefined} */
101
- const wG = this.lineWidth ? this.lineWidth(c, resolution, z, viewScale) : undefined
102
- if (!wG || wG < 0) continue
103
-
104
- //line color
105
- /** @type {string|undefined} */
106
- const col = this.color ? this.color(c, resolution, z, viewScale) : undefined
107
- if (!col) continue
108
-
109
-
110
- //x
111
- const offX = this.offsetX ? this.offsetX(c, resolution, z) : 0
112
- if (offX == undefined || isNaN(offX)) continue
113
- const w = this.width ? this.width(c, resolution, z) : resolution
114
- if (w == undefined || isNaN(w)) continue
115
-
116
- //y
117
- const offY = this.offsetY ? this.offsetY(c, resolution, z) : 0
118
- if (offY == undefined || isNaN(offY)) continue
119
- const h = this.height ? this.height(c, resolution, z) : resolution
120
- if (h == undefined || isNaN(h)) continue
121
- const anchY = this.anchorModeY ? this.anchorModeY(c, resolution, z) : "center"
122
- if (!anchY) continue
123
-
124
- geoCanvas.ctx.lineWidth = wG
125
- geoCanvas.ctx.strokeStyle = col
126
-
127
- //compute anchor Y figures
128
- let val0, y0
129
- if (anchY === "first") {
130
- //get first value
131
- val0 = c[this.ts[0]]
132
- y0 = 0
133
- } else if (anchY === "last") {
134
- //get last value
135
- val0 = c[this.ts[this.ts.length - 1]]
136
- y0 = 0
137
- } else if (anchY === "bottom") {
138
- //get min
139
- for (let t of this.ts) {
140
- const val = +c[t];
141
- if (val == undefined) continue
142
- if (val0 == undefined || val < val0) val0 = val
143
- }
144
- y0 = 0
145
- } else if (anchY === "top") {
146
- //get max
147
- for (let t of this.ts) {
148
- const val = +c[t];
149
- if (val == undefined) continue
150
- if (val0 == undefined || val > val0) val0 = val
151
- }
152
- y0 = resolution
153
- } else if (anchY === "center") {
154
- //get min and max
155
- let min, max
156
- for (let t of this.ts) {
157
- const val = c[t];
158
- if (val == undefined) continue
159
- if (min == undefined || val < min) min = val
160
- if (max == undefined || val > max) max = val
161
- }
162
- val0 = (+max + +min) * 0.5
163
- y0 = resolution / 2
164
- } else {
165
- console.log("Unexpected anchorModeY: " + anchY)
166
- continue;
167
- }
168
-
169
- /*/draw line
170
- if (val0 == undefined || isNaN(val0)) continue
171
- cg.ctx.beginPath()
172
- const sX = w / (nb - 1)
173
- for (let i = 0; i < nb; i++) {
174
- const val = c[this.ts[i]]
175
- if (val == undefined || isNaN(val)) break
176
- if (i == 0)
177
- cg.ctx.moveTo(c.x + i * sX + offX, c.y + y0 + (val - val0) * h / ampMax + offY)
178
- else
179
- cg.ctx.lineTo(c.x + i * sX + offX, c.y + y0 + (val - val0) * h / ampMax + offY)
180
- }
181
- cg.ctx.stroke()*/
182
-
183
-
184
- //draw line, segment by segment
185
- const sX = w / (nb - 1)
186
-
187
- //handle first point
188
- let v0 = c[this.ts[0]]
189
- if (!this.noData(v0)) {
190
- geoCanvas.ctx.beginPath()
191
- geoCanvas.ctx.moveTo(c.x + offX, c.y + y0 + (v0 - val0) * h / ampMax + offY)
192
- }
193
- //console.log(v0, isNaN(v0))
194
-
195
- let v1
196
- for (let i = 1; i < nb; i++) {
197
- v1 = c[this.ts[i]]
198
-
199
- //draw segment from v0 to v1
200
-
201
- //both points 'no data'
202
- if (this.noData(v0) && this.noData(v1)) {
203
-
204
- //second point 'no data'
205
- } else if (!this.noData(v0) && this.noData(v1)) {
206
- geoCanvas.ctx.stroke()
207
-
208
- //first point 'no data'
209
- } else if (this.noData(v0) && !this.noData(v1)) {
210
- geoCanvas.ctx.beginPath()
211
- geoCanvas.ctx.moveTo(c.x + i * sX + offX, c.y + y0 + (v1 - val0) * h / ampMax + offY)
212
-
213
- //both points have data: trace line
214
- } else {
215
- geoCanvas.ctx.lineTo(c.x + i * sX + offX, c.y + y0 + (v1 - val0) * h / ampMax + offY)
216
- //if it is the last point, stroke
217
- if (i == nb - 1) geoCanvas.ctx.stroke()
218
- }
219
- v0 = v1
220
- }
221
-
222
- }
223
-
224
- //update legend, if any
225
- this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
226
- }
227
-
228
- }
229
-
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { Style } from '../core/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
+ * @module style
13
+ * @author Julien Gaffuri
14
+ */
15
+ export class TimeSeriesStyle extends Style {
16
+ /** @param {object} opts */
17
+ constructor(opts) {
18
+ super(opts)
19
+ opts = opts || {}
20
+
21
+ /** The columns of the time series, ordered in chronological order.
22
+ * @type {Array.<string>} */
23
+ this.ts = opts.ts
24
+
25
+ /** 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.
26
+ * @type {function(string):boolean} */
27
+ this.noData = opts.noData || ((v) => v === undefined || v == '' || v === null || isNaN(+v))
28
+
29
+ //x
30
+ /** in geo unit
31
+ * @type {function(import("../core/Dataset.js").Cell,number,number):number} */
32
+ this.offsetX = opts.offsetX || ((c, r, z) => 0)
33
+ /** @type {function(import("../core/Dataset.js").Cell,number,number):number} */
34
+ this.width = opts.width || ((c, r, z) => r)
35
+
36
+ //y
37
+ /** in geo unit
38
+ * @type {function(import("../core/Dataset.js").Cell,number,number):number} */
39
+ this.offsetY = opts.offsetY || ((c, r, z) => 0)
40
+ /** @type {function(import("../core/Dataset.js").Cell,number,number):number} */
41
+ this.height = opts.height || ((c, r, z) => r)
42
+ /** @type {function(import("../core/Dataset.js").Cell,number,number):AnchorModeYEnum} */
43
+ this.anchorModeY = opts.anchorModeY || ((c, r, z) => 'center')
44
+
45
+ /** A function returning the width of the line, in geo unit
46
+ * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
47
+ this.lineWidth = opts.lineWidth || ((v, r, s, z) => 1.5 * z)
48
+
49
+ /** A function returning the color of the chart.
50
+ * @type {function(import('../core/Dataset.js').Cell, number, number, object):string} */
51
+ this.color = opts.color || (() => 'black') //(c,r,z,vs) => {}
52
+ }
53
+
54
+ /**
55
+ * Draw cells as text.
56
+ *
57
+ * @param {Array.<import("../core/Dataset.js").Cell>} cells
58
+ * @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
59
+ * @param {number} resolution
60
+ */
61
+ draw(cells, geoCanvas, resolution) {
62
+ //filter
63
+ if (this.filter) cells = cells.filter(this.filter)
64
+
65
+ //
66
+ const z = geoCanvas.view.z
67
+ const ctx = geoCanvas.offscreenCtx
68
+
69
+ //get view scale
70
+ const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
71
+
72
+ //compute cell amplitude
73
+ const getAmplitude = (c) => {
74
+ let min, max
75
+ for (let t of this.ts) {
76
+ const val = c[t]
77
+ if (val == undefined) continue
78
+ if (min == undefined || val < min) min = val
79
+ if (max == undefined || val > max) max = val
80
+ }
81
+ if (min == undefined) return undefined
82
+ return max - min
83
+ }
84
+
85
+ //compute max amplitude
86
+ let ampMax
87
+ for (let c of cells) {
88
+ const amp = getAmplitude(c)
89
+ if (amp == undefined) continue
90
+ if (ampMax == undefined || amp > ampMax) ampMax = amp
91
+ }
92
+ if (!ampMax) return
93
+
94
+ const nb = this.ts.length
95
+
96
+ ctx.lineCap = 'butt'
97
+ for (let c of cells) {
98
+ //line width
99
+ /** @type {number|undefined} */
100
+ const wG = this.lineWidth ? this.lineWidth(c, resolution, z, viewScale) : undefined
101
+ if (!wG || wG < 0) continue
102
+
103
+ //line color
104
+ /** @type {string|undefined} */
105
+ const col = this.color ? this.color(c, resolution, z, viewScale) : undefined
106
+ if (!col) continue
107
+
108
+ //x
109
+ const offX = this.offsetX ? this.offsetX(c, resolution, z) : 0
110
+ if (offX == undefined || isNaN(offX)) continue
111
+ const w = this.width ? this.width(c, resolution, z) : resolution
112
+ if (w == undefined || isNaN(w)) continue
113
+
114
+ //y
115
+ const offY = this.offsetY ? this.offsetY(c, resolution, z) : 0
116
+ if (offY == undefined || isNaN(offY)) continue
117
+ const h = this.height ? this.height(c, resolution, z) : resolution
118
+ if (h == undefined || isNaN(h)) continue
119
+ const anchY = this.anchorModeY ? this.anchorModeY(c, resolution, z) : 'center'
120
+ if (!anchY) continue
121
+
122
+ ctx.lineWidth = wG
123
+ ctx.strokeStyle = col
124
+
125
+ //compute anchor Y figures
126
+ let val0, y0
127
+ if (anchY === 'first') {
128
+ //get first value
129
+ val0 = c[this.ts[0]]
130
+ y0 = 0
131
+ } else if (anchY === 'last') {
132
+ //get last value
133
+ val0 = c[this.ts[this.ts.length - 1]]
134
+ y0 = 0
135
+ } else if (anchY === 'bottom') {
136
+ //get min
137
+ for (let t of this.ts) {
138
+ const val = +c[t]
139
+ if (val == undefined) continue
140
+ if (val0 == undefined || val < val0) val0 = val
141
+ }
142
+ y0 = 0
143
+ } else if (anchY === 'top') {
144
+ //get max
145
+ for (let t of this.ts) {
146
+ const val = +c[t]
147
+ if (val == undefined) continue
148
+ if (val0 == undefined || val > val0) val0 = val
149
+ }
150
+ y0 = resolution
151
+ } else if (anchY === 'center') {
152
+ //get min and max
153
+ let min, max
154
+ for (let t of this.ts) {
155
+ const val = c[t]
156
+ if (val == undefined) continue
157
+ if (min == undefined || val < min) min = val
158
+ if (max == undefined || val > max) max = val
159
+ }
160
+ val0 = (+max + +min) * 0.5
161
+ y0 = resolution / 2
162
+ } else {
163
+ console.log('Unexpected anchorModeY: ' + anchY)
164
+ continue
165
+ }
166
+
167
+ /*/draw line
168
+ if (val0 == undefined || isNaN(val0)) continue
169
+ cg.ctx.beginPath()
170
+ const sX = w / (nb - 1)
171
+ for (let i = 0; i < nb; i++) {
172
+ const val = c[this.ts[i]]
173
+ if (val == undefined || isNaN(val)) break
174
+ if (i == 0)
175
+ cg.ctx.moveTo(c.x + i * sX + offX, c.y + y0 + (val - val0) * h / ampMax + offY)
176
+ else
177
+ cg.ctx.lineTo(c.x + i * sX + offX, c.y + y0 + (val - val0) * h / ampMax + offY)
178
+ }
179
+ cg.ctx.stroke()*/
180
+
181
+ //draw line, segment by segment
182
+ const sX = w / (nb - 1)
183
+
184
+ //handle first point
185
+ let v0 = c[this.ts[0]]
186
+ if (!this.noData(v0)) {
187
+ ctx.beginPath()
188
+ ctx.moveTo(c.x + offX, c.y + y0 + ((v0 - val0) * h) / ampMax + offY)
189
+ }
190
+ //console.log(v0, isNaN(v0))
191
+
192
+ let v1
193
+ for (let i = 1; i < nb; i++) {
194
+ v1 = c[this.ts[i]]
195
+
196
+ //draw segment from v0 to v1
197
+
198
+ //both points 'no data'
199
+ if (this.noData(v0) && this.noData(v1)) {
200
+ //second point 'no data'
201
+ } else if (!this.noData(v0) && this.noData(v1)) {
202
+ ctx.stroke()
203
+
204
+ //first point 'no data'
205
+ } else if (this.noData(v0) && !this.noData(v1)) {
206
+ ctx.beginPath()
207
+ ctx.moveTo(c.x + i * sX + offX, c.y + y0 + ((v1 - val0) * h) / ampMax + offY)
208
+
209
+ //both points have data: trace line
210
+ } else {
211
+ ctx.lineTo(c.x + i * sX + offX, c.y + y0 + ((v1 - val0) * h) / ampMax + offY)
212
+ //if it is the last point, stroke
213
+ if (i == nb - 1) ctx.stroke()
214
+ }
215
+ v0 = v1
216
+ }
217
+ }
218
+
219
+ //update legend, if any
220
+ this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
221
+ }
222
+ }