gridviz 3.0.35 → 3.0.37

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 (67) hide show
  1. package/README.md +129 -129
  2. package/dist/gridviz.js +21056 -17487
  3. package/dist/gridviz.min.js +2 -2
  4. package/package.json +74 -74
  5. package/src/button/Button.js +67 -67
  6. package/src/button/FullscreenButton.js +121 -121
  7. package/src/button/ZoomButtons.js +103 -103
  8. package/src/core/Dataset.js +232 -154
  9. package/src/core/Drawable.js +78 -78
  10. package/src/core/GeoCanvas.js +443 -443
  11. package/src/core/Layer.js +23 -23
  12. package/src/core/Legend.js +108 -108
  13. package/src/core/Map.js +650 -568
  14. package/src/core/MultiResolutionDataset.js +93 -93
  15. package/src/core/Style.js +98 -98
  16. package/src/core/Tooltip.js +182 -182
  17. package/src/dataset/COGeo.js +25 -25
  18. package/src/dataset/CSVGrid.js +112 -112
  19. package/src/dataset/GeoTIFF.js +122 -122
  20. package/src/dataset/JSGrid.js +55 -55
  21. package/src/dataset/TiledGrid.js +311 -302
  22. package/src/dataset/worker.js +18 -18
  23. package/src/index.js +79 -79
  24. package/src/layer/BackgroundLayer.js +173 -173
  25. package/src/layer/BackgroundLayerImage.js +81 -81
  26. package/src/layer/BackgroundLayerWMS.js +104 -104
  27. package/src/layer/GeoJSONLayer.js +276 -276
  28. package/src/layer/GridLayer.js +166 -166
  29. package/src/layer/LabelLayer.js +194 -194
  30. package/src/legend/ColorCategoryLegend.js +109 -109
  31. package/src/legend/ColorDiscreteLegend.js +100 -100
  32. package/src/legend/ColorLegend.js +115 -115
  33. package/src/legend/OrientationLegend.js +89 -89
  34. package/src/legend/SizeLegend.js +224 -224
  35. package/src/legend/TernaryLegend.js +302 -302
  36. package/src/style/CompositionStyle.js +291 -291
  37. package/src/style/DotDensityStyle.js +133 -133
  38. package/src/style/ImageStyle.js +100 -100
  39. package/src/style/Interpolator.js +258 -258
  40. package/src/style/IsoFenceStyle.js +217 -217
  41. package/src/style/JoyPlotStyle.js +180 -180
  42. package/src/style/LegoStyle.js +132 -132
  43. package/src/style/MosaicStyle.js +99 -99
  44. package/src/style/NinjaStarStyle.js +102 -102
  45. package/src/style/PillarStyle.js +207 -207
  46. package/src/style/SegmentStyle.js +105 -105
  47. package/src/style/ShadingRayStyle.js +280 -280
  48. package/src/style/ShadingStyle.js +72 -72
  49. package/src/style/ShapeColorSizeStyle.js +147 -147
  50. package/src/style/SideCategoryStyle.js +112 -112
  51. package/src/style/SideStyle.js +217 -217
  52. package/src/style/SideTanakaStyle.js +154 -154
  53. package/src/style/SquareColorCategoryWebGLStyle.js +311 -294
  54. package/src/style/SquareColorWebGLStyle.js +126 -126
  55. package/src/style/StrokeStyle.js +135 -135
  56. package/src/style/TextStyle.js +110 -110
  57. package/src/style/TimeSeriesStyle.js +222 -222
  58. package/src/utils/WebGLRectangleColoring.js +106 -106
  59. package/src/utils/WebGLSquareColoring.js +114 -118
  60. package/src/utils/WebGLSquareColoringAdvanced.js +223 -227
  61. package/src/utils/WebGLSquareColoringKS.js +153 -153
  62. package/src/utils/scale.js +255 -255
  63. package/src/utils/stretching.js +120 -120
  64. package/src/utils/ternary.js +208 -208
  65. package/src/utils/utils.js +125 -125
  66. package/src/utils/webGLUtils.js +178 -73
  67. package/src/utils/zoomUtils.js +142 -142
@@ -1,302 +1,311 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- /** @typedef {{ dims: object, crs: string, tileSizeCell: number, originPoint: {x:number,y:number}, resolutionGeo: number, tilingBounds:import("../core/GeoCanvas.js").Envelope }} GridInfo */
5
-
6
- // internal
7
- import { Dataset } from '../core/Dataset.js'
8
- //import { monitor, monitorDuration } from '../utils/Utils.js'
9
-
10
- // external
11
- import { json, csv } from 'd3-fetch'
12
-
13
- /**
14
- * A tiled dataset, composed of CSV tiles.
15
- *
16
- * @module dataset
17
- * @author Joseph Davies, Julien Gaffuri
18
- */
19
- export class TiledGrid extends Dataset {
20
- /**
21
- * @param {import("../core/Map.js").Map} map The map.
22
- * @param {string} url The URL of the dataset.
23
- * @param {{preprocess?:(function(import("../core/Dataset.js").Cell):boolean), onlyDrawWhenAllTilesReady:boolean}} opts
24
- */
25
- constructor(map, url, opts = {}) {
26
- super(map, url, 0, opts)
27
- this.onlyDrawWhenAllTilesReady = opts.onlyDrawWhenAllTilesReady || false
28
- /**
29
- * The grid info object, from the info.json file.
30
- * @type {GridInfo | undefined}
31
- * @private
32
- * */
33
- this.info = undefined
34
-
35
- /**
36
- * @type {string}
37
- * @private */
38
- this.infoLoadingStatus = 'notLoaded'
39
-
40
- /**
41
- * The cache of the loaded tiles. It is double indexed: by xT and then yT.
42
- * Example: this.cache[xT][yT] returns the tile at [xT][yT] location.
43
- *
44
- * @type {object}
45
- * */
46
- this.cache = {}
47
-
48
- //launch loading
49
- this.loadInfo()
50
- }
51
-
52
- /**
53
- * Load the info.json from the url.
54
- * @returns this
55
- */
56
- loadInfo() {
57
- if (!this.info && this.infoLoadingStatus === 'notLoaded') {
58
- ;(async () => {
59
- try {
60
- const data = await json(this.url + 'info.json')
61
- this.info = data
62
- this.resolution = data.resolutionGeo
63
- this.infoLoadingStatus = 'loaded'
64
- this.map.redraw()
65
- } catch (error) {
66
- //mark as failed
67
- this.infoLoadingStatus = 'failed'
68
- }
69
- })()
70
- } else if (this.infoLoadingStatus === 'loaded' || this.infoLoadingStatus === 'failed') this.map.redraw()
71
- return this
72
- }
73
-
74
- /**
75
- * Compute a tiling envelope from a geographical envelope.
76
- * This is the function to use to know which tiles to download for a geographical view.
77
- *
78
- * @param {import("../core/GeoCanvas.js").Envelope} e
79
- * @returns {import("../core/GeoCanvas.js").Envelope|undefined}
80
- */
81
- getTilingEnvelope(e) {
82
- if (!this.info) {
83
- this.loadInfo()
84
- return
85
- }
86
-
87
- const po = this.info.originPoint,
88
- r = this.info.resolutionGeo,
89
- s = this.info.tileSizeCell
90
-
91
- return {
92
- xMin: Math.floor((e.xMin - po.x) / (r * s)),
93
- xMax: Math.floor((e.xMax - po.x) / (r * s)),
94
- yMin: Math.floor((e.yMin - po.y) / (r * s)),
95
- yMax: Math.floor((e.yMax - po.y) / (r * s)),
96
- }
97
- }
98
-
99
- /**
100
- * Request data within a geographic envelope.
101
- *
102
- * @param {import('../core/GeoCanvas.js').Envelope} extGeo
103
- * @returns {this}
104
- */
105
- async getData(extGeo) {
106
- if (!this.info) return this
107
-
108
- // Create an AbortController for the current data request
109
- this.abortController = new AbortController()
110
- const signal = this.abortController.signal
111
-
112
- // Get the tiling envelope and check bounds
113
- const tb = this.getTilingEnvelope(extGeo)
114
- if (!tb) return this
115
-
116
- const { xMin: gbXMin, xMax: gbXMax, yMin: gbYMin, yMax: gbYMax } = this.info.tilingBounds
117
-
118
- const xMin = Math.max(tb.xMin, gbXMin)
119
- const xMax = Math.min(tb.xMax, gbXMax)
120
- const yMin = Math.max(tb.yMin, gbYMin)
121
- const yMax = Math.min(tb.yMax, gbYMax)
122
-
123
- const totalTiles = (xMax - xMin + 1) * (yMax - yMin + 1)
124
- let processedTiles = 0
125
- const tilePromises = []
126
-
127
- // Iterate over tiles within bounds
128
- for (let xT = xMin; xT <= xMax; xT++) {
129
- for (let yT = yMin; yT <= yMax; yT++) {
130
- if (!this.cache[xT]) this.cache[xT] = {}
131
-
132
- // Skip already loaded tiles or retry failed ones
133
- if (this.cache[xT][yT] && this.cache[xT][yT] !== 'failed') {
134
- ++processedTiles
135
- continue
136
- }
137
-
138
- // Mark tile as loading
139
- this.cache[xT][yT] = 'loading'
140
-
141
- tilePromises.push(
142
- this.loadTile(xT, yT, signal)
143
- .then((tile) => {
144
- this.cache[xT][yT] = tile
145
-
146
- // Check if this is the last tile
147
- const isLastTile = ++processedTiles === totalTiles
148
- this.checkAndRedraw(tile, isLastTile)
149
- })
150
- .catch(() => {
151
- this.cache[xT][yT] = 'failed'
152
- ++processedTiles
153
- })
154
- )
155
- }
156
- }
157
-
158
- await Promise.allSettled(tilePromises)
159
- return this
160
- }
161
-
162
- /**
163
- * Load a tile.
164
- *
165
- * @param {number} xT
166
- * @param {number} yT
167
- * @param {AbortSignal} signal
168
- * @returns {Promise<any>}
169
- */
170
- async loadTile(xT, yT, signal) {
171
- try {
172
- const data = await csv(`${this.url}${xT}/${yT}.csv`, { signal })
173
-
174
- const cells = this.preprocess ? data.filter((cell) => this.preprocess(cell) !== false) : data
175
-
176
- if (!this.info) throw new Error('Tile info unknown')
177
-
178
- return getGridTile(cells, xT, yT, this.info)
179
- } catch (error) {
180
- if (error.name === 'AbortError') {
181
- console.warn(`Tile request for ${xT}, ${yT} was aborted.`)
182
- }
183
- throw error
184
- }
185
- }
186
-
187
- /**
188
- * Cancel ongoing data requests when zoom level changes.
189
- */
190
- cancelCurrentRequests() {
191
- if (this.abortController) {
192
- this.abortController.abort()
193
- }
194
- }
195
-
196
- checkAndRedraw(tile, isLastTile) {
197
- // Check if any visible layer depends on this dataset
198
- // check if redraw is really needed, that is if:
199
- // 1. the dataset belongs to a layer which is visible at the current zoom level
200
- let needsRedraw = false
201
- //go through the layers
202
- const z = this.map.getZoom()
203
- for (const lay of this.map.layers) {
204
- if (lay.visible && !lay.visible(z)) continue
205
- if (!lay.getDataset) continue
206
- if (lay.getDataset(z) != this) continue
207
- //found one layer. No need to seek more.
208
- needsRedraw = true
209
- break
210
- }
211
-
212
- if (!needsRedraw) return
213
-
214
- // Check if tile intersects the current view
215
- const env = this.map.updateExtentGeo()
216
- const { xMin, xMax, yMin, yMax } = tile.extGeo
217
- if (env.xMax <= xMin || env.xMin >= xMax || env.yMax <= yMin || env.yMin >= yMax) return
218
-
219
- // Trigger redraw
220
- if (this.onlyDrawWhenAllTilesReady) {
221
- if (isLastTile) {
222
- this.map.redraw()
223
- }
224
- } else {
225
- this.map.redraw()
226
- }
227
- }
228
-
229
- /**
230
- * Fill the view cache with all cells which are within a geographical envelope.
231
- * @abstract
232
- * @param {import("../core/GeoCanvas.js").Envelope} extGeo
233
- * @returns {void}
234
- */
235
- updateViewCache(extGeo) {
236
- //
237
- this.cellsViewCache = []
238
-
239
- //check if info has been loaded
240
- if (!this.info) return
241
-
242
- //tiles within the scope
243
- /** @type {import("../core/GeoCanvas.js").Envelope|undefined} */
244
- const tb = this.getTilingEnvelope(extGeo)
245
- if (!tb) return
246
-
247
- //grid bounds
248
- /** @type {import("../core/GeoCanvas.js").Envelope} */
249
- const gb = this.info.tilingBounds
250
-
251
- for (let xT = Math.max(tb.xMin, gb.xMin); xT <= Math.min(tb.xMax, gb.xMax); xT++) {
252
- if (!this.cache[xT]) continue
253
- for (let yT = Math.max(tb.yMin, gb.yMin); yT <= Math.min(tb.yMax, gb.yMax); yT++) {
254
- //get tile
255
- /** @type {object} */
256
- const tile = this.cache[xT][yT]
257
- if (!tile || typeof tile === 'string') continue
258
-
259
- //get cells
260
- //this.cellsViewCache = this.cellsViewCache.concat(tile.cells)
261
-
262
- for (const cell of tile.cells) {
263
- if (+cell.x + this.resolution < extGeo.xMin) continue
264
- if (+cell.x - this.resolution > extGeo.xMax) continue
265
- if (+cell.y + this.resolution < extGeo.yMin) continue
266
- if (+cell.y - this.resolution > extGeo.yMax) continue
267
- this.cellsViewCache.push(cell)
268
- }
269
- }
270
- }
271
- }
272
- }
273
-
274
- function getGridTile(cells, xT, yT, gridInfo) {
275
- const tile = {}
276
-
277
- /** @type {Array.<import("../core/Dataset").Cell>} */
278
- tile.cells = cells
279
- /** @type {number} */
280
- tile.x = xT
281
- /** @type {number} */
282
- tile.y = yT
283
-
284
- const r = gridInfo.resolutionGeo
285
- const s = gridInfo.tileSizeCell
286
-
287
- /** @type {import("../core/GeoCanvas").Envelope} */
288
- tile.extGeo = {
289
- xMin: gridInfo.originPoint.x + r * s * tile.x,
290
- xMax: gridInfo.originPoint.x + r * s * (tile.x + 1),
291
- yMin: gridInfo.originPoint.y + r * s * tile.y,
292
- yMax: gridInfo.originPoint.y + r * s * (tile.y + 1),
293
- }
294
-
295
- //convert cell coordinates into geographical coordinates
296
- for (let cell of tile.cells) {
297
- cell.x = tile.extGeo.xMin + cell.x * r
298
- cell.y = tile.extGeo.yMin + cell.y * r
299
- }
300
-
301
- return tile
302
- }
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ /** @typedef {{ dims: object, crs: string, tileSizeCell: number, originPoint: {x:number,y:number}, resolutionGeo: number, tilingBounds:import("../core/GeoCanvas.js").Envelope }} GridInfo */
5
+
6
+ // internal
7
+ import { Dataset } from '../core/Dataset.js'
8
+ //import { monitor, monitorDuration } from '../utils/Utils.js'
9
+
10
+ // external
11
+ import { json, csv } from 'd3-fetch'
12
+
13
+ /**
14
+ * A tiled dataset, composed of CSV tiles.
15
+ *
16
+ * @module dataset
17
+ * @author Joseph Davies, Julien Gaffuri
18
+ */
19
+ export class TiledGrid extends Dataset {
20
+ /**
21
+ * @param {import("../core/Map.js").Map} map The map.
22
+ * @param {string} url The URL of the dataset.
23
+ * @param {{preprocess?:(function(import("../core/Dataset.js").Cell):boolean), onlyDrawWhenAllTilesReady:boolean}} opts
24
+ */
25
+ constructor(map, url, opts = {}) {
26
+ super(map, url, 0, opts)
27
+ this.onlyDrawWhenAllTilesReady = opts.onlyDrawWhenAllTilesReady || false
28
+ /**
29
+ * The grid info object, from the info.json file.
30
+ * @type {GridInfo | undefined}
31
+ * @private
32
+ * */
33
+ this.info = undefined
34
+
35
+ /**
36
+ * @type {string}
37
+ * @private */
38
+ this.infoLoadingStatus = 'notLoaded'
39
+
40
+ /**
41
+ * The cache of the loaded tiles. It is double indexed: by xT and then yT.
42
+ * Example: this.cache[xT][yT] returns the tile at [xT][yT] location.
43
+ *
44
+ * @type {object}
45
+ * */
46
+ this.cache = {}
47
+
48
+ //launch loading
49
+ this.loadInfo()
50
+ }
51
+
52
+ /**
53
+ * Load the info.json from the url.
54
+ * @returns this
55
+ */
56
+ loadInfo() {
57
+ if (!this.info && this.infoLoadingStatus === 'notLoaded') {
58
+ // marked before the request, so the redraws that happen while it's under way
59
+ // don't request it again
60
+ this.infoLoadingStatus = 'loading'
61
+ ;(async () => {
62
+ try {
63
+ const data = await json(this.url + 'info.json')
64
+ this.info = data
65
+ this.resolution = data.resolutionGeo
66
+ this.infoLoadingStatus = 'loaded'
67
+ // all the resolutions of a multi-resolution dataset load their info at
68
+ // once: only the one currently shown needs a redraw
69
+ if (this.isShown()) this.map.redraw()
70
+ } catch (error) {
71
+ //mark as failed
72
+ this.infoLoadingStatus = 'failed'
73
+ }
74
+ })()
75
+ }
76
+ // (no redraw for a failed info.json: every redraw would ask again - an endless loop)
77
+ return this
78
+ }
79
+
80
+ /**
81
+ * True when a visible layer of the map shows this dataset at the current zoom.
82
+ * @returns {boolean}
83
+ */
84
+ isShown() {
85
+ if (!this.map || !this.map.layers) return false
86
+ const z = this.map.getZoom()
87
+ for (const lay of this.map.layers) {
88
+ if (lay.visible && !lay.visible(z)) continue
89
+ if (!lay.getDataset) continue
90
+ if (lay.getDataset(z) == this) return true
91
+ }
92
+ return false
93
+ }
94
+
95
+ /**
96
+ * Compute a tiling envelope from a geographical envelope.
97
+ * This is the function to use to know which tiles to download for a geographical view.
98
+ *
99
+ * @param {import("../core/GeoCanvas.js").Envelope} e
100
+ * @returns {import("../core/GeoCanvas.js").Envelope|undefined}
101
+ */
102
+ getTilingEnvelope(e) {
103
+ if (!this.info) {
104
+ this.loadInfo()
105
+ return
106
+ }
107
+
108
+ const po = this.info.originPoint,
109
+ r = this.info.resolutionGeo,
110
+ s = this.info.tileSizeCell
111
+
112
+ return {
113
+ xMin: Math.floor((e.xMin - po.x) / (r * s)),
114
+ xMax: Math.floor((e.xMax - po.x) / (r * s)),
115
+ yMin: Math.floor((e.yMin - po.y) / (r * s)),
116
+ yMax: Math.floor((e.yMax - po.y) / (r * s)),
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Request data within a geographic envelope.
122
+ *
123
+ * @param {import('../core/GeoCanvas.js').Envelope} extGeo
124
+ * @returns {this}
125
+ */
126
+ async getData(extGeo) {
127
+ if (!this.info) return this
128
+
129
+ // Create an AbortController for the current data request
130
+ this.abortController = new AbortController()
131
+ const signal = this.abortController.signal
132
+
133
+ // Get the tiling envelope and check bounds
134
+ const tb = this.getTilingEnvelope(extGeo)
135
+ if (!tb) return this
136
+
137
+ const { xMin: gbXMin, xMax: gbXMax, yMin: gbYMin, yMax: gbYMax } = this.info.tilingBounds
138
+
139
+ const xMin = Math.max(tb.xMin, gbXMin)
140
+ const xMax = Math.min(tb.xMax, gbXMax)
141
+ const yMin = Math.max(tb.yMin, gbYMin)
142
+ const yMax = Math.min(tb.yMax, gbYMax)
143
+
144
+ const totalTiles = (xMax - xMin + 1) * (yMax - yMin + 1)
145
+ let processedTiles = 0
146
+ const tilePromises = []
147
+
148
+ // Iterate over tiles within bounds
149
+ for (let xT = xMin; xT <= xMax; xT++) {
150
+ for (let yT = yMin; yT <= yMax; yT++) {
151
+ if (!this.cache[xT]) this.cache[xT] = {}
152
+
153
+ // Skip already loaded tiles or retry failed ones
154
+ if (this.cache[xT][yT] && this.cache[xT][yT] !== 'failed') {
155
+ ++processedTiles
156
+ continue
157
+ }
158
+
159
+ // Mark tile as loading
160
+ this.cache[xT][yT] = 'loading'
161
+
162
+ tilePromises.push(
163
+ this.loadTile(xT, yT, signal)
164
+ .then((tile) => {
165
+ this.cache[xT][yT] = tile
166
+
167
+ // Check if this is the last tile
168
+ const isLastTile = ++processedTiles === totalTiles
169
+ this.checkAndRedraw(tile, isLastTile)
170
+ })
171
+ .catch(() => {
172
+ this.cache[xT][yT] = 'failed'
173
+ ++processedTiles
174
+ })
175
+ )
176
+ }
177
+ }
178
+
179
+ await Promise.allSettled(tilePromises)
180
+ return this
181
+ }
182
+
183
+ /**
184
+ * Load a tile.
185
+ *
186
+ * @param {number} xT
187
+ * @param {number} yT
188
+ * @param {AbortSignal} signal
189
+ * @returns {Promise<any>}
190
+ */
191
+ async loadTile(xT, yT, signal) {
192
+ try {
193
+ const data = await csv(`${this.url}${xT}/${yT}.csv`, { signal })
194
+
195
+ const cells = this.preprocess ? data.filter((cell) => this.preprocess(cell) !== false) : data
196
+
197
+ if (!this.info) throw new Error('Tile info unknown')
198
+
199
+ return getGridTile(cells, xT, yT, this.info)
200
+ } catch (error) {
201
+ if (error.name === 'AbortError') {
202
+ console.warn(`Tile request for ${xT}, ${yT} was aborted.`)
203
+ }
204
+ throw error
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Cancel ongoing data requests when zoom level changes.
210
+ */
211
+ cancelCurrentRequests() {
212
+ if (this.abortController) {
213
+ this.abortController.abort()
214
+ }
215
+ }
216
+
217
+ checkAndRedraw(tile, isLastTile) {
218
+ // Check if any visible layer depends on this dataset
219
+ // check if redraw is really needed, that is if:
220
+ // 1. the dataset belongs to a layer which is visible at the current zoom level
221
+ if (!this.isShown()) return
222
+
223
+ // Check if tile intersects the current view
224
+ const env = this.map.updateExtentGeo()
225
+ const { xMin, xMax, yMin, yMax } = tile.extGeo
226
+ if (env.xMax <= xMin || env.xMin >= xMax || env.yMax <= yMin || env.yMin >= yMax) return
227
+
228
+ // Trigger redraw
229
+ if (this.onlyDrawWhenAllTilesReady) {
230
+ if (isLastTile) {
231
+ this.map.redraw()
232
+ }
233
+ } else {
234
+ this.map.redraw()
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Fill the view cache with all cells which are within a geographical envelope.
240
+ * @abstract
241
+ * @param {import("../core/GeoCanvas.js").Envelope} extGeo
242
+ * @returns {void}
243
+ */
244
+ updateViewCache(extGeo) {
245
+ //
246
+ this.cellsViewCache = []
247
+
248
+ //check if info has been loaded
249
+ if (!this.info) return
250
+
251
+ //tiles within the scope
252
+ /** @type {import("../core/GeoCanvas.js").Envelope|undefined} */
253
+ const tb = this.getTilingEnvelope(extGeo)
254
+ if (!tb) return
255
+
256
+ //grid bounds
257
+ /** @type {import("../core/GeoCanvas.js").Envelope} */
258
+ const gb = this.info.tilingBounds
259
+
260
+ for (let xT = Math.max(tb.xMin, gb.xMin); xT <= Math.min(tb.xMax, gb.xMax); xT++) {
261
+ if (!this.cache[xT]) continue
262
+ for (let yT = Math.max(tb.yMin, gb.yMin); yT <= Math.min(tb.yMax, gb.yMax); yT++) {
263
+ //get tile
264
+ /** @type {object} */
265
+ const tile = this.cache[xT][yT]
266
+ if (!tile || typeof tile === 'string') continue
267
+
268
+ //get cells
269
+ //this.cellsViewCache = this.cellsViewCache.concat(tile.cells)
270
+
271
+ for (const cell of tile.cells) {
272
+ if (+cell.x + this.resolution < extGeo.xMin) continue
273
+ if (+cell.x - this.resolution > extGeo.xMax) continue
274
+ if (+cell.y + this.resolution < extGeo.yMin) continue
275
+ if (+cell.y - this.resolution > extGeo.yMax) continue
276
+ this.cellsViewCache.push(cell)
277
+ }
278
+ }
279
+ }
280
+ }
281
+ }
282
+
283
+ function getGridTile(cells, xT, yT, gridInfo) {
284
+ const tile = {}
285
+
286
+ /** @type {Array.<import("../core/Dataset").Cell>} */
287
+ tile.cells = cells
288
+ /** @type {number} */
289
+ tile.x = xT
290
+ /** @type {number} */
291
+ tile.y = yT
292
+
293
+ const r = gridInfo.resolutionGeo
294
+ const s = gridInfo.tileSizeCell
295
+
296
+ /** @type {import("../core/GeoCanvas").Envelope} */
297
+ tile.extGeo = {
298
+ xMin: gridInfo.originPoint.x + r * s * tile.x,
299
+ xMax: gridInfo.originPoint.x + r * s * (tile.x + 1),
300
+ yMin: gridInfo.originPoint.y + r * s * tile.y,
301
+ yMax: gridInfo.originPoint.y + r * s * (tile.y + 1),
302
+ }
303
+
304
+ //convert cell coordinates into geographical coordinates
305
+ for (let cell of tile.cells) {
306
+ cell.x = tile.extGeo.xMin + cell.x * r
307
+ cell.y = tile.extGeo.yMin + cell.y * r
308
+ }
309
+
310
+ return tile
311
+ }