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.
- package/dist/gridviz.js +34368 -0
- package/dist/gridviz.min.js +1 -1
- package/package.json +10 -6
- package/src/App.js +654 -0
- package/src/BackgroundLayer.js +182 -0
- package/src/BackgroundLayerWMS.js +131 -0
- package/src/Dataset.js +76 -0
- package/src/DatasetComponent.js +103 -0
- package/src/GeoCanvas.js +419 -0
- package/src/LabelLayer.js +190 -0
- package/src/Layer.js +92 -0
- package/src/Legend.js +86 -0
- package/src/LineLayer.js +150 -0
- package/src/Style.js +114 -0
- package/src/Tooltip.js +150 -0
- package/src/dataset/COGeo.js +24 -0
- package/src/dataset/CSVGrid.js +104 -0
- package/src/dataset/GeoTIFF.js +127 -0
- package/src/dataset/GridTile.js +41 -0
- package/src/dataset/ParquetGrid.js +122 -0
- package/src/dataset/TiledGrid.js +296 -0
- package/src/index.js +177 -0
- package/src/legend/ColorCategoryLegend.js +124 -0
- package/src/legend/ColorDiscreteLegend.js +105 -0
- package/src/legend/ColorLegend.js +125 -0
- package/src/legend/SegmentOrientationLegend.js +87 -0
- package/src/legend/SegmentWidthLegend.js +97 -0
- package/src/legend/SizeLegend.js +141 -0
- package/src/style/CompositionStyle.js +300 -0
- package/src/style/ContourStyle.js +54 -0
- package/src/style/DotDensityStyle.js +156 -0
- package/src/style/JoyPlotStyle.js +135 -0
- package/src/style/KernelSmoothingOldStyle.js +221 -0
- package/src/style/KernelSmoothingStyle.js +115 -0
- package/src/style/KernelSmoothingWGLStyle.js +130 -0
- package/src/style/LegoStyle.js +112 -0
- package/src/style/MosaicStyle.js +107 -0
- package/src/style/NinjaStarStyle.js +124 -0
- package/src/style/PillarStyle.js +230 -0
- package/src/style/SegmentStyle.js +142 -0
- package/src/style/ShapeColorSizeStyle.js +126 -0
- package/src/style/SideCatStyle.js +172 -0
- package/src/style/SideStyle.js +218 -0
- package/src/style/SquareColorCatWGLStyle.js +120 -0
- package/src/style/SquareColorWGLStyle.js +146 -0
- package/src/style/StrokeStyle.js +131 -0
- package/src/style/TanakaStyle.js +160 -0
- package/src/style/TextStyle.js +132 -0
- package/src/utils/Utils.js +35 -0
- package/src/utils/WebGLRectangleColoring.js +106 -0
- package/src/utils/WebGLSquareColoring.js +118 -0
- package/src/utils/WebGLSquareColoringAdvanced.js +230 -0
- package/src/utils/WebGLSquareColoringCatAdvanced.js +133 -0
- package/src/utils/WebGLSquareColoringKS.js +153 -0
- package/src/utils/stretching.js +131 -0
- package/src/utils/webGLUtils.js +71 -0
- package/src/utils/zoomUtils.js +142 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* A map background layer in "Slippy map" XYZ standard.
|
|
7
|
+
* See https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
|
|
8
|
+
* https://www.maptiler.com/google-maps-coordinates-tile-bounds-projection/#6/27.88/44.48
|
|
9
|
+
*
|
|
10
|
+
* @author Julien Gaffuri
|
|
11
|
+
*/
|
|
12
|
+
export class BackgroundLayer {
|
|
13
|
+
/**
|
|
14
|
+
* @param {object} opts
|
|
15
|
+
*/
|
|
16
|
+
constructor(opts) {
|
|
17
|
+
opts = opts || {}
|
|
18
|
+
|
|
19
|
+
/** An attribute to specify if a layer should be drawn or not
|
|
20
|
+
* @type {boolean} */
|
|
21
|
+
this.visible = opts.visible == false ? false : true
|
|
22
|
+
|
|
23
|
+
/** The minimum zoom factor: Below this level, the layer is not shown.
|
|
24
|
+
* @type {number} */
|
|
25
|
+
this.minZoom = opts.minZoom || 0
|
|
26
|
+
|
|
27
|
+
/** The maximum zoom factor: Above this level, the layer is not shown.
|
|
28
|
+
* @type {number} */
|
|
29
|
+
this.maxZoom = opts.maxZoom || Infinity
|
|
30
|
+
|
|
31
|
+
//ensure acceptable values for the zoom limits.
|
|
32
|
+
if (this.minZoom >= this.maxZoom)
|
|
33
|
+
throw new Error('Unexpected zoom limits for layer. Zoom min should be smaller than zoom max.')
|
|
34
|
+
|
|
35
|
+
/** The image cache, indexed by z/y/x */
|
|
36
|
+
this.cache = {}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @type {string} */
|
|
40
|
+
this.url = opts.url
|
|
41
|
+
/** @type {function(number,number,number):string} */
|
|
42
|
+
this.urlFun = opts.urlFun || ((x, y, z) => this.url + z + '/' + x + '/' + y + '.png')
|
|
43
|
+
|
|
44
|
+
/** @type {Array.<number>} */
|
|
45
|
+
this.resolutions = opts.resolutions
|
|
46
|
+
if (!this.resolutions || this.resolutions.length == 0)
|
|
47
|
+
throw new Error('No resolutions provided for background layer')
|
|
48
|
+
|
|
49
|
+
/** @type {number} */
|
|
50
|
+
this.nbPix = opts.nbPix || 256
|
|
51
|
+
/** CRS coordinates of top left corner
|
|
52
|
+
* @type {Array.<number>} */
|
|
53
|
+
this.origin = opts.origin || [0, 0]
|
|
54
|
+
/** @type {number} */
|
|
55
|
+
this.z0 = opts.z0 || 0
|
|
56
|
+
|
|
57
|
+
/** @type {function(number):string} */
|
|
58
|
+
this.filterColor = opts.filterColor // (zf) => "#eee7"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Get z/x/y cache data.
|
|
63
|
+
* @param {number} z
|
|
64
|
+
* @param {number} x
|
|
65
|
+
* @param {number} y
|
|
66
|
+
* @returns {HTMLImageElement|string|undefined}
|
|
67
|
+
* @private
|
|
68
|
+
*/
|
|
69
|
+
get(z, x, y) {
|
|
70
|
+
let d = this.cache[z]
|
|
71
|
+
if (!d) return
|
|
72
|
+
d = d[x]
|
|
73
|
+
if (!d) return
|
|
74
|
+
return d[y]
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get z/x/y cache data.
|
|
79
|
+
* @param {HTMLImageElement|string} img
|
|
80
|
+
* @param {number} z
|
|
81
|
+
* @param {number} x
|
|
82
|
+
* @param {number} y
|
|
83
|
+
* @returns
|
|
84
|
+
* @private
|
|
85
|
+
*/
|
|
86
|
+
put(img, z, x, y) {
|
|
87
|
+
if (!this.cache[z]) this.cache[z] = {}
|
|
88
|
+
if (!this.cache[z][x]) this.cache[z][x] = {}
|
|
89
|
+
this.cache[z][x][y] = img
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @param {import("./GeoCanvas").GeoCanvas} cg The canvas where to draw the layer.
|
|
94
|
+
* @returns {void}
|
|
95
|
+
*/
|
|
96
|
+
draw(cg) {
|
|
97
|
+
if (!this.resolutions || this.resolutions.length == 0) {
|
|
98
|
+
console.error('No resolutions provided for background layer')
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
//
|
|
103
|
+
const zf = cg.getZf()
|
|
104
|
+
const x0 = this.origin[0],
|
|
105
|
+
y0 = this.origin[1]
|
|
106
|
+
|
|
107
|
+
//get zoom level and resolution
|
|
108
|
+
let z = 0
|
|
109
|
+
for (z = 0; z < this.resolutions.length; z++) if (this.resolutions[z] < zf) break
|
|
110
|
+
z -= 1
|
|
111
|
+
z = Math.max(0, z)
|
|
112
|
+
z = Math.min(z, this.resolutions.length - 1)
|
|
113
|
+
//console.log(this.resolutions.length, z)
|
|
114
|
+
const res = this.resolutions[z]
|
|
115
|
+
|
|
116
|
+
z += this.z0
|
|
117
|
+
|
|
118
|
+
const sizeG = this.nbPix * res
|
|
119
|
+
const size = sizeG / zf
|
|
120
|
+
|
|
121
|
+
//get tile numbers
|
|
122
|
+
const xGeoToTMS = (x) => Math.ceil((x - x0) / sizeG)
|
|
123
|
+
const yGeoToTMS = (y) => Math.ceil(-(y - y0) / sizeG)
|
|
124
|
+
const xMin = xGeoToTMS(cg.extGeo.xMin) - 1
|
|
125
|
+
const xMax = xGeoToTMS(cg.extGeo.xMax)
|
|
126
|
+
const yMax = yGeoToTMS(cg.extGeo.yMin)
|
|
127
|
+
const yMin = yGeoToTMS(cg.extGeo.yMax) - 1
|
|
128
|
+
|
|
129
|
+
//TODO ?
|
|
130
|
+
//cg.setCanvasTransform()
|
|
131
|
+
|
|
132
|
+
//handle images
|
|
133
|
+
for (let x = xMin; x < xMax; x++) {
|
|
134
|
+
for (let y = yMin; y < yMax; y++) {
|
|
135
|
+
//get image
|
|
136
|
+
let img = this.get(z, x, y)
|
|
137
|
+
|
|
138
|
+
//load image
|
|
139
|
+
if (!img) {
|
|
140
|
+
const img = new Image()
|
|
141
|
+
this.put(img, z, x, y)
|
|
142
|
+
img.onload = () => {
|
|
143
|
+
cg.redraw()
|
|
144
|
+
}
|
|
145
|
+
img.onerror = () => {
|
|
146
|
+
//case when no image
|
|
147
|
+
this.put('failed', z, x, y)
|
|
148
|
+
}
|
|
149
|
+
img.src = this.urlFun(x, y, z)
|
|
150
|
+
continue
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
//case when no image
|
|
154
|
+
if (img === 'failed') continue
|
|
155
|
+
if (!(img instanceof HTMLImageElement)) {
|
|
156
|
+
console.log(img)
|
|
157
|
+
continue
|
|
158
|
+
}
|
|
159
|
+
if (img.width == 0 || img.height == 0) continue
|
|
160
|
+
|
|
161
|
+
//draw image
|
|
162
|
+
const xGeo = x0 + x * sizeG
|
|
163
|
+
const yGeo = y0 - y * sizeG
|
|
164
|
+
try {
|
|
165
|
+
cg.ctx.drawImage(img, cg.geoToPixX(xGeo), cg.geoToPixY(yGeo), size, size)
|
|
166
|
+
//cg.ctx.drawImage(img, xGeo, yGeo, sizeG, -sizeG)
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.error(error)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
//apply filter
|
|
174
|
+
if (this.filterColor) {
|
|
175
|
+
const fc = this.filterColor(zf)
|
|
176
|
+
if (fc && fc != 'none') {
|
|
177
|
+
cg.ctx.fillStyle = fc
|
|
178
|
+
cg.ctx.fillRect(0, 0, cg.w, cg.h)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* A map WMS background layer.
|
|
7
|
+
*
|
|
8
|
+
* @author Julien Gaffuri
|
|
9
|
+
*/
|
|
10
|
+
export class BackgroundLayerWMS {
|
|
11
|
+
/**
|
|
12
|
+
* @param {object} opts
|
|
13
|
+
*/
|
|
14
|
+
constructor(opts) {
|
|
15
|
+
opts = opts || {}
|
|
16
|
+
|
|
17
|
+
/** An attribute to specify if a layer should be drawn or not
|
|
18
|
+
* @type {boolean} */
|
|
19
|
+
this.visible = opts.visible == false ? false : true
|
|
20
|
+
|
|
21
|
+
/** The minimum zoom factor: Below this level, the layer is not shown.
|
|
22
|
+
* @type {number} */
|
|
23
|
+
this.minZoom = opts.minZoom || 0
|
|
24
|
+
|
|
25
|
+
/** The maximum zoom factor: Above this level, the layer is not shown.
|
|
26
|
+
* @type {number} */
|
|
27
|
+
this.maxZoom = opts.maxZoom || Infinity
|
|
28
|
+
|
|
29
|
+
//ensure acceptable values for the zoom limits.
|
|
30
|
+
if (this.minZoom >= this.maxZoom)
|
|
31
|
+
throw new Error('Unexpected zoom limits for layer. Zoom min should be smaller than zoom max.')
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @type {string} */
|
|
35
|
+
this.url = opts.url
|
|
36
|
+
|
|
37
|
+
/** @type {function(number):string} */
|
|
38
|
+
this.filterColor = opts.filterColor // (zf) => "#eee7"
|
|
39
|
+
|
|
40
|
+
/** @type {HTMLImageElement|undefined} */
|
|
41
|
+
this.img = undefined;
|
|
42
|
+
|
|
43
|
+
/** @type {number|undefined} */
|
|
44
|
+
this.xMin = undefined;
|
|
45
|
+
/** @type {number|undefined} */
|
|
46
|
+
this.xMax = undefined;
|
|
47
|
+
/** @type {number|undefined} */
|
|
48
|
+
this.yMin = undefined;
|
|
49
|
+
/** @type {number|undefined} */
|
|
50
|
+
this.yMax = undefined;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Check if the view has moved and a new image needs to be retrieved.
|
|
54
|
+
* @private */
|
|
55
|
+
hasMoved(extGeo) {
|
|
56
|
+
if ((extGeo.xMin) != this.xMin) return true
|
|
57
|
+
else if ((extGeo.xMax) != this.xMax) return true
|
|
58
|
+
else if ((extGeo.yMin) != this.yMin) return true
|
|
59
|
+
else if ((extGeo.yMax) != this.yMax) return true
|
|
60
|
+
else return false
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @param {import("./GeoCanvas").GeoCanvas} cg The canvas where to draw the layer.
|
|
66
|
+
* @returns {void}
|
|
67
|
+
*/
|
|
68
|
+
draw(cg) {
|
|
69
|
+
|
|
70
|
+
//update map extent
|
|
71
|
+
cg.updateExtentGeo(0)
|
|
72
|
+
|
|
73
|
+
if (!this.hasMoved(cg.extGeo) && this.img) {
|
|
74
|
+
//the map did not move and the image was already downloaded: draw the image
|
|
75
|
+
cg.ctx.drawImage(this.img, 0, 0, cg.w, cg.h)
|
|
76
|
+
|
|
77
|
+
} else {
|
|
78
|
+
//the map moved: retrieve new image
|
|
79
|
+
|
|
80
|
+
//
|
|
81
|
+
this.xMin = cg.extGeo.xMin
|
|
82
|
+
this.xMax = cg.extGeo.xMax
|
|
83
|
+
this.yMin = cg.extGeo.yMin
|
|
84
|
+
this.yMax = cg.extGeo.yMax
|
|
85
|
+
|
|
86
|
+
//build WMS URL
|
|
87
|
+
const url = []
|
|
88
|
+
url.push(this.url)
|
|
89
|
+
url.push("&width=")
|
|
90
|
+
url.push(cg.w)
|
|
91
|
+
url.push("&height=")
|
|
92
|
+
url.push(cg.h)
|
|
93
|
+
//bbox: xmin ymin xmax ymax
|
|
94
|
+
url.push("&bbox=")
|
|
95
|
+
url.push(cg.extGeo.xMin)
|
|
96
|
+
url.push(",")
|
|
97
|
+
url.push(cg.extGeo.yMin)
|
|
98
|
+
url.push(",")
|
|
99
|
+
url.push(cg.extGeo.xMax)
|
|
100
|
+
url.push(",")
|
|
101
|
+
url.push(cg.extGeo.yMax)
|
|
102
|
+
|
|
103
|
+
const urlS = url.join("")
|
|
104
|
+
//console.log(urlS)
|
|
105
|
+
|
|
106
|
+
if (!this.img) {
|
|
107
|
+
this.img = new Image()
|
|
108
|
+
this.img.onload = () => {
|
|
109
|
+
cg.redraw()
|
|
110
|
+
}
|
|
111
|
+
this.img.onerror = () => {
|
|
112
|
+
//case when no image
|
|
113
|
+
console.warn("Could not retrieve WMS background image from", urlS)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
//set URL to launch the download
|
|
118
|
+
this.img.src = urlS
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
//apply filter
|
|
122
|
+
const zf = cg.getZf()
|
|
123
|
+
if (this.filterColor) {
|
|
124
|
+
const fc = this.filterColor(zf)
|
|
125
|
+
if (fc && fc != 'none') {
|
|
126
|
+
cg.ctx.fillStyle = fc
|
|
127
|
+
cg.ctx.fillRect(0, 0, cg.w, cg.h)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
package/src/Dataset.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A grid cell.
|
|
6
|
+
* @typedef {{x: number, y: number}} Cell */
|
|
7
|
+
/**
|
|
8
|
+
* An envelope.
|
|
9
|
+
* @typedef { {xMin: number, xMax: number, yMin: number, yMax: number} } Envelope */
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A multi resolution dataset of grid cells.
|
|
13
|
+
* It consists of different {@link DatasetComponent}s for each resolution.
|
|
14
|
+
*
|
|
15
|
+
* @abstract
|
|
16
|
+
*
|
|
17
|
+
* @author Joseph Davies, Julien Gaffuri
|
|
18
|
+
*/
|
|
19
|
+
export class Dataset {
|
|
20
|
+
/**
|
|
21
|
+
* @param {Array.<import("./DatasetComponent").DatasetComponent>} datasetComponents The dataset components
|
|
22
|
+
* @param {Array.<number>} resolutions The resolutions of the dataset components, in CRS geographical unit
|
|
23
|
+
* @param { {preprocess?:function(Cell):boolean} } opts Options. preprocess: A function to apply on each dataset cell to prepare its values. Can be used also to select cells to keep.
|
|
24
|
+
*/
|
|
25
|
+
constructor(datasetComponents, resolutions, opts = {}) {
|
|
26
|
+
opts = opts || {}
|
|
27
|
+
|
|
28
|
+
/** The dataset components.
|
|
29
|
+
* @type {Array.<import("./DatasetComponent").DatasetComponent>} */
|
|
30
|
+
this.datasetComponents = datasetComponents
|
|
31
|
+
|
|
32
|
+
/** The resolutions of the dataset components, in CRS geographical unit.
|
|
33
|
+
* @type {Array.<number>} */
|
|
34
|
+
this.resolutions = resolutions
|
|
35
|
+
|
|
36
|
+
//there must be as many dataset components as resolutions
|
|
37
|
+
if (this.datasetComponents.length > 1 && this.datasetComponents.length != this.resolutions.length)
|
|
38
|
+
throw new Error(
|
|
39
|
+
'Uncompatible number of datasets and resolutions: ' +
|
|
40
|
+
this.datasetComponents.length +
|
|
41
|
+
' ' +
|
|
42
|
+
this.resolutions.length
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
//set dataset preprocesses if specified
|
|
46
|
+
if (opts.preprocess) this.setPrepocesses(opts.preprocess)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Set a preprocess function for all dataset components.
|
|
51
|
+
* This is a function applied on each cell after it has been loaded.
|
|
52
|
+
*
|
|
53
|
+
* @param {function(Cell):boolean} preprocess
|
|
54
|
+
* @returns {this}
|
|
55
|
+
*/
|
|
56
|
+
setPrepocesses(preprocess) {
|
|
57
|
+
for (let ds of this.datasetComponents) ds.preprocess = preprocess
|
|
58
|
+
return this
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A function to ease the creation of datasets from their components.
|
|
63
|
+
*
|
|
64
|
+
* @param {Array.<number>} resolutions The resolutions of the dataset components, in CRS geographical unit
|
|
65
|
+
* @param {function(number):import("./DatasetComponent").DatasetComponent} resToDatasetComponent Function returning a dataset component from a resolution
|
|
66
|
+
* @param { {preprocess?:function(Cell):boolean} } opts Options. preprocess: A function to apply on each dataset cell to prepare its values
|
|
67
|
+
* @returns {Dataset}
|
|
68
|
+
*/
|
|
69
|
+
static make(resolutions, resToDatasetComponent, opts) {
|
|
70
|
+
//make dataset components
|
|
71
|
+
const dsc = []
|
|
72
|
+
for (const res of resolutions) dsc.push(resToDatasetComponent(res))
|
|
73
|
+
//make dataset
|
|
74
|
+
return new Dataset(dsc, resolutions, opts)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
/** @typedef {"CSV"|"PARQUET"} Format */
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A dataset component, of grid cells.
|
|
8
|
+
* @abstract
|
|
9
|
+
*
|
|
10
|
+
* @author Joseph Davies, Julien Gaffuri
|
|
11
|
+
*/
|
|
12
|
+
export class DatasetComponent {
|
|
13
|
+
/**
|
|
14
|
+
* @param {string} url The URL of the dataset.
|
|
15
|
+
* @param {number} resolution The dataset resolution, in the CRS geographical unit.
|
|
16
|
+
* @param {{preprocess?:function(import("./Dataset").Cell):boolean}} opts
|
|
17
|
+
* @abstract
|
|
18
|
+
*/
|
|
19
|
+
constructor(url, resolution, opts = {}) {
|
|
20
|
+
opts = opts || {}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The url of the dataset.
|
|
24
|
+
* @protected
|
|
25
|
+
* @type {string} */
|
|
26
|
+
this.url = url
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The dataset resolution in geographical unit.
|
|
30
|
+
* @protected
|
|
31
|
+
* @type {number} */
|
|
32
|
+
this.resolution = resolution
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A preprocess to run on each cell after loading. It can be used to apply some specific treatment before or compute a new column. And also to determine which cells to keep after loading.
|
|
36
|
+
* @type {(function(import("./Dataset").Cell):boolean )| undefined } */
|
|
37
|
+
this.preprocess = opts.preprocess || undefined
|
|
38
|
+
|
|
39
|
+
/** The cells within the view
|
|
40
|
+
* @protected
|
|
41
|
+
* @type {Array.<import("./Dataset").Cell>} */
|
|
42
|
+
this.cellsViewCache = []
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Request data within a geographic envelope.
|
|
47
|
+
*
|
|
48
|
+
* @abstract
|
|
49
|
+
* @param {import("./Dataset").Envelope|undefined} extGeo
|
|
50
|
+
* @param {function():void} callback
|
|
51
|
+
* @returns {this}
|
|
52
|
+
*/
|
|
53
|
+
getData(extGeo, callback) {
|
|
54
|
+
throw new Error('Method getData not implemented.')
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Fill the view cache with all cells which are within a geographical envelope.
|
|
59
|
+
* @abstract
|
|
60
|
+
* @param {import("./Dataset").Envelope} extGeo The view geographical envelope.
|
|
61
|
+
* @returns {void}
|
|
62
|
+
*/
|
|
63
|
+
updateViewCache(extGeo) {
|
|
64
|
+
throw new Error('Method updateViewCache not implemented.')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get a cell under a given position, if any.
|
|
69
|
+
*
|
|
70
|
+
* @param {{x:number,y:number}} posGeo
|
|
71
|
+
* @param {Array.<import("./Dataset").Cell>} cells Some cells from the dataset (a subset if necessary, usually the view cache).
|
|
72
|
+
* @returns {import("./Dataset").Cell|undefined}
|
|
73
|
+
*/
|
|
74
|
+
getCellFromPosition(posGeo, cells) {
|
|
75
|
+
//compute candidate cell position
|
|
76
|
+
/** @type {number} */
|
|
77
|
+
const r = this.getResolution()
|
|
78
|
+
/** @type {number} */
|
|
79
|
+
const cellX = r * Math.floor(posGeo.x / r)
|
|
80
|
+
/** @type {number} */
|
|
81
|
+
const cellY = r * Math.floor(posGeo.y / r)
|
|
82
|
+
|
|
83
|
+
//get cell
|
|
84
|
+
for (const cell of cells) {
|
|
85
|
+
if (cell.x != cellX) continue
|
|
86
|
+
if (cell.y != cellY) continue
|
|
87
|
+
return cell
|
|
88
|
+
}
|
|
89
|
+
return undefined
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
//getters and setters
|
|
93
|
+
|
|
94
|
+
/** @returns {number} */
|
|
95
|
+
getResolution() {
|
|
96
|
+
return this.resolution
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** @returns {Array.<import("./Dataset").Cell>} */
|
|
100
|
+
getViewCache() {
|
|
101
|
+
return this.cellsViewCache
|
|
102
|
+
}
|
|
103
|
+
}
|