gridviz 2.0.28 → 2.0.31

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/dist/gridviz.js +34368 -0
  2. package/dist/gridviz.min.js +1 -1
  3. package/package.json +10 -6
  4. package/src/App.js +654 -0
  5. package/src/BackgroundLayer.js +182 -0
  6. package/src/BackgroundLayerWMS.js +131 -0
  7. package/src/Dataset.js +76 -0
  8. package/src/DatasetComponent.js +103 -0
  9. package/src/GeoCanvas.js +419 -0
  10. package/src/LabelLayer.js +190 -0
  11. package/src/Layer.js +92 -0
  12. package/src/Legend.js +86 -0
  13. package/src/LineLayer.js +150 -0
  14. package/src/Style.js +114 -0
  15. package/src/Tooltip.js +150 -0
  16. package/src/dataset/COGeo.js +24 -0
  17. package/src/dataset/CSVGrid.js +104 -0
  18. package/src/dataset/GeoTIFF.js +127 -0
  19. package/src/dataset/GridTile.js +41 -0
  20. package/src/dataset/ParquetGrid.js +122 -0
  21. package/src/dataset/TiledGrid.js +296 -0
  22. package/src/index.js +177 -0
  23. package/src/legend/ColorCategoryLegend.js +124 -0
  24. package/src/legend/ColorDiscreteLegend.js +105 -0
  25. package/src/legend/ColorLegend.js +125 -0
  26. package/src/legend/SegmentOrientationLegend.js +87 -0
  27. package/src/legend/SegmentWidthLegend.js +97 -0
  28. package/src/legend/SizeLegend.js +141 -0
  29. package/src/style/CompositionStyle.js +300 -0
  30. package/src/style/ContourStyle.js +54 -0
  31. package/src/style/DotDensityStyle.js +156 -0
  32. package/src/style/JoyPlotStyle.js +135 -0
  33. package/src/style/KernelSmoothingOldStyle.js +221 -0
  34. package/src/style/KernelSmoothingStyle.js +115 -0
  35. package/src/style/KernelSmoothingWGLStyle.js +130 -0
  36. package/src/style/LegoStyle.js +112 -0
  37. package/src/style/MosaicStyle.js +107 -0
  38. package/src/style/NinjaStarStyle.js +124 -0
  39. package/src/style/PillarStyle.js +230 -0
  40. package/src/style/SegmentStyle.js +142 -0
  41. package/src/style/ShapeColorSizeStyle.js +126 -0
  42. package/src/style/SideCatStyle.js +172 -0
  43. package/src/style/SideStyle.js +218 -0
  44. package/src/style/SquareColorCatWGLStyle.js +120 -0
  45. package/src/style/SquareColorWGLStyle.js +146 -0
  46. package/src/style/StrokeStyle.js +131 -0
  47. package/src/style/TanakaStyle.js +160 -0
  48. package/src/style/TextStyle.js +132 -0
  49. package/src/utils/Utils.js +35 -0
  50. package/src/utils/WebGLRectangleColoring.js +106 -0
  51. package/src/utils/WebGLSquareColoring.js +118 -0
  52. package/src/utils/WebGLSquareColoringAdvanced.js +230 -0
  53. package/src/utils/WebGLSquareColoringCatAdvanced.js +133 -0
  54. package/src/utils/WebGLSquareColoringKS.js +153 -0
  55. package/src/utils/stretching.js +131 -0
  56. package/src/utils/webGLUtils.js +71 -0
  57. package/src/utils/zoomUtils.js +142 -0
package/src/Legend.js ADDED
@@ -0,0 +1,86 @@
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { select } from 'd3-selection'
5
+
6
+ /**
7
+ * A legend container.
8
+ *
9
+ * @author Joseph Davies, Julien Gaffuri
10
+ */
11
+ export class Legend {
12
+ /**
13
+ * @param {Object} opts
14
+ */
15
+ constructor(opts) {
16
+ opts = opts || {}
17
+
18
+ /** @type {string} */
19
+ this.id = opts.id
20
+
21
+ //TODO stop using it. Use style method below instead.
22
+
23
+ /** @type {number} @deprecated */
24
+ this.top = opts.top
25
+ /** @type {number} @deprecated */
26
+ this.bottom = opts.bottom
27
+ /** @type {number} @deprecated */
28
+ this.left = opts.left
29
+ /** @type {number} @deprecated */
30
+ this.right = opts.right
31
+ /** @type {string} @deprecated */
32
+ this.background = opts.background || 'none'
33
+ /** @type {string} @deprecated */
34
+ this.padding = opts.padding || '5px'
35
+ /** @type {string} @deprecated */
36
+ this.border = opts.border || '0px'
37
+ /** @type {string} @deprecated */
38
+ this['border-radius'] = opts['border-radius'] || 'none'
39
+ /** @type {string} @deprecated */
40
+ this['box-shadow'] = opts['box-shadow'] || 'none'
41
+ /** @type {string} @deprecated */
42
+ this['font-family'] = opts['font-family'] || 'Helvetica, Arial, sans-serif'
43
+ /** @type {string} @deprecated */
44
+ this.width = opts.width
45
+ /** @type {string} @deprecated */
46
+ this.height = opts.height
47
+
48
+ //the div element
49
+ if (this.id) this.div = select('#' + this.id)
50
+
51
+ if (!this.div || this.div.empty()) {
52
+ this.div = select(document.createElement('div'))
53
+ if (this.id) this.div.attr('id', this.id)
54
+ }
55
+
56
+ //set style
57
+ this.div.style('background', this.background)
58
+ this.div.style('padding', this.padding)
59
+ this.div.style('border', this.border)
60
+ this.div.style('border-radius', this['border-radius'])
61
+ this.div.style('box-shadow', this['box-shadow'])
62
+ this.div.style('font-family', this['font-family'])
63
+
64
+ if (this.width) this.div.style('width', this.width)
65
+ if (this.height) this.div.style('height', this.height)
66
+ }
67
+
68
+ /**
69
+ * Apply a style to the legend div.
70
+ * @param {string} k
71
+ * @param {string} v
72
+ * @returns {this}
73
+ */
74
+ style(k, v) {
75
+ this.div.style(k, v)
76
+ return this
77
+ }
78
+
79
+ /**
80
+ * @param {Object} opts
81
+ * @abstract
82
+ */
83
+ update(opts) {
84
+ console.error('Legend update not implemented yet.')
85
+ }
86
+ }
@@ -0,0 +1,150 @@
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { json } from 'd3-fetch'
5
+
6
+ /**
7
+ * @author Joseph Davies, Julien Gaffuri
8
+ */
9
+ export class LineLayer {
10
+ /**
11
+ * @param {object} opts
12
+ */
13
+ constructor(opts) {
14
+ opts = opts || {}
15
+
16
+ /**
17
+ * @private
18
+ * @type {string} */
19
+ this.url = opts.url
20
+
21
+ /**
22
+ * A preprocess to run on each feature after loading.
23
+ * It can be used to apply some specific treatment before, format the label data, project coordinates, etc.
24
+ * Return false if the label should not be kept.
25
+ * @private
26
+ * @type {function(object):boolean} */
27
+ this.preprocess = opts.preprocess
28
+
29
+ /**
30
+ * @private
31
+ * @type {function(object,number):string} */
32
+ this.color = opts.color || ((f, zf) => 'gray')
33
+ /**
34
+ * @private
35
+ * @type {function(object,number):number} */
36
+ this.width = opts.width || ((f, zf) => 2)
37
+ /**
38
+ * @private
39
+ * @type {function(object,number):Array.<number>|undefined} */
40
+ this.lineDash = opts.lineDash || ((f, zf) => undefined)
41
+
42
+ /**
43
+ * @private
44
+ * @type {Array.<object> | undefined} */
45
+ this.fs = undefined
46
+
47
+ /**
48
+ * @private
49
+ * @type {string} */
50
+ this.loadingStatus = 'notLoaded'
51
+ }
52
+
53
+ /**
54
+ * Draw the layer.
55
+ * @param {import("./GeoCanvas").GeoCanvas} cg The canvas where to draw the layer.
56
+ * @returns {void}
57
+ */
58
+ draw(cg) {
59
+ //load data, if not done yet.
60
+ if (!this.fs) {
61
+ this.load(cg.redraw)
62
+ return
63
+ }
64
+
65
+ //TODO sort lines by width ?
66
+
67
+ //zoom factor
68
+ const zf = cg.getZf()
69
+
70
+ //draw in geo coordinates
71
+ cg.setCanvasTransform()
72
+
73
+ for (const f of this.fs) {
74
+ const cs = f.geometry.coordinates
75
+ if (cs.length < 2) continue
76
+
77
+ //set color
78
+ const col = this.color(f, zf)
79
+ if (!col || col == 'none') continue
80
+ cg.ctx.strokeStyle = col
81
+
82
+ //set linewidth
83
+ const wP = this.width(f, zf)
84
+ if (!wP || wP < 0) continue
85
+ cg.ctx.lineWidth = wP * zf
86
+
87
+ //set line dash
88
+ const ldP = this.lineDash(f, zf)
89
+ if (ldP) cg.ctx.setLineDash(ldP)
90
+
91
+ //draw line
92
+ cg.ctx.beginPath()
93
+ cg.ctx.moveTo(cs[0][0], cs[0][1])
94
+ for (let i = 1; i < cs.length; i++) cg.ctx.lineTo(cs[i][0], cs[i][1])
95
+ cg.ctx.stroke()
96
+ }
97
+
98
+ //...
99
+ cg.ctx.setLineDash([])
100
+ }
101
+
102
+ /**
103
+ * Load data for labels, from URL this.url
104
+ * @param {function():void} callback
105
+ * @private
106
+ */
107
+ async load(callback) {
108
+ if (!this.url) {
109
+ console.log('Failed loading boundaries: No URL specified. ' + this.url)
110
+ this.loadingStatus = 'failed'
111
+ this.labels = []
112
+ return
113
+ }
114
+
115
+ //check if data already loaded
116
+ if (this.loadingStatus != 'notLoaded') return
117
+
118
+ //load data
119
+ this.loadingStatus = 'loading'
120
+
121
+ try {
122
+ const data_ = await json(this.url)
123
+
124
+ /** @type { Array.<object> } */
125
+ const data = data_.features
126
+
127
+ //preprocess/filter
128
+ if (this.preprocess) {
129
+ this.fs = []
130
+ for (const c of data) {
131
+ const b = this.preprocess(c)
132
+ if (b == false) continue
133
+ this.fs.push(c)
134
+ }
135
+ } else {
136
+ //store labels
137
+ this.fs = data
138
+ }
139
+
140
+ this.loadingStatus = 'loaded'
141
+
142
+ //redraw
143
+ if (callback) callback()
144
+ } catch (error) {
145
+ console.log('Failed loading boundaries from ' + this.url)
146
+ this.fs = []
147
+ this.loadingStatus = 'failed'
148
+ }
149
+ }
150
+ }
package/src/Style.js ADDED
@@ -0,0 +1,114 @@
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ /**
5
+ * Statistics of a set of values
6
+ * @typedef {{min:number,max:number}} Stat */
7
+
8
+ /** @typedef {"square"|"circle"|"diamond"|"donut"|"none"} Shape */
9
+
10
+ /**
11
+ * A style, to show a grid dataset.
12
+ *
13
+ * @abstract
14
+ *
15
+ * @author Joseph Davies, Julien Gaffuri
16
+ */
17
+ export class Style {
18
+ /**
19
+ * @abstract
20
+ * @param {{filter?:function(import('./Dataset').Cell):boolean,offset?:function(import('./Dataset').Cell,number,number):{dx:number,dy:number},minZoom?:number,maxZoom?:number}} opts
21
+ * minZoom: The minimum zoom level when to show the layer. maxZoom: The maximum zoom level when to show the layer
22
+ */
23
+ constructor(opts) {
24
+ opts = opts || {}
25
+
26
+ /** A filter function to apply to the cell list, to filter out some cells not to be drawn (such as for example the cells with value=0).
27
+ * @protected
28
+ * @type {function(import('./Dataset').Cell):boolean} */
29
+ this.filter = opts.filter || (() => true)
30
+
31
+ /** An offset. This is to alter the position of all symbols in a given direction. In geographical unit.
32
+ * @protected
33
+ * @type {function(import('./Dataset').Cell,number,number):{dx:number,dy:number}} */
34
+ this.offset = opts.offset || ((c, r, zf) => ({ dx: 0, dy: 0 }))
35
+
36
+ /** The minimum zoom factor: Below this level, the layer is not shown.
37
+ * @type {number}
38
+ * */
39
+ this.minZoom = opts.minZoom || 0
40
+
41
+ /** The maximum zoom factor: Above this level, the layer is not shown.
42
+ * @type {number}
43
+ * */
44
+ this.maxZoom = opts.maxZoom || Infinity
45
+
46
+ //ensure acceptable values for the zoom limits.
47
+ if (this.minZoom >= this.maxZoom)
48
+ throw new Error('Unexpected zoom limits for layer. Zoom min should be smaller than zoom max.')
49
+
50
+ /**
51
+ * @public
52
+ * @type {Array.<import("./Legend").Legend>} */
53
+ this.legends = []
54
+ }
55
+
56
+ /**
57
+ * Draw cells.
58
+ *
59
+ * @param {Array.<import('./Dataset').Cell>} cells The cells to draw.
60
+ * @param {number} resolution Their resolution (in geographic unit)
61
+ * @param {import("./GeoCanvas").GeoCanvas} cg The canvas where to draw them.
62
+ * @abstract
63
+ */
64
+ draw(cells, resolution, cg) {
65
+ throw new Error('Method draw not implemented.')
66
+ }
67
+
68
+ //getters and setters
69
+
70
+ /** @returns {function(import('./Dataset').Cell,number,number):{dx:number,dy:number}} */
71
+ getOffset() {
72
+ return this.offset
73
+ }
74
+ /** @param {function(import('./Dataset').Cell,number,number):{dx:number,dy:number}} val @returns {this} */
75
+ setOffset(val) {
76
+ this.offset = val
77
+ return this
78
+ }
79
+
80
+ /** Hide all legend elements of the style, if any
81
+ * @param {object} opts
82
+ * @returns {this} */
83
+ updateLegends(opts) {
84
+ for (const lg of this.legends) lg.update(opts)
85
+ return this
86
+ }
87
+
88
+ /**
89
+ * Compute some statistics on a value of some cells.
90
+ * This is used to define how to draw specifically the cells within the view.
91
+ * TODO: compute median ?
92
+ *
93
+ * @param {Array.<import('./Dataset').Cell>} cells
94
+ * @param {function(import('./Dataset').Cell):number} valFun
95
+ * @param {boolean} ignoreZeros
96
+ * @returns {Stat | undefined}
97
+ */
98
+ static getStatistics(cells, valFun, ignoreZeros) {
99
+ if (!cells || cells.length == 0) return undefined
100
+ let min = Infinity
101
+ let max = -Infinity
102
+ //let sum = 0
103
+ //let nb = 0
104
+ for (const cell of cells) {
105
+ const v = +valFun(cell)
106
+ if (ignoreZeros && !v) continue
107
+ if (v < min) min = v
108
+ if (v > max) max = v
109
+ //sum += v
110
+ //nb++
111
+ }
112
+ return { min: min, max: max }
113
+ }
114
+ }
package/src/Tooltip.js ADDED
@@ -0,0 +1,150 @@
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { select } from 'd3-selection'
5
+ //import { transition } from "d3-transition";
6
+
7
+ /**
8
+ * A generic class to make a tooltip.
9
+ * It is a div element, which can be moved under the mouse pointer and filled with some information in html.
10
+ */
11
+ export class Tooltip {
12
+ /**
13
+ * @param {object} opts
14
+ */
15
+ constructor(opts) {
16
+ opts = opts || {}
17
+
18
+ /** @type {string} */
19
+ this.div = opts.div || 'tooltip_eurostat'
20
+ /** @type {string} */
21
+ this.maxWidth = opts.maxWidth || '20em'
22
+ /** @type {string} */
23
+ this.fontSize = opts.fontSize || '1.2em'
24
+ /** @type {string} */
25
+ this.background = opts.background || 'white'
26
+ /** @type {string} */
27
+ this.padding = opts.padding || '5px'
28
+ /** @type {string} */
29
+ this.border = opts.border || '0px'
30
+ /** @type {string} */
31
+ this['border-radius'] = opts['border-radius'] || '5px'
32
+ /** @type {string} */
33
+ this['box-shadow'] = opts['box-shadow'] || '5px 5px 5px grey'
34
+ /** @type {string} */
35
+ this['font-family'] = opts['font-family'] || 'Helvetica, Arial, sans-serif'
36
+
37
+ /** @type {number} */
38
+ this.transitionDuration = opts.transitionDuration || 100
39
+ /** @type {number} */
40
+ this.xOffset = opts.xOffset || 30
41
+ /** @type {number} */
42
+ this.yOffset = opts.yOffset || 20
43
+ /** @type {number} */ // e.g. to prevent mouse cursor covering cell being highlighted
44
+ this.yMouseOffset = opts.yMouseOffset || 0
45
+ /** @type {number} */
46
+ this.xMouseOffset = opts.xMouseOffset || 0
47
+
48
+ /**
49
+ * @private
50
+ * @type {import("d3-selection").Selection} */
51
+ this.tooltip = select('#' + this.div)
52
+ if (this.tooltip.empty()) this.tooltip = select('body').append('div').attr('id', this.div)
53
+
54
+ //initialise
55
+ this.tooltip.style('max-width', this.maxWidth)
56
+ this.tooltip.style('overflow', 'hidden')
57
+ this.tooltip.style('font-size', this.fontSize)
58
+ this.tooltip.style('background', this.background)
59
+ this.tooltip.style('padding', this.padding)
60
+ this.tooltip.style('border', this.border)
61
+ this.tooltip.style('border-radius', this['border-radius'])
62
+ this.tooltip.style('box-shadow', this['box-shadow'])
63
+ this.tooltip.style('font-family', this['font-family'])
64
+ this.tooltip.style('position', 'absolute')
65
+ this.tooltip.style('pointer-events', 'none')
66
+ this.tooltip.style('opacity', '0')
67
+ }
68
+
69
+ /** Show the tooltip */
70
+ show() {
71
+ // @ts-ignore
72
+ this.tooltip.transition().duration(this.transitionDuration).style('opacity', 1)
73
+ }
74
+
75
+ /** Hide the tooltip */
76
+ hide() {
77
+ // @ts-ignore
78
+ this.tooltip.transition().duration(this.transitionDuration).style('opacity', 0)
79
+ }
80
+
81
+ /**
82
+ * Set the content of the tooltip.
83
+ * @param {string} html
84
+ */
85
+ html(html) {
86
+ this.tooltip.html(html)
87
+ }
88
+
89
+ /**
90
+ * Set the position of the tooltip at the mouse event position.
91
+ * @param {MouseEvent} event
92
+ */
93
+ setPosition(event) {
94
+ this.tooltip
95
+ .style('left', event.pageX + this.xOffset + 'px')
96
+ .style('top', event.pageY - this.yOffset + 'px')
97
+ }
98
+
99
+ /*
100
+ my.mouseover = function (event, html) {
101
+ if (html) my.html(html);
102
+ my.setPosition(event);
103
+ my.show()
104
+ //this.ensureTooltipOnScreen();
105
+ };
106
+
107
+ my.mousemove = function (event) {
108
+ my.setPosition(event);
109
+ //this.ensureTooltipOnScreen();
110
+ };
111
+
112
+ my.mouseout = function () {
113
+ my.hide();
114
+ };*/
115
+
116
+ style(k, v) {
117
+ if (arguments.length == 1) return this.tooltip.style(k)
118
+ this.tooltip.style(k, v)
119
+ return this
120
+ }
121
+
122
+ attr(k, v) {
123
+ if (arguments.length == 1) return this.tooltip.attr(k)
124
+ this.tooltip.attr(k, v)
125
+ return this
126
+ }
127
+
128
+ /**
129
+ * @function ensureTooltipOnScreen
130
+ * @description Prevents the tooltip from overflowing off screen
131
+ */
132
+ /*my.ensureTooltipOnScreen = function () {
133
+ // TODO: parent needs to be the all-encompassing container, not the map SVG id otherwise it just uses the last SVG which will be an inset SVG.
134
+ let parent = document.getElementById(config.parentContainerId);
135
+ let bbox = parent.getBBox();
136
+ let parentWidth = bbox.width;
137
+ let parentHeight = bbox.height;
138
+ let node = tooltip.node();
139
+ //too far right
140
+ if (node.offsetLeft > parentWidth - node.clientWidth) {
141
+ node.style.left = node.offsetLeft - (node.clientWidth + config.xOffset * 2) + "px";
142
+
143
+ }
144
+ //too far down
145
+ if (node.offsetTop + node.clientHeight > parentHeight) {
146
+ node.style.top = node.offsetTop - (node.clientHeight + config.yOffset * 2) + "px";
147
+ }
148
+
149
+ }*/
150
+ }
@@ -0,0 +1,24 @@
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { DatasetComponent } from '../DatasetComponent.js'
5
+
6
+ /**
7
+ * @todo
8
+ * A dataset composed of a COGeo file.
9
+ * @see https://www.cogeo.org/
10
+ *
11
+ * @author Joseph Davies, Julien Gaffuri
12
+ */
13
+ export class COGeo extends DatasetComponent {
14
+ /**
15
+ *
16
+ * @param {String} url
17
+ * @param {{preprocess?:(function(import("../Dataset").Cell):boolean)}} opts
18
+ */
19
+ constructor(url, opts = {}) {
20
+ super(url, 0, opts)
21
+ }
22
+
23
+ //TODO Use https://geotiffjs.github.io/
24
+ }
@@ -0,0 +1,104 @@
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 }} GridInfo */
5
+
6
+ import { csv } from 'd3-fetch'
7
+ import { DatasetComponent } from '../DatasetComponent.js'
8
+
9
+ /**
10
+ * A dataset composed of a single CSV file (not tiled).
11
+ *
12
+ * @author Joseph Davies, Julien Gaffuri
13
+ */
14
+ export class CSVGrid extends DatasetComponent {
15
+ /**
16
+ * @param {string} url The URL of the dataset.
17
+ * @param {number} resolution The dataset resolution in geographical unit.
18
+ * @param {{preprocess?:(function(import("../Dataset").Cell):boolean)}} opts
19
+ */
20
+ constructor(url, resolution, opts = {}) {
21
+ super(url, resolution, opts)
22
+
23
+ /**
24
+ * @private
25
+ * @type {Array.<import("../Dataset").Cell>} */
26
+ this.cells = []
27
+
28
+ /**
29
+ * @type {string}
30
+ * @private */
31
+ this.infoLoadingStatus = 'notLoaded'
32
+ }
33
+
34
+ /**
35
+ * Request data within a geographic envelope.
36
+ *
37
+ * @param {import("../Dataset").Envelope|undefined} e
38
+ * @param {function():void} redraw
39
+ */
40
+ getData(e, redraw) {
41
+ //check if data already loaded
42
+ if (this.infoLoadingStatus != 'notLoaded') return this
43
+
44
+ //load data
45
+ this.infoLoadingStatus = 'loading'
46
+ ;(async () => {
47
+ try {
48
+ const data = await csv(this.url)
49
+
50
+ //convert coordinates in numbers
51
+ for (const c of data) {
52
+ c.x = +c.x
53
+ c.y = +c.y
54
+ }
55
+
56
+ //preprocess/filter
57
+ if (this.preprocess) {
58
+ this.cells = []
59
+ for (const c of data) {
60
+ const b = this.preprocess(c)
61
+ if (b == false) continue
62
+ this.cells.push(c)
63
+ }
64
+ } else {
65
+ this.cells = data
66
+ }
67
+
68
+ //TODO check if redraw is necessary
69
+ //that is if the dataset belongs to a layer which is visible at the current zoom level
70
+
71
+ //execute the callback, usually a draw function
72
+ if (redraw) redraw()
73
+
74
+ this.infoLoadingStatus = 'loaded'
75
+ } catch (error) {
76
+ //mark as failed
77
+ this.infoLoadingStatus = 'failed'
78
+ this.cells = []
79
+ }
80
+ })()
81
+
82
+ return this
83
+ }
84
+
85
+ /**
86
+ * Fill the view cache with all cells which are within a geographical envelope.
87
+ *
88
+ * @param {import("../Dataset").Envelope} extGeo
89
+ * @returns {void}
90
+ */
91
+ updateViewCache(extGeo) {
92
+ //data not loaded yet
93
+ if (!this.cells) return
94
+
95
+ this.cellsViewCache = []
96
+ for (const cell of this.cells) {
97
+ if (+cell.x + this.resolution < extGeo.xMin) continue
98
+ if (+cell.x - this.resolution > extGeo.xMax) continue
99
+ if (+cell.y + this.resolution < extGeo.yMin) continue
100
+ if (+cell.y - this.resolution > extGeo.yMax) continue
101
+ this.cellsViewCache.push(cell)
102
+ }
103
+ }
104
+ }