gridviz 2.1.11 → 2.1.13
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/README.md +125 -125
- package/dist/gridviz.js +8254 -7887
- package/dist/gridviz.min.js +1 -1
- package/package.json +77 -77
- package/src/App.js +758 -705
- package/src/BackgroundLayer.js +182 -182
- package/src/BackgroundLayerWMS.js +131 -131
- package/src/Dataset.js +76 -76
- package/src/DatasetComponent.js +113 -113
- package/src/GeoCanvas.js +420 -420
- package/src/LabelLayer.js +190 -190
- package/src/Layer.js +103 -103
- package/src/Legend.js +86 -86
- package/src/LineLayer.js +150 -150
- package/src/Style.js +129 -129
- package/src/Tooltip.js +180 -180
- package/src/button/Button.js +54 -0
- package/src/button/FullscreenButton.js +98 -0
- package/src/button/ZoomButtons.js +72 -0
- package/src/dataset/COGeo.js +24 -24
- package/src/dataset/CSVGrid.js +104 -104
- package/src/dataset/GeoTIFF.js +127 -127
- package/src/dataset/GridTile.js +41 -41
- package/src/dataset/LGrid.js +54 -54
- package/src/dataset/TiledGrid.js +264 -264
- package/src/index.js +71 -71
- package/src/legend/ColorCategoryLegend.js +124 -124
- package/src/legend/ColorDiscreteLegend.js +103 -103
- package/src/legend/ColorLegend.js +128 -124
- package/src/legend/SegmentOrientationLegend.js +87 -87
- package/src/legend/SegmentWidthLegend.js +101 -97
- package/src/legend/SizeLegend.js +141 -141
- package/src/style/CompositionStyle.js +300 -300
- package/src/style/ContourStyle.js +54 -54
- package/src/style/DotDensityStyle.js +156 -156
- package/src/style/IsoFenceStyle.js +262 -262
- package/src/style/JoyPlotStyle.js +135 -135
- package/src/style/LegoStyle.js +112 -112
- package/src/style/MosaicStyle.js +107 -107
- package/src/style/NinjaStarStyle.js +125 -125
- package/src/style/PillarStyle.js +230 -230
- package/src/style/SegmentStyle.js +142 -142
- package/src/style/ShapeColorSizeStyle.js +152 -126
- package/src/style/SideCatStyle.js +172 -172
- package/src/style/SideStyle.js +216 -216
- package/src/style/SquareColorCatWGLStyle.js +120 -120
- package/src/style/SquareColorWGLStyle.js +146 -146
- package/src/style/StrokeStyle.js +131 -131
- package/src/style/TanakaStyle.js +160 -160
- package/src/style/TextStyle.js +132 -132
- package/src/style/TimeSeriesStyle.js +259 -250
- package/src/utils/Utils.js +35 -35
- package/src/utils/WebGLRectangleColoring.js +106 -106
- package/src/utils/WebGLSquareColoring.js +118 -118
- package/src/utils/WebGLSquareColoringAdvanced.js +230 -230
- package/src/utils/WebGLSquareColoringCatAdvanced.js +133 -133
- package/src/utils/WebGLSquareColoringKS.js +153 -153
- package/src/utils/stretching.js +131 -131
- package/src/utils/webGLUtils.js +71 -71
- package/src/utils/zoomUtils.js +142 -142
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parent class for button elements used to interact with the gridviz viewer.
|
|
3
|
+
*
|
|
4
|
+
* @author Joseph Davies, Julien Gaffuri
|
|
5
|
+
*/
|
|
6
|
+
export class Button {
|
|
7
|
+
/**
|
|
8
|
+
* @param {Object} opts
|
|
9
|
+
* opts.parentNode
|
|
10
|
+
* opts.id
|
|
11
|
+
* opts.title
|
|
12
|
+
* opts.class
|
|
13
|
+
* opts.onClickFunction
|
|
14
|
+
* opts.x
|
|
15
|
+
* opts.y
|
|
16
|
+
*/
|
|
17
|
+
constructor(opts) {
|
|
18
|
+
opts = opts || {}
|
|
19
|
+
|
|
20
|
+
this.app = opts.app
|
|
21
|
+
this.parentNode = opts.parentNode || opts.app.container
|
|
22
|
+
this.id = opts.id || 'button-' + Math.random()
|
|
23
|
+
|
|
24
|
+
// create HTML node
|
|
25
|
+
this.node = document.createElement('div')
|
|
26
|
+
this.node.id = this.id
|
|
27
|
+
if (opts.title) this.node.title = opts.title
|
|
28
|
+
if (opts.class) this.node.classList.add(opts.class)
|
|
29
|
+
|
|
30
|
+
// add events
|
|
31
|
+
if (opts.onClickFunction) this.node.addEventListener('onclick', opts.onClickFunction)
|
|
32
|
+
this.node.addEventListener('mouseover', (e)=>{this.node.style.backgroundColor = 'lightgrey'})
|
|
33
|
+
this.node.addEventListener('mouseout', (e)=>{this.node.style.backgroundColor = '#ffffff'})
|
|
34
|
+
|
|
35
|
+
//set styles
|
|
36
|
+
this.node.classList.add(opts.class)
|
|
37
|
+
this.node.style.boxShadow =
|
|
38
|
+
'0 7px 8px rgba(0,47,103,.08), 0 0 22px rgba(0,47,103,.04), 0 12px 17px rgba(0,47,103,.04), 0 -4px 4px rgba(0,47,103,.04)' //.ecl-u-shadow-3
|
|
39
|
+
this.node.style.backgroundColor = '#ffffff' //.ecl-u-bg-white
|
|
40
|
+
this.node.style.position = 'absolute'
|
|
41
|
+
this.node.style.cursor = 'pointer'
|
|
42
|
+
this.node.style.display = 'flex'
|
|
43
|
+
this.node.style.justifyContent = 'center'
|
|
44
|
+
this.node.style.alignItems = 'center'
|
|
45
|
+
this.node.style.width = '30px'
|
|
46
|
+
this.node.style.height = '30px'
|
|
47
|
+
// this.node.style.padding = '4px'
|
|
48
|
+
this.node.style.top = opts.y + 'px'
|
|
49
|
+
this.node.style.left = opts.x + 'px'
|
|
50
|
+
|
|
51
|
+
// append to parent
|
|
52
|
+
this.parentNode.appendChild(this.node)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Button } from './Button.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Button for toggling fullscreen mode
|
|
5
|
+
*
|
|
6
|
+
* @author Joseph Davies, Julien Gaffuri
|
|
7
|
+
*/
|
|
8
|
+
export class FullscreenButton extends Button {
|
|
9
|
+
/**
|
|
10
|
+
* @param {Object} opts
|
|
11
|
+
* opts.parentNode - the node that the button is appended to
|
|
12
|
+
* opts.canvas - the gridviz canvas
|
|
13
|
+
* opts.id
|
|
14
|
+
* opts.title - HTML title attribute
|
|
15
|
+
* opts.class - css class
|
|
16
|
+
* opts.onClickFunction
|
|
17
|
+
* opts.x - x position of the button
|
|
18
|
+
* opts.y - y position of the button
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
// default state
|
|
22
|
+
isFullscreen = false
|
|
23
|
+
|
|
24
|
+
constructor(opts) {
|
|
25
|
+
super(opts)
|
|
26
|
+
|
|
27
|
+
// append fullscreen icon to button container
|
|
28
|
+
this.node.innerHTML = `
|
|
29
|
+
<svg
|
|
30
|
+
style="height: 1.2rem; width: 1.2rem; fill:black; margin:0;"
|
|
31
|
+
focusable="false"
|
|
32
|
+
aria-hidden="true"
|
|
33
|
+
>
|
|
34
|
+
<svg fill="#000000" viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg">
|
|
35
|
+
<title/>
|
|
36
|
+
<g>
|
|
37
|
+
<path d="M30,0H6A5.9966,5.9966,0,0,0,0,6V30a6,6,0,0,0,12,0V12H30A6,6,0,0,0,30,0Z"/>
|
|
38
|
+
<path d="M90,0H66a6,6,0,0,0,0,12H84V30a6,6,0,0,0,12,0V6A5.9966,5.9966,0,0,0,90,0Z"/>
|
|
39
|
+
<path d="M30,84H12V66A6,6,0,0,0,0,66V90a5.9966,5.9966,0,0,0,6,6H30a6,6,0,0,0,0-12Z"/>
|
|
40
|
+
<path d="M90,60a5.9966,5.9966,0,0,0-6,6V84H66a6,6,0,0,0,0,12H90a5.9966,5.9966,0,0,0,6-6V66A5.9966,5.9966,0,0,0,90,60Z"/>
|
|
41
|
+
</g>
|
|
42
|
+
</svg>
|
|
43
|
+
</svg>
|
|
44
|
+
`
|
|
45
|
+
|
|
46
|
+
//save initial app dimensions
|
|
47
|
+
this.defaultHeight = this.app.h
|
|
48
|
+
this.defaultWidth = this.app.w
|
|
49
|
+
|
|
50
|
+
// event handler
|
|
51
|
+
this.node.addEventListener('click', (e) => {
|
|
52
|
+
this.onClickFunction(e)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
onClickFunction(e) {
|
|
58
|
+
if (this.isFullscreen) {
|
|
59
|
+
this.closeFullscreen(containerDiv)
|
|
60
|
+
//resize canvas to default
|
|
61
|
+
this.app.h = this.defaultHeight
|
|
62
|
+
this.app.w = this.defaultWidth
|
|
63
|
+
this.isFullscreen = false
|
|
64
|
+
} else {
|
|
65
|
+
this.openFullscreen(containerDiv)
|
|
66
|
+
//resize canvas to fullscreen
|
|
67
|
+
this.app.h = window.screen.height
|
|
68
|
+
this.app.w = window.screen.width
|
|
69
|
+
this.isFullscreen = true
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Open fullscreen */
|
|
74
|
+
openFullscreen(elem) {
|
|
75
|
+
if (elem.requestFullscreen) {
|
|
76
|
+
elem.requestFullscreen()
|
|
77
|
+
} else if (elem.webkitRequestFullscreen) {
|
|
78
|
+
/* Safari */
|
|
79
|
+
elem.webkitRequestFullscreen()
|
|
80
|
+
} else if (elem.msRequestFullscreen) {
|
|
81
|
+
/* IE11 */
|
|
82
|
+
elem.msRequestFullscreen()
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Close fullscreen */
|
|
87
|
+
closeFullscreen() {
|
|
88
|
+
if (document.exitFullscreen) {
|
|
89
|
+
document.exitFullscreen()
|
|
90
|
+
} else if (document.webkitExitFullscreen) {
|
|
91
|
+
/* Safari */
|
|
92
|
+
document.webkitExitFullscreen()
|
|
93
|
+
} else if (document.msExitFullscreen) {
|
|
94
|
+
/* IE11 */
|
|
95
|
+
document.msExitFullscreen()
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Button } from './Button.js'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Button for toggling fullscreen mode
|
|
6
|
+
*
|
|
7
|
+
* @author Joseph Davies, Julien Gaffuri
|
|
8
|
+
*/
|
|
9
|
+
export class ZoomButtons extends Button {
|
|
10
|
+
/**
|
|
11
|
+
* @param {Object} opts
|
|
12
|
+
*/
|
|
13
|
+
constructor(opts) {
|
|
14
|
+
super(opts)
|
|
15
|
+
|
|
16
|
+
this.onZoom = opts.onZoom // custom user event handler
|
|
17
|
+
this.delta = opts.delta || 0.2
|
|
18
|
+
|
|
19
|
+
// zoom in btn
|
|
20
|
+
this.zoomInBtn = document.createElement('a')
|
|
21
|
+
this.zoomInBtn.innerHTML = `<a id="zoomin" class="gridviz-zoom-button" title="Zoom in">+</a>`
|
|
22
|
+
this.zoomInBtn.title = 'Zoom in';
|
|
23
|
+
this.zoomInBtn.addEventListener('click', (e)=>{this.zoomIn(e)})
|
|
24
|
+
this.zoomInBtn.addEventListener('mouseover', (e)=>{this.zoomInBtn.style.backgroundColor = 'lightgrey'})
|
|
25
|
+
this.zoomInBtn.addEventListener('mouseout', (e)=>{this.zoomInBtn.style.backgroundColor = '#ffffff'})
|
|
26
|
+
|
|
27
|
+
// zoom out btn
|
|
28
|
+
this.zoomOutBtn = document.createElement('a')
|
|
29
|
+
this.zoomOutBtn.innerHTML = `<a id="zoomin" class="gridviz-zoom-button" title="Zoom out">-</a>`
|
|
30
|
+
this.zoomOutBtn.title = 'Zoom out';
|
|
31
|
+
this.zoomOutBtn.addEventListener('click', (e)=>{this.zoomOut(e)})
|
|
32
|
+
this.zoomOutBtn.addEventListener('mouseover', (e)=>{this.zoomOutBtn.style.backgroundColor = 'lightgrey'})
|
|
33
|
+
this.zoomOutBtn.addEventListener('mouseout', (e)=>{this.zoomOutBtn.style.backgroundColor = '#ffffff'})
|
|
34
|
+
|
|
35
|
+
//set styles
|
|
36
|
+
let btns = [this.zoomInBtn, this.zoomOutBtn]
|
|
37
|
+
btns.forEach((btn, i)=>{
|
|
38
|
+
btn.style.alignItems = 'center';
|
|
39
|
+
btn.style.justifyContent = 'center';
|
|
40
|
+
btn.style.display = 'flex';
|
|
41
|
+
btn.style.border = 'none';
|
|
42
|
+
btn.style.color = 'black';
|
|
43
|
+
btn.style.textAlign = 'center';
|
|
44
|
+
btn.style.textDecoration = 'none';
|
|
45
|
+
btn.style.padding = '4px';
|
|
46
|
+
btn.style.fontSize = '20px';
|
|
47
|
+
btn.style.fontWeight = 'bold';
|
|
48
|
+
btn.style.userSelect = 'none';
|
|
49
|
+
if (i==0) btn.style.borderBottom = '1px solid grey'
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
// unset parent class height
|
|
53
|
+
this.node.style.height="unset"
|
|
54
|
+
this.node.style.display="unset"
|
|
55
|
+
|
|
56
|
+
// append to button container
|
|
57
|
+
this.node.appendChild(this.zoomInBtn)
|
|
58
|
+
this.node.appendChild(this.zoomOutBtn)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Zoom in */
|
|
62
|
+
zoomIn(e) {
|
|
63
|
+
this.app.setZoomFactor(this.app.getZoomFactor() * (1 - this.delta)).redraw()
|
|
64
|
+
if (this.onZoom) this.onZoom(e)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Zoom out */
|
|
68
|
+
zoomOut(e) {
|
|
69
|
+
this.app.setZoomFactor(this.app.getZoomFactor() * (1 + this.delta)).redraw()
|
|
70
|
+
if (this.onZoom) this.onZoom(e)
|
|
71
|
+
}
|
|
72
|
+
}
|
package/src/dataset/COGeo.js
CHANGED
|
@@ -1,24 +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
|
-
}
|
|
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
|
+
}
|
package/src/dataset/CSVGrid.js
CHANGED
|
@@ -1,104 +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
|
-
}
|
|
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
|
+
}
|