gridviz 3.0.25 → 3.0.27
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 +128 -128
- package/dist/gridviz.js +8630 -8615
- package/dist/gridviz.min.js +1 -1
- package/package.json +74 -74
- package/src/button/Button.js +67 -67
- package/src/button/FullscreenButton.js +121 -121
- package/src/button/ZoomButtons.js +103 -103
- package/src/core/Dataset.js +154 -154
- package/src/core/Drawable.js +78 -78
- package/src/core/GeoCanvas.js +443 -438
- package/src/core/Layer.js +23 -23
- package/src/core/Legend.js +108 -108
- package/src/core/Map.js +544 -544
- package/src/core/MultiResolutionDataset.js +93 -93
- package/src/core/Style.js +98 -98
- package/src/core/Tooltip.js +182 -182
- package/src/dataset/COGeo.js +25 -25
- package/src/dataset/CSVGrid.js +112 -112
- package/src/dataset/GeoTIFF.js +122 -122
- package/src/dataset/JSGrid.js +55 -55
- package/src/dataset/TiledGrid.js +302 -302
- package/src/dataset/worker.js +18 -18
- package/src/index.js +77 -77
- package/src/layer/BackgroundLayer.js +173 -173
- package/src/layer/BackgroundLayerImage.js +81 -81
- package/src/layer/BackgroundLayerWMS.js +104 -104
- package/src/layer/GeoJSONLayer.js +224 -214
- package/src/layer/GridLayer.js +148 -148
- package/src/layer/LabelLayer.js +194 -194
- package/src/legend/ColorCategoryLegend.js +109 -109
- package/src/legend/ColorDiscreteLegend.js +100 -100
- package/src/legend/ColorLegend.js +115 -115
- package/src/legend/OrientationLegend.js +89 -89
- package/src/legend/SizeLegend.js +224 -224
- package/src/legend/TernaryLegend.js +302 -302
- package/src/style/CompositionStyle.js +291 -291
- package/src/style/ContourStyle.js +21 -21
- package/src/style/DotDensityStyle.js +133 -133
- package/src/style/ImageStyle.js +100 -100
- package/src/style/IsoFenceStyle.js +217 -217
- package/src/style/JoyPlotStyle.js +127 -127
- package/src/style/LegoStyle.js +110 -110
- package/src/style/MosaicStyle.js +99 -99
- package/src/style/NinjaStarStyle.js +102 -102
- package/src/style/PillarStyle.js +207 -207
- package/src/style/SegmentStyle.js +105 -105
- package/src/style/ShapeColorSizeStyle.js +147 -147
- package/src/style/SideCategoryStyle.js +112 -112
- package/src/style/SideStyle.js +212 -212
- package/src/style/SquareColorCategoryWebGLStyle.js +107 -107
- package/src/style/SquareColorWebGLStyle.js +126 -126
- package/src/style/StrokeStyle.js +135 -135
- package/src/style/TanakaStyle.js +69 -69
- package/src/style/TextStyle.js +110 -110
- package/src/style/TimeSeriesStyle.js +222 -222
- 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/scale.js +218 -218
- package/src/utils/stretching.js +120 -120
- package/src/utils/ternary.js +208 -208
- package/src/utils/utils.js +58 -58
- package/src/utils/webGLUtils.js +72 -72
- package/src/utils/zoomUtils.js +142 -142
|
@@ -1,103 +1,103 @@
|
|
|
1
|
-
import { Button } from './Button.js'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Button for toggling fullscreen mode
|
|
5
|
-
*
|
|
6
|
-
* @module button
|
|
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
|
-
// Create zoom in button
|
|
20
|
-
this.zoomInBtn = document.createElement('a')
|
|
21
|
-
this.zoomInBtn.id = 'zoom-in'
|
|
22
|
-
this.zoomInBtn.className = 'gridviz-zoom-button'
|
|
23
|
-
this.zoomInBtn.title = 'Zoom in'
|
|
24
|
-
this.zoomInBtn.textContent = '+'
|
|
25
|
-
this.zoomInBtn.addEventListener('click', (e) => {
|
|
26
|
-
this.zoomIn(e)
|
|
27
|
-
})
|
|
28
|
-
this.zoomInBtn.addEventListener('mouseover', () => {
|
|
29
|
-
this.zoomInBtn.style.backgroundColor = 'lightgrey'
|
|
30
|
-
})
|
|
31
|
-
this.zoomInBtn.addEventListener('mouseout', () => {
|
|
32
|
-
this.zoomInBtn.style.backgroundColor = '#ffffff'
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
// Create zoom out button
|
|
36
|
-
this.zoomOutBtn = document.createElement('a')
|
|
37
|
-
this.zoomOutBtn.id = 'zoom-out'
|
|
38
|
-
this.zoomOutBtn.className = 'gridviz-zoom-button'
|
|
39
|
-
this.zoomOutBtn.title = 'Zoom out'
|
|
40
|
-
this.zoomOutBtn.textContent = '-'
|
|
41
|
-
this.zoomOutBtn.addEventListener('click', (e) => {
|
|
42
|
-
this.zoomOut(e)
|
|
43
|
-
})
|
|
44
|
-
this.zoomOutBtn.addEventListener('mouseover', () => {
|
|
45
|
-
this.zoomOutBtn.style.backgroundColor = 'lightgrey'
|
|
46
|
-
})
|
|
47
|
-
this.zoomOutBtn.addEventListener('mouseout', () => {
|
|
48
|
-
this.zoomOutBtn.style.backgroundColor = '#ffffff'
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
// Set common styles for buttons
|
|
52
|
-
const buttons = [this.zoomInBtn, this.zoomOutBtn]
|
|
53
|
-
buttons.forEach((btn, index) => {
|
|
54
|
-
btn.style.alignItems = 'center'
|
|
55
|
-
btn.style.justifyContent = 'center'
|
|
56
|
-
btn.style.display = 'flex'
|
|
57
|
-
btn.style.border = 'none'
|
|
58
|
-
btn.style.color = 'black'
|
|
59
|
-
btn.style.textAlign = 'center'
|
|
60
|
-
btn.style.textDecoration = 'none'
|
|
61
|
-
btn.style.padding = '4px'
|
|
62
|
-
btn.style.fontSize = '24px'
|
|
63
|
-
btn.style.fontWeight = 'bold'
|
|
64
|
-
btn.style.userSelect = 'none'
|
|
65
|
-
btn.style.backgroundColor = '#ffffff'
|
|
66
|
-
if (index === 0) btn.style.borderBottom = '1px solid grey' // Zoom in button only
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
// Unset parent class height and display for dual buttons
|
|
70
|
-
this.style('height', 'unset')
|
|
71
|
-
this.style('display', 'unset')
|
|
72
|
-
|
|
73
|
-
// Set position
|
|
74
|
-
if (opts.x) {
|
|
75
|
-
this.style('left', opts.x + 'px')
|
|
76
|
-
} else {
|
|
77
|
-
this.style('right', '10px')
|
|
78
|
-
}
|
|
79
|
-
if (opts.y) {
|
|
80
|
-
this.style('top', opts.y + 'px')
|
|
81
|
-
} else {
|
|
82
|
-
this.style('top', '10px')
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Append buttons to the container
|
|
86
|
-
this.div.node().appendChild(this.zoomInBtn)
|
|
87
|
-
this.div.node().appendChild(this.zoomOutBtn)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/* Zoom in */
|
|
91
|
-
zoomIn(e) {
|
|
92
|
-
this.map.setZoom(this.map.getZoom() * (1 - this.delta)).redraw()
|
|
93
|
-
if (this.onZoom) this.onZoom(e)
|
|
94
|
-
if (this.map.geoCanvas.onZoomFun) this.map.geoCanvas.onZoomFun(e)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/* Zoom out */
|
|
98
|
-
zoomOut(e) {
|
|
99
|
-
this.map.setZoom(this.map.getZoom() * (1 + this.delta)).redraw()
|
|
100
|
-
if (this.onZoom) this.onZoom(e)
|
|
101
|
-
if (this.map.geoCanvas.onZoomFun) this.map.geoCanvas.onZoomFun(e)
|
|
102
|
-
}
|
|
103
|
-
}
|
|
1
|
+
import { Button } from './Button.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Button for toggling fullscreen mode
|
|
5
|
+
*
|
|
6
|
+
* @module button
|
|
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
|
+
// Create zoom in button
|
|
20
|
+
this.zoomInBtn = document.createElement('a')
|
|
21
|
+
this.zoomInBtn.id = 'zoom-in'
|
|
22
|
+
this.zoomInBtn.className = 'gridviz-zoom-button'
|
|
23
|
+
this.zoomInBtn.title = 'Zoom in'
|
|
24
|
+
this.zoomInBtn.textContent = '+'
|
|
25
|
+
this.zoomInBtn.addEventListener('click', (e) => {
|
|
26
|
+
this.zoomIn(e)
|
|
27
|
+
})
|
|
28
|
+
this.zoomInBtn.addEventListener('mouseover', () => {
|
|
29
|
+
this.zoomInBtn.style.backgroundColor = 'lightgrey'
|
|
30
|
+
})
|
|
31
|
+
this.zoomInBtn.addEventListener('mouseout', () => {
|
|
32
|
+
this.zoomInBtn.style.backgroundColor = '#ffffff'
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
// Create zoom out button
|
|
36
|
+
this.zoomOutBtn = document.createElement('a')
|
|
37
|
+
this.zoomOutBtn.id = 'zoom-out'
|
|
38
|
+
this.zoomOutBtn.className = 'gridviz-zoom-button'
|
|
39
|
+
this.zoomOutBtn.title = 'Zoom out'
|
|
40
|
+
this.zoomOutBtn.textContent = '-'
|
|
41
|
+
this.zoomOutBtn.addEventListener('click', (e) => {
|
|
42
|
+
this.zoomOut(e)
|
|
43
|
+
})
|
|
44
|
+
this.zoomOutBtn.addEventListener('mouseover', () => {
|
|
45
|
+
this.zoomOutBtn.style.backgroundColor = 'lightgrey'
|
|
46
|
+
})
|
|
47
|
+
this.zoomOutBtn.addEventListener('mouseout', () => {
|
|
48
|
+
this.zoomOutBtn.style.backgroundColor = '#ffffff'
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
// Set common styles for buttons
|
|
52
|
+
const buttons = [this.zoomInBtn, this.zoomOutBtn]
|
|
53
|
+
buttons.forEach((btn, index) => {
|
|
54
|
+
btn.style.alignItems = 'center'
|
|
55
|
+
btn.style.justifyContent = 'center'
|
|
56
|
+
btn.style.display = 'flex'
|
|
57
|
+
btn.style.border = 'none'
|
|
58
|
+
btn.style.color = 'black'
|
|
59
|
+
btn.style.textAlign = 'center'
|
|
60
|
+
btn.style.textDecoration = 'none'
|
|
61
|
+
btn.style.padding = '4px'
|
|
62
|
+
btn.style.fontSize = '24px'
|
|
63
|
+
btn.style.fontWeight = 'bold'
|
|
64
|
+
btn.style.userSelect = 'none'
|
|
65
|
+
btn.style.backgroundColor = '#ffffff'
|
|
66
|
+
if (index === 0) btn.style.borderBottom = '1px solid grey' // Zoom in button only
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
// Unset parent class height and display for dual buttons
|
|
70
|
+
this.style('height', 'unset')
|
|
71
|
+
this.style('display', 'unset')
|
|
72
|
+
|
|
73
|
+
// Set position
|
|
74
|
+
if (opts.x) {
|
|
75
|
+
this.style('left', opts.x + 'px')
|
|
76
|
+
} else {
|
|
77
|
+
this.style('right', '10px')
|
|
78
|
+
}
|
|
79
|
+
if (opts.y) {
|
|
80
|
+
this.style('top', opts.y + 'px')
|
|
81
|
+
} else {
|
|
82
|
+
this.style('top', '10px')
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Append buttons to the container
|
|
86
|
+
this.div.node().appendChild(this.zoomInBtn)
|
|
87
|
+
this.div.node().appendChild(this.zoomOutBtn)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* Zoom in */
|
|
91
|
+
zoomIn(e) {
|
|
92
|
+
this.map.setZoom(this.map.getZoom() * (1 - this.delta)).redraw()
|
|
93
|
+
if (this.onZoom) this.onZoom(e)
|
|
94
|
+
if (this.map.geoCanvas.onZoomFun) this.map.geoCanvas.onZoomFun(e)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* Zoom out */
|
|
98
|
+
zoomOut(e) {
|
|
99
|
+
this.map.setZoom(this.map.getZoom() * (1 + this.delta)).redraw()
|
|
100
|
+
if (this.onZoom) this.onZoom(e)
|
|
101
|
+
if (this.map.geoCanvas.onZoomFun) this.map.geoCanvas.onZoomFun(e)
|
|
102
|
+
}
|
|
103
|
+
}
|
package/src/core/Dataset.js
CHANGED
|
@@ -1,154 +1,154 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* A grid cell.
|
|
6
|
-
* @typedef {{x: number, y: number}} Cell */
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* A dataset component, of grid cells.
|
|
10
|
-
* @abstract
|
|
11
|
-
*
|
|
12
|
-
* @module core
|
|
13
|
-
* @author Joseph Davies, Julien Gaffuri
|
|
14
|
-
*/
|
|
15
|
-
export class Dataset {
|
|
16
|
-
/**
|
|
17
|
-
* @param {import("./Map.js").Map} map The map.
|
|
18
|
-
* @param {string} url The URL of the dataset.
|
|
19
|
-
* @param {number} resolution The dataset resolution, in the CRS geographical unit.
|
|
20
|
-
* @param {{preprocess?:function(Cell):boolean, mixedResolution?:function(Cell):number}} opts
|
|
21
|
-
* @abstract
|
|
22
|
-
*/
|
|
23
|
-
constructor(map, url, resolution, opts = {}) {
|
|
24
|
-
/**
|
|
25
|
-
* The map.
|
|
26
|
-
* @protected
|
|
27
|
-
* @type {import("./Map.js").Map} */
|
|
28
|
-
this.map = map
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* The url of the dataset.
|
|
32
|
-
* @protected
|
|
33
|
-
* @type {string} */
|
|
34
|
-
this.url = url
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* The dataset resolution in geographical unit.
|
|
38
|
-
* @protected
|
|
39
|
-
* @type {number} */
|
|
40
|
-
this.resolution = resolution
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* In case the dataset is a dataset with cells having different resolution,
|
|
44
|
-
* this is the function returning the resolution of each cell.
|
|
45
|
-
* @protected
|
|
46
|
-
* @type {(function(Cell):number )| undefined } */
|
|
47
|
-
this.mixedResolution = opts.mixedResolution
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* 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.
|
|
51
|
-
* @type {(function(Cell):boolean )| undefined } */
|
|
52
|
-
this.preprocess = opts.preprocess || undefined
|
|
53
|
-
|
|
54
|
-
/** The cells within the view
|
|
55
|
-
* @protected
|
|
56
|
-
* @type {Array.<Cell>} */
|
|
57
|
-
this.cellsViewCache = []
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Request data within a geographic envelope.
|
|
62
|
-
*
|
|
63
|
-
* @abstract
|
|
64
|
-
* @param {import("./GeoCanvas").Envelope|undefined} extGeo
|
|
65
|
-
* @returns {this}
|
|
66
|
-
*/
|
|
67
|
-
getData(extGeo = undefined) {
|
|
68
|
-
throw new Error('Method getData not implemented.')
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Fill the view cache with all cells which are within a geographical envelope.
|
|
73
|
-
* @abstract
|
|
74
|
-
* @param {import("./GeoCanvas").Envelope} extGeo The view geographical envelope.
|
|
75
|
-
* @returns {void}
|
|
76
|
-
*/
|
|
77
|
-
updateViewCache(extGeo) {
|
|
78
|
-
throw new Error('Method updateViewCache not implemented.')
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Get a cell under a given position, if any.
|
|
83
|
-
*
|
|
84
|
-
* @param {{x:number,y:number}} posGeo
|
|
85
|
-
* @param {Array.<Cell>} cells Some cells from the dataset (a subset if necessary, usually the view cache).
|
|
86
|
-
* @returns {Cell|undefined}
|
|
87
|
-
*/
|
|
88
|
-
getCellFromPosition(posGeo, cells) {
|
|
89
|
-
//compute candidate cell position
|
|
90
|
-
/** @type {number} */
|
|
91
|
-
//const r = this.getResolution()
|
|
92
|
-
/** @type {number} */
|
|
93
|
-
//const cellX = r * Math.floor(posGeo.x / r)
|
|
94
|
-
/** @type {number} */
|
|
95
|
-
//const cellY = r * Math.floor(posGeo.y / r)
|
|
96
|
-
|
|
97
|
-
/*/get cell
|
|
98
|
-
for (const cell of cells) {
|
|
99
|
-
if (cell.x != cellX) continue
|
|
100
|
-
if (cell.y != cellY) continue
|
|
101
|
-
return cell
|
|
102
|
-
}
|
|
103
|
-
return undefined*/
|
|
104
|
-
|
|
105
|
-
//rare case of mixed resolution dataset
|
|
106
|
-
if (this.mixedResolution) {
|
|
107
|
-
for (const c of cells) {
|
|
108
|
-
/** @type {number} */
|
|
109
|
-
const r = +this.mixedResolution(c)
|
|
110
|
-
if (posGeo.x < c.x) continue
|
|
111
|
-
else if (c.x + r < posGeo.x) continue
|
|
112
|
-
else if (posGeo.y < c.y) continue
|
|
113
|
-
else if (c.y + r < posGeo.y) continue
|
|
114
|
-
else return c
|
|
115
|
-
}
|
|
116
|
-
return undefined
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
//common case
|
|
120
|
-
|
|
121
|
-
/** @type {number} */
|
|
122
|
-
const r = this.getResolution()
|
|
123
|
-
for (const cell of cells) {
|
|
124
|
-
if (posGeo.x < cell.x) continue
|
|
125
|
-
else if (cell.x + r < posGeo.x) continue
|
|
126
|
-
else if (posGeo.y < cell.y) continue
|
|
127
|
-
else if (cell.y + r < posGeo.y) continue
|
|
128
|
-
else return cell
|
|
129
|
-
}
|
|
130
|
-
return undefined
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
//getters and setters
|
|
134
|
-
|
|
135
|
-
/** @returns {number} */
|
|
136
|
-
getResolution() {
|
|
137
|
-
return this.resolution
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/** @returns {Array.<Cell>} */
|
|
141
|
-
getViewCache() {
|
|
142
|
-
return this.cellsViewCache
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Return the relevant dataset for a specified zoom.
|
|
147
|
-
* @param {number} z
|
|
148
|
-
* @param {number} minPixelsPerCell
|
|
149
|
-
* @returns {Dataset|undefined}
|
|
150
|
-
* */
|
|
151
|
-
getDataset(z, minPixelsPerCell) {
|
|
152
|
-
return this
|
|
153
|
-
}
|
|
154
|
-
}
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A grid cell.
|
|
6
|
+
* @typedef {{x: number, y: number}} Cell */
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A dataset component, of grid cells.
|
|
10
|
+
* @abstract
|
|
11
|
+
*
|
|
12
|
+
* @module core
|
|
13
|
+
* @author Joseph Davies, Julien Gaffuri
|
|
14
|
+
*/
|
|
15
|
+
export class Dataset {
|
|
16
|
+
/**
|
|
17
|
+
* @param {import("./Map.js").Map} map The map.
|
|
18
|
+
* @param {string} url The URL of the dataset.
|
|
19
|
+
* @param {number} resolution The dataset resolution, in the CRS geographical unit.
|
|
20
|
+
* @param {{preprocess?:function(Cell):boolean, mixedResolution?:function(Cell):number}} opts
|
|
21
|
+
* @abstract
|
|
22
|
+
*/
|
|
23
|
+
constructor(map, url, resolution, opts = {}) {
|
|
24
|
+
/**
|
|
25
|
+
* The map.
|
|
26
|
+
* @protected
|
|
27
|
+
* @type {import("./Map.js").Map} */
|
|
28
|
+
this.map = map
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The url of the dataset.
|
|
32
|
+
* @protected
|
|
33
|
+
* @type {string} */
|
|
34
|
+
this.url = url
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The dataset resolution in geographical unit.
|
|
38
|
+
* @protected
|
|
39
|
+
* @type {number} */
|
|
40
|
+
this.resolution = resolution
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* In case the dataset is a dataset with cells having different resolution,
|
|
44
|
+
* this is the function returning the resolution of each cell.
|
|
45
|
+
* @protected
|
|
46
|
+
* @type {(function(Cell):number )| undefined } */
|
|
47
|
+
this.mixedResolution = opts.mixedResolution
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 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.
|
|
51
|
+
* @type {(function(Cell):boolean )| undefined } */
|
|
52
|
+
this.preprocess = opts.preprocess || undefined
|
|
53
|
+
|
|
54
|
+
/** The cells within the view
|
|
55
|
+
* @protected
|
|
56
|
+
* @type {Array.<Cell>} */
|
|
57
|
+
this.cellsViewCache = []
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Request data within a geographic envelope.
|
|
62
|
+
*
|
|
63
|
+
* @abstract
|
|
64
|
+
* @param {import("./GeoCanvas").Envelope|undefined} extGeo
|
|
65
|
+
* @returns {this}
|
|
66
|
+
*/
|
|
67
|
+
getData(extGeo = undefined) {
|
|
68
|
+
throw new Error('Method getData not implemented.')
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Fill the view cache with all cells which are within a geographical envelope.
|
|
73
|
+
* @abstract
|
|
74
|
+
* @param {import("./GeoCanvas").Envelope} extGeo The view geographical envelope.
|
|
75
|
+
* @returns {void}
|
|
76
|
+
*/
|
|
77
|
+
updateViewCache(extGeo) {
|
|
78
|
+
throw new Error('Method updateViewCache not implemented.')
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get a cell under a given position, if any.
|
|
83
|
+
*
|
|
84
|
+
* @param {{x:number,y:number}} posGeo
|
|
85
|
+
* @param {Array.<Cell>} cells Some cells from the dataset (a subset if necessary, usually the view cache).
|
|
86
|
+
* @returns {Cell|undefined}
|
|
87
|
+
*/
|
|
88
|
+
getCellFromPosition(posGeo, cells) {
|
|
89
|
+
//compute candidate cell position
|
|
90
|
+
/** @type {number} */
|
|
91
|
+
//const r = this.getResolution()
|
|
92
|
+
/** @type {number} */
|
|
93
|
+
//const cellX = r * Math.floor(posGeo.x / r)
|
|
94
|
+
/** @type {number} */
|
|
95
|
+
//const cellY = r * Math.floor(posGeo.y / r)
|
|
96
|
+
|
|
97
|
+
/*/get cell
|
|
98
|
+
for (const cell of cells) {
|
|
99
|
+
if (cell.x != cellX) continue
|
|
100
|
+
if (cell.y != cellY) continue
|
|
101
|
+
return cell
|
|
102
|
+
}
|
|
103
|
+
return undefined*/
|
|
104
|
+
|
|
105
|
+
//rare case of mixed resolution dataset
|
|
106
|
+
if (this.mixedResolution) {
|
|
107
|
+
for (const c of cells) {
|
|
108
|
+
/** @type {number} */
|
|
109
|
+
const r = +this.mixedResolution(c)
|
|
110
|
+
if (posGeo.x < c.x) continue
|
|
111
|
+
else if (c.x + r < posGeo.x) continue
|
|
112
|
+
else if (posGeo.y < c.y) continue
|
|
113
|
+
else if (c.y + r < posGeo.y) continue
|
|
114
|
+
else return c
|
|
115
|
+
}
|
|
116
|
+
return undefined
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
//common case
|
|
120
|
+
|
|
121
|
+
/** @type {number} */
|
|
122
|
+
const r = this.getResolution()
|
|
123
|
+
for (const cell of cells) {
|
|
124
|
+
if (posGeo.x < cell.x) continue
|
|
125
|
+
else if (cell.x + r < posGeo.x) continue
|
|
126
|
+
else if (posGeo.y < cell.y) continue
|
|
127
|
+
else if (cell.y + r < posGeo.y) continue
|
|
128
|
+
else return cell
|
|
129
|
+
}
|
|
130
|
+
return undefined
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
//getters and setters
|
|
134
|
+
|
|
135
|
+
/** @returns {number} */
|
|
136
|
+
getResolution() {
|
|
137
|
+
return this.resolution
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** @returns {Array.<Cell>} */
|
|
141
|
+
getViewCache() {
|
|
142
|
+
return this.cellsViewCache
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Return the relevant dataset for a specified zoom.
|
|
147
|
+
* @param {number} z
|
|
148
|
+
* @param {number} minPixelsPerCell
|
|
149
|
+
* @returns {Dataset|undefined}
|
|
150
|
+
* */
|
|
151
|
+
getDataset(z, minPixelsPerCell) {
|
|
152
|
+
return this
|
|
153
|
+
}
|
|
154
|
+
}
|
package/src/core/Drawable.js
CHANGED
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* This is an abstract class used to group elements shared between Layer and Style classes.
|
|
6
|
-
*
|
|
7
|
-
* @abstract
|
|
8
|
-
* @module core
|
|
9
|
-
* @author Joseph Davies, Julien Gaffuri
|
|
10
|
-
*/
|
|
11
|
-
export class Drawable {
|
|
12
|
-
/**
|
|
13
|
-
* @param {object} opts
|
|
14
|
-
*/
|
|
15
|
-
constructor(opts) {
|
|
16
|
-
opts = opts || {}
|
|
17
|
-
|
|
18
|
-
/** A function specifying if the element should be visible or not.
|
|
19
|
-
* The function parameter is the zoom level.
|
|
20
|
-
* @type {function(number):boolean} */
|
|
21
|
-
this.visible = opts.visible
|
|
22
|
-
|
|
23
|
-
/** A function returning the alpha (transparency/opacity), between 0.0 (fully transparent) and 1.0 (fully opaque).
|
|
24
|
-
* The function parameter is the zoom level.
|
|
25
|
-
* (see CanvasRenderingContext2D: globalAlpha property)
|
|
26
|
-
* @type {(function(number):number)|undefined} */
|
|
27
|
-
this.alpha = opts.alpha
|
|
28
|
-
|
|
29
|
-
/** A function returning the blend operation.
|
|
30
|
-
* The function parameter is the zoom level.
|
|
31
|
-
* (see CanvasRenderingContext2D: globalCompositeOperation property)
|
|
32
|
-
* @type {function(number):GlobalCompositeOperation} */
|
|
33
|
-
this.blendOperation = opts.blendOperation || ((z) => 'source-over')
|
|
34
|
-
|
|
35
|
-
/** @type {(function(number):string)|undefined} */
|
|
36
|
-
this.filterColor = opts.filterColor // (z) => "#eee7"
|
|
37
|
-
/** @type {(function(number):GlobalCompositeOperation|"none")|undefined} */
|
|
38
|
-
this.filterBlendOperation = opts.filterBlendOperation // (z) => "multiply"
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Draw layer filter.
|
|
43
|
-
*
|
|
44
|
-
* @param {import("./GeoCanvas.js").GeoCanvas} geoCanvas The canvas where to draw the layer.
|
|
45
|
-
* @returns {void}
|
|
46
|
-
* @abstract
|
|
47
|
-
*/
|
|
48
|
-
drawFilter(geoCanvas) {
|
|
49
|
-
//no filter: return
|
|
50
|
-
if (!this.filterColor) return
|
|
51
|
-
|
|
52
|
-
//get filter
|
|
53
|
-
const fc = this.filterColor(geoCanvas.view.z)
|
|
54
|
-
|
|
55
|
-
//no filter: return
|
|
56
|
-
if (!fc || fc == 'none') return
|
|
57
|
-
|
|
58
|
-
//draw filter
|
|
59
|
-
|
|
60
|
-
//set color
|
|
61
|
-
geoCanvas.offscreenCtx.fillStyle = fc
|
|
62
|
-
|
|
63
|
-
//save blend mode and set new, if any
|
|
64
|
-
let bo = undefined, bo2 = undefined
|
|
65
|
-
if (this.filterBlendOperation) {
|
|
66
|
-
bo = geoCanvas.offscreenCtx.globalCompositeOperation
|
|
67
|
-
bo2 = this.filterBlendOperation(geoCanvas.view.z)
|
|
68
|
-
}
|
|
69
|
-
if (bo2 && bo2 != "none") geoCanvas.offscreenCtx.globalCompositeOperation = bo2;
|
|
70
|
-
|
|
71
|
-
//draw
|
|
72
|
-
geoCanvas.offscreenCtx.fillRect(0, 0, geoCanvas.w, geoCanvas.h)
|
|
73
|
-
|
|
74
|
-
//restore blend mode
|
|
75
|
-
if (bo) geoCanvas.offscreenCtx.globalCompositeOperation = bo;
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
}
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* This is an abstract class used to group elements shared between Layer and Style classes.
|
|
6
|
+
*
|
|
7
|
+
* @abstract
|
|
8
|
+
* @module core
|
|
9
|
+
* @author Joseph Davies, Julien Gaffuri
|
|
10
|
+
*/
|
|
11
|
+
export class Drawable {
|
|
12
|
+
/**
|
|
13
|
+
* @param {object} opts
|
|
14
|
+
*/
|
|
15
|
+
constructor(opts) {
|
|
16
|
+
opts = opts || {}
|
|
17
|
+
|
|
18
|
+
/** A function specifying if the element should be visible or not.
|
|
19
|
+
* The function parameter is the zoom level.
|
|
20
|
+
* @type {function(number):boolean} */
|
|
21
|
+
this.visible = opts.visible
|
|
22
|
+
|
|
23
|
+
/** A function returning the alpha (transparency/opacity), between 0.0 (fully transparent) and 1.0 (fully opaque).
|
|
24
|
+
* The function parameter is the zoom level.
|
|
25
|
+
* (see CanvasRenderingContext2D: globalAlpha property)
|
|
26
|
+
* @type {(function(number):number)|undefined} */
|
|
27
|
+
this.alpha = opts.alpha
|
|
28
|
+
|
|
29
|
+
/** A function returning the blend operation.
|
|
30
|
+
* The function parameter is the zoom level.
|
|
31
|
+
* (see CanvasRenderingContext2D: globalCompositeOperation property)
|
|
32
|
+
* @type {function(number):GlobalCompositeOperation} */
|
|
33
|
+
this.blendOperation = opts.blendOperation || ((z) => 'source-over')
|
|
34
|
+
|
|
35
|
+
/** @type {(function(number):string)|undefined} */
|
|
36
|
+
this.filterColor = opts.filterColor // (z) => "#eee7"
|
|
37
|
+
/** @type {(function(number):GlobalCompositeOperation|"none")|undefined} */
|
|
38
|
+
this.filterBlendOperation = opts.filterBlendOperation // (z) => "multiply"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Draw layer filter.
|
|
43
|
+
*
|
|
44
|
+
* @param {import("./GeoCanvas.js").GeoCanvas} geoCanvas The canvas where to draw the layer.
|
|
45
|
+
* @returns {void}
|
|
46
|
+
* @abstract
|
|
47
|
+
*/
|
|
48
|
+
drawFilter(geoCanvas) {
|
|
49
|
+
//no filter: return
|
|
50
|
+
if (!this.filterColor) return
|
|
51
|
+
|
|
52
|
+
//get filter
|
|
53
|
+
const fc = this.filterColor(geoCanvas.view.z)
|
|
54
|
+
|
|
55
|
+
//no filter: return
|
|
56
|
+
if (!fc || fc == 'none') return
|
|
57
|
+
|
|
58
|
+
//draw filter
|
|
59
|
+
|
|
60
|
+
//set color
|
|
61
|
+
geoCanvas.offscreenCtx.fillStyle = fc
|
|
62
|
+
|
|
63
|
+
//save blend mode and set new, if any
|
|
64
|
+
let bo = undefined, bo2 = undefined
|
|
65
|
+
if (this.filterBlendOperation) {
|
|
66
|
+
bo = geoCanvas.offscreenCtx.globalCompositeOperation
|
|
67
|
+
bo2 = this.filterBlendOperation(geoCanvas.view.z)
|
|
68
|
+
}
|
|
69
|
+
if (bo2 && bo2 != "none") geoCanvas.offscreenCtx.globalCompositeOperation = bo2;
|
|
70
|
+
|
|
71
|
+
//draw
|
|
72
|
+
geoCanvas.offscreenCtx.fillRect(0, 0, geoCanvas.w, geoCanvas.h)
|
|
73
|
+
|
|
74
|
+
//restore blend mode
|
|
75
|
+
if (bo) geoCanvas.offscreenCtx.globalCompositeOperation = bo;
|
|
76
|
+
|
|
77
|
+
}
|
|
78
|
+
}
|