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,296 +1,296 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- /** @typedef {{ dims: object, crs: string, tileSizeCell: number, originPoint: {x:number,y:number}, resolutionGeo: number, tilingBounds:import("../Dataset").Envelope, format:import("../DatasetComponent").Format }} GridInfo */
5
-
6
- // internal
7
- import { GridTile } from './GridTile.js'
8
- import { App } from '../App.js'
9
- import { DatasetComponent } from '../DatasetComponent.js'
10
- import { monitor, monitorDuration } from '../utils/Utils.js'
11
-
12
- // external
13
- import { json, csv } from 'd3-fetch'
14
- import { tableFromIPC } from 'apache-arrow'
15
-
16
- /**
17
- * A tiled dataset, composed of CSV (or parquet) tiles.
18
- *
19
- * @author Joseph Davies, Julien Gaffuri
20
- */
21
- export class TiledGrid extends DatasetComponent {
22
- /**
23
- * @param {string} url The URL of the dataset.
24
- * @param {App} app The application.
25
- * @param {{preprocess?:(function(import("../Dataset").Cell):boolean), readParquetFun?:Function }} opts
26
- */
27
- constructor(url, app, opts = {}) {
28
- super(url, 0, opts)
29
-
30
- /**
31
- * The app being used.
32
- * @type {App}
33
- */
34
- this.app = app
35
-
36
- /**
37
- * The grid info object, from the info.json file.
38
- * @type {GridInfo | undefined}
39
- * @private
40
- * */
41
- this.info = undefined
42
-
43
- /**
44
- * @type {string}
45
- * @private */
46
- this.infoLoadingStatus = 'notLoaded'
47
-
48
- /**
49
- * The cache of the loaded tiles. It is double indexed: by xT and then yT.
50
- * Example: this.cache[xT][yT] returns the tile at [xT][yT] location.
51
- *
52
- * @type {object}
53
- * */
54
- this.cache = {}
55
-
56
- /**
57
- * @type {Function|undefined}
58
- * @private */
59
- this.readParquetFun = opts.readParquetFun
60
- }
61
-
62
- /**
63
- * Load the info.json from the url.
64
- *
65
- * @param {function():void} callback
66
- * @returns this
67
- */
68
- loadInfo(callback) {
69
- if (!this.info && this.infoLoadingStatus === 'notLoaded') {
70
- ;(async () => {
71
- try {
72
- const data = await json(this.url + 'info.json')
73
- this.info = data
74
- this.resolution = data.resolutionGeo
75
- this.infoLoadingStatus = 'loaded'
76
- if (callback) callback()
77
- } catch (error) {
78
- //mark as failed
79
- this.infoLoadingStatus = 'failed'
80
- }
81
- })()
82
- } else if (callback && (this.infoLoadingStatus === 'loaded' || this.infoLoadingStatus === 'failed'))
83
- callback()
84
- return this
85
- }
86
-
87
- /**
88
- * Compute a tiling envelope from a geographical envelope.
89
- * This is the function to use to know which tiles to download for a geographical view.
90
- *
91
- * @param {import("../Dataset").Envelope} e
92
- * @returns {import("../Dataset").Envelope|undefined}
93
- */
94
- getTilingEnvelope(e) {
95
- if (!this.info) {
96
- this.loadInfo(() => {})
97
- return
98
- }
99
-
100
- const po = this.info.originPoint,
101
- r = this.info.resolutionGeo,
102
- s = this.info.tileSizeCell
103
-
104
- return {
105
- xMin: Math.floor((e.xMin - po.x) / (r * s)),
106
- xMax: Math.floor((e.xMax - po.x) / (r * s)),
107
- yMin: Math.floor((e.yMin - po.y) / (r * s)),
108
- yMax: Math.floor((e.yMax - po.y) / (r * s)),
109
- }
110
- }
111
-
112
- /**
113
- * Request data within a geographic envelope.
114
- *
115
- * @param {import("../Dataset").Envelope} extGeo
116
- * @param {function():void} redrawFun
117
- * @returns {this}
118
- */
119
- getData(extGeo, redrawFun) {
120
- //TODO empty cache when it gets too big ?
121
-
122
- //check if info has been loaded
123
- if (!this.info) return this
124
-
125
- //tiles within the scope
126
- /** @type {import("../Dataset").Envelope|undefined} */
127
- const tb = this.getTilingEnvelope(extGeo)
128
- if (!tb) return this
129
-
130
- //grid bounds
131
- /** @type {import("../Dataset").Envelope} */
132
- const gb = this.info.tilingBounds
133
-
134
- const format = this.info.format
135
-
136
- for (let xT = Math.max(tb.xMin, gb.xMin); xT <= Math.min(tb.xMax, gb.xMax); xT++) {
137
- for (let yT = Math.max(tb.yMin, gb.yMin); yT <= Math.min(tb.yMax, gb.yMax); yT++) {
138
- //prepare cache
139
- if (!this.cache[xT]) this.cache[xT] = {}
140
-
141
- //check if tile exists in the cache
142
- /** @type {GridTile} */
143
- let tile = this.cache[xT][yT]
144
- if (tile) continue
145
-
146
- //mark tile as loading
147
- this.cache[xT][yT] = 'loading'
148
- ;(async () => {
149
- //request tile
150
- /** @type {Array.<import("../Dataset").Cell>} */
151
- let cells
152
-
153
- try {
154
- if (!format || format === 'CSV') {
155
- /** @type {Array.<import("../Dataset").Cell>} */
156
- // @ts-ignore
157
- const data = await csv(this.url + xT + '/' + yT + '.csv')
158
-
159
- if (monitor) monitorDuration('*** TiledGrid parse start')
160
-
161
- //preprocess/filter
162
- if (this.preprocess) {
163
- cells = []
164
- for (const c of data) {
165
- const b = this.preprocess(c)
166
- if (b == false) continue
167
- cells.push(c)
168
- }
169
- } else {
170
- cells = data
171
- }
172
-
173
- if (monitor) monitorDuration('preprocess / filter')
174
- } else if (format === 'PARQUET') {
175
- if (!this.readParquetFun)
176
- throw new Error('readParquet function needed for parquet dataset')
177
-
178
- const resp = await fetch(this.url + xT + '/' + yT + '.parquet')
179
- const parquetUint8Array = new Uint8Array(await resp.arrayBuffer())
180
- const arrowUint8Array = this.readParquetFun(parquetUint8Array)
181
- const t = tableFromIPC(arrowUint8Array)
182
-
183
- cells = []
184
- for (const e of t) {
185
- //get cell
186
- const c = e.toJSON()
187
-
188
- //preprocess/filter
189
- if (this.preprocess) {
190
- const b = this.preprocess(c)
191
- if (b == false) continue
192
- cells.push(c)
193
- } else {
194
- cells.push(c)
195
- }
196
- }
197
- } else throw new Error('Tiled format not supported: ' + format)
198
- } catch (error) {
199
- //mark as failed
200
- this.cache[xT][yT] = 'failed'
201
- return
202
- }
203
-
204
- //store tile in cache
205
- if (!this.info) {
206
- console.error('Tile info inknown')
207
- return
208
- }
209
- const tile_ = new GridTile(cells, xT, yT, this.info)
210
- this.cache[xT][yT] = tile_
211
-
212
- if (monitor) monitorDuration('storage')
213
-
214
- //if no redraw is specified, then leave
215
- if (!redrawFun) return
216
-
217
- //check if redraw is really needed, that is if:
218
-
219
- // 1. the dataset belongs to a layer which is visible at the current zoom level
220
- let redraw = false
221
- //go through the layers
222
- const zf = this.app.getZoomFactor()
223
- for (const lay of this.app.layers) {
224
- if (!lay.visible) continue
225
- if (lay.getDatasetComponent(zf) != this) continue
226
- //found one layer. No need to seek more.
227
- redraw = true
228
- break
229
- }
230
- if (monitor) monitorDuration('check redraw 1')
231
-
232
- if (!redraw) return
233
-
234
- // 2. the tile is within the view, that is its geo envelope intersects the viewer geo envelope.
235
- const env = this.app.updateExtentGeo()
236
- const envT = tile_.extGeo
237
- if (env.xMax <= envT.xMin) return
238
- if (env.xMin >= envT.xMax) return
239
- if (env.yMax <= envT.yMin) return
240
- if (env.yMin >= envT.yMax) return
241
-
242
- if (monitor) monitorDuration('check redraw 2')
243
- if (monitor) monitorDuration('*** TiledGrid parse end')
244
-
245
- //redraw
246
- redrawFun()
247
- })()
248
- }
249
- }
250
- return this
251
- }
252
-
253
- /**
254
- * Fill the view cache with all cells which are within a geographical envelope.
255
- * @abstract
256
- * @param {import("../Dataset").Envelope} extGeo
257
- * @returns {void}
258
- */
259
- updateViewCache(extGeo) {
260
- //
261
- this.cellsViewCache = []
262
-
263
- //check if info has been loaded
264
- if (!this.info) return
265
-
266
- //tiles within the scope
267
- /** @type {import("../Dataset").Envelope|undefined} */
268
- const tb = this.getTilingEnvelope(extGeo)
269
- if (!tb) return
270
-
271
- //grid bounds
272
- /** @type {import("../Dataset").Envelope} */
273
- const gb = this.info.tilingBounds
274
-
275
- for (let xT = Math.max(tb.xMin, gb.xMin); xT <= Math.min(tb.xMax, gb.xMax); xT++) {
276
- if (!this.cache[xT]) continue
277
- for (let yT = Math.max(tb.yMin, gb.yMin); yT <= Math.min(tb.yMax, gb.yMax); yT++) {
278
- //get tile
279
- /** @type {GridTile} */
280
- const tile = this.cache[xT][yT]
281
- if (!tile || typeof tile === 'string') continue
282
-
283
- //get cells
284
- //this.cellsViewCache = this.cellsViewCache.concat(tile.cells)
285
-
286
- for (const cell of tile.cells) {
287
- if (+cell.x + this.resolution < extGeo.xMin) continue
288
- if (+cell.x - this.resolution > extGeo.xMax) continue
289
- if (+cell.y + this.resolution < extGeo.yMin) continue
290
- if (+cell.y - this.resolution > extGeo.yMax) continue
291
- this.cellsViewCache.push(cell)
292
- }
293
- }
294
- }
295
- }
296
- }
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ /** @typedef {{ dims: object, crs: string, tileSizeCell: number, originPoint: {x:number,y:number}, resolutionGeo: number, tilingBounds:import("../Dataset").Envelope, format:import("../DatasetComponent").Format }} GridInfo */
5
+
6
+ // internal
7
+ import { GridTile } from './GridTile.js'
8
+ import { App } from '../App.js'
9
+ import { DatasetComponent } from '../DatasetComponent.js'
10
+ import { monitor, monitorDuration } from '../utils/Utils.js'
11
+
12
+ // external
13
+ import { json, csv } from 'd3-fetch'
14
+ import { tableFromIPC } from 'apache-arrow'
15
+
16
+ /**
17
+ * A tiled dataset, composed of CSV (or parquet) tiles.
18
+ *
19
+ * @author Joseph Davies, Julien Gaffuri
20
+ */
21
+ export class TiledGrid extends DatasetComponent {
22
+ /**
23
+ * @param {string} url The URL of the dataset.
24
+ * @param {App} app The application.
25
+ * @param {{preprocess?:(function(import("../Dataset").Cell):boolean), readParquetFun?:Function }} opts
26
+ */
27
+ constructor(url, app, opts = {}) {
28
+ super(url, 0, opts)
29
+
30
+ /**
31
+ * The app being used.
32
+ * @type {App}
33
+ */
34
+ this.app = app
35
+
36
+ /**
37
+ * The grid info object, from the info.json file.
38
+ * @type {GridInfo | undefined}
39
+ * @private
40
+ * */
41
+ this.info = undefined
42
+
43
+ /**
44
+ * @type {string}
45
+ * @private */
46
+ this.infoLoadingStatus = 'notLoaded'
47
+
48
+ /**
49
+ * The cache of the loaded tiles. It is double indexed: by xT and then yT.
50
+ * Example: this.cache[xT][yT] returns the tile at [xT][yT] location.
51
+ *
52
+ * @type {object}
53
+ * */
54
+ this.cache = {}
55
+
56
+ /**
57
+ * @type {Function|undefined}
58
+ * @private */
59
+ this.readParquetFun = opts.readParquetFun
60
+ }
61
+
62
+ /**
63
+ * Load the info.json from the url.
64
+ *
65
+ * @param {function():void} callback
66
+ * @returns this
67
+ */
68
+ loadInfo(callback) {
69
+ if (!this.info && this.infoLoadingStatus === 'notLoaded') {
70
+ ;(async () => {
71
+ try {
72
+ const data = await json(this.url + 'info.json')
73
+ this.info = data
74
+ this.resolution = data.resolutionGeo
75
+ this.infoLoadingStatus = 'loaded'
76
+ if (callback) callback()
77
+ } catch (error) {
78
+ //mark as failed
79
+ this.infoLoadingStatus = 'failed'
80
+ }
81
+ })()
82
+ } else if (callback && (this.infoLoadingStatus === 'loaded' || this.infoLoadingStatus === 'failed'))
83
+ callback()
84
+ return this
85
+ }
86
+
87
+ /**
88
+ * Compute a tiling envelope from a geographical envelope.
89
+ * This is the function to use to know which tiles to download for a geographical view.
90
+ *
91
+ * @param {import("../Dataset").Envelope} e
92
+ * @returns {import("../Dataset").Envelope|undefined}
93
+ */
94
+ getTilingEnvelope(e) {
95
+ if (!this.info) {
96
+ this.loadInfo(() => {})
97
+ return
98
+ }
99
+
100
+ const po = this.info.originPoint,
101
+ r = this.info.resolutionGeo,
102
+ s = this.info.tileSizeCell
103
+
104
+ return {
105
+ xMin: Math.floor((e.xMin - po.x) / (r * s)),
106
+ xMax: Math.floor((e.xMax - po.x) / (r * s)),
107
+ yMin: Math.floor((e.yMin - po.y) / (r * s)),
108
+ yMax: Math.floor((e.yMax - po.y) / (r * s)),
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Request data within a geographic envelope.
114
+ *
115
+ * @param {import("../Dataset").Envelope} extGeo
116
+ * @param {function():void} redrawFun
117
+ * @returns {this}
118
+ */
119
+ getData(extGeo, redrawFun) {
120
+ //TODO empty cache when it gets too big ?
121
+
122
+ //check if info has been loaded
123
+ if (!this.info) return this
124
+
125
+ //tiles within the scope
126
+ /** @type {import("../Dataset").Envelope|undefined} */
127
+ const tb = this.getTilingEnvelope(extGeo)
128
+ if (!tb) return this
129
+
130
+ //grid bounds
131
+ /** @type {import("../Dataset").Envelope} */
132
+ const gb = this.info.tilingBounds
133
+
134
+ const format = this.info.format
135
+
136
+ for (let xT = Math.max(tb.xMin, gb.xMin); xT <= Math.min(tb.xMax, gb.xMax); xT++) {
137
+ for (let yT = Math.max(tb.yMin, gb.yMin); yT <= Math.min(tb.yMax, gb.yMax); yT++) {
138
+ //prepare cache
139
+ if (!this.cache[xT]) this.cache[xT] = {}
140
+
141
+ //check if tile exists in the cache
142
+ /** @type {GridTile} */
143
+ let tile = this.cache[xT][yT]
144
+ if (tile) continue
145
+
146
+ //mark tile as loading
147
+ this.cache[xT][yT] = 'loading'
148
+ ;(async () => {
149
+ //request tile
150
+ /** @type {Array.<import("../Dataset").Cell>} */
151
+ let cells
152
+
153
+ try {
154
+ if (!format || format === 'CSV') {
155
+ /** @type {Array.<import("../Dataset").Cell>} */
156
+ // @ts-ignore
157
+ const data = await csv(this.url + xT + '/' + yT + '.csv')
158
+
159
+ if (monitor) monitorDuration('*** TiledGrid parse start')
160
+
161
+ //preprocess/filter
162
+ if (this.preprocess) {
163
+ cells = []
164
+ for (const c of data) {
165
+ const b = this.preprocess(c)
166
+ if (b == false) continue
167
+ cells.push(c)
168
+ }
169
+ } else {
170
+ cells = data
171
+ }
172
+
173
+ if (monitor) monitorDuration('preprocess / filter')
174
+ } else if (format === 'PARQUET') {
175
+ if (!this.readParquetFun)
176
+ throw new Error('readParquet function needed for parquet dataset')
177
+
178
+ const resp = await fetch(this.url + xT + '/' + yT + '.parquet')
179
+ const parquetUint8Array = new Uint8Array(await resp.arrayBuffer())
180
+ const arrowUint8Array = this.readParquetFun(parquetUint8Array)
181
+ const t = tableFromIPC(arrowUint8Array)
182
+
183
+ cells = []
184
+ for (const e of t) {
185
+ //get cell
186
+ const c = e.toJSON()
187
+
188
+ //preprocess/filter
189
+ if (this.preprocess) {
190
+ const b = this.preprocess(c)
191
+ if (b == false) continue
192
+ cells.push(c)
193
+ } else {
194
+ cells.push(c)
195
+ }
196
+ }
197
+ } else throw new Error('Tiled format not supported: ' + format)
198
+ } catch (error) {
199
+ //mark as failed
200
+ this.cache[xT][yT] = 'failed'
201
+ return
202
+ }
203
+
204
+ //store tile in cache
205
+ if (!this.info) {
206
+ console.error('Tile info inknown')
207
+ return
208
+ }
209
+ const tile_ = new GridTile(cells, xT, yT, this.info)
210
+ this.cache[xT][yT] = tile_
211
+
212
+ if (monitor) monitorDuration('storage')
213
+
214
+ //if no redraw is specified, then leave
215
+ if (!redrawFun) return
216
+
217
+ //check if redraw is really needed, that is if:
218
+
219
+ // 1. the dataset belongs to a layer which is visible at the current zoom level
220
+ let redraw = false
221
+ //go through the layers
222
+ const zf = this.app.getZoomFactor()
223
+ for (const lay of this.app.layers) {
224
+ if (!lay.visible) continue
225
+ if (lay.getDatasetComponent(zf) != this) continue
226
+ //found one layer. No need to seek more.
227
+ redraw = true
228
+ break
229
+ }
230
+ if (monitor) monitorDuration('check redraw 1')
231
+
232
+ if (!redraw) return
233
+
234
+ // 2. the tile is within the view, that is its geo envelope intersects the viewer geo envelope.
235
+ const env = this.app.updateExtentGeo()
236
+ const envT = tile_.extGeo
237
+ if (env.xMax <= envT.xMin) return
238
+ if (env.xMin >= envT.xMax) return
239
+ if (env.yMax <= envT.yMin) return
240
+ if (env.yMin >= envT.yMax) return
241
+
242
+ if (monitor) monitorDuration('check redraw 2')
243
+ if (monitor) monitorDuration('*** TiledGrid parse end')
244
+
245
+ //redraw
246
+ redrawFun()
247
+ })()
248
+ }
249
+ }
250
+ return this
251
+ }
252
+
253
+ /**
254
+ * Fill the view cache with all cells which are within a geographical envelope.
255
+ * @abstract
256
+ * @param {import("../Dataset").Envelope} extGeo
257
+ * @returns {void}
258
+ */
259
+ updateViewCache(extGeo) {
260
+ //
261
+ this.cellsViewCache = []
262
+
263
+ //check if info has been loaded
264
+ if (!this.info) return
265
+
266
+ //tiles within the scope
267
+ /** @type {import("../Dataset").Envelope|undefined} */
268
+ const tb = this.getTilingEnvelope(extGeo)
269
+ if (!tb) return
270
+
271
+ //grid bounds
272
+ /** @type {import("../Dataset").Envelope} */
273
+ const gb = this.info.tilingBounds
274
+
275
+ for (let xT = Math.max(tb.xMin, gb.xMin); xT <= Math.min(tb.xMax, gb.xMax); xT++) {
276
+ if (!this.cache[xT]) continue
277
+ for (let yT = Math.max(tb.yMin, gb.yMin); yT <= Math.min(tb.yMax, gb.yMax); yT++) {
278
+ //get tile
279
+ /** @type {GridTile} */
280
+ const tile = this.cache[xT][yT]
281
+ if (!tile || typeof tile === 'string') continue
282
+
283
+ //get cells
284
+ //this.cellsViewCache = this.cellsViewCache.concat(tile.cells)
285
+
286
+ for (const cell of tile.cells) {
287
+ if (+cell.x + this.resolution < extGeo.xMin) continue
288
+ if (+cell.x - this.resolution > extGeo.xMax) continue
289
+ if (+cell.y + this.resolution < extGeo.yMin) continue
290
+ if (+cell.y - this.resolution > extGeo.yMax) continue
291
+ this.cellsViewCache.push(cell)
292
+ }
293
+ }
294
+ }
295
+ }
296
+ }