gridviz 2.0.45 → 2.0.46
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 +119 -119
- package/dist/gridviz.js +6937 -6937
- package/package.json +76 -76
- package/src/App.js +668 -668
- package/src/BackgroundLayer.js +182 -182
- package/src/BackgroundLayerWMS.js +131 -131
- package/src/Dataset.js +76 -76
- package/src/DatasetComponent.js +101 -101
- package/src/GeoCanvas.js +420 -420
- package/src/LabelLayer.js +190 -190
- package/src/Layer.js +92 -92
- package/src/Legend.js +86 -86
- package/src/LineLayer.js +150 -150
- package/src/Style.js +114 -114
- package/src/Tooltip.js +172 -172
- 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/TiledGrid.js +264 -264
- package/src/index.js +177 -176
- package/src/legend/ColorCategoryLegend.js +124 -124
- package/src/legend/ColorDiscreteLegend.js +103 -103
- package/src/legend/ColorLegend.js +124 -124
- package/src/legend/SegmentOrientationLegend.js +87 -87
- package/src/legend/SegmentWidthLegend.js +97 -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/JoyPlotStyle.js +135 -135
- package/src/style/LegoStyle.js +112 -112
- package/src/style/MosaicStyle.js +107 -107
- package/src/style/NinjaStarStyle.js +124 -124
- package/src/style/PillarStyle.js +230 -230
- package/src/style/SegmentStyle.js +142 -142
- package/src/style/ShapeColorSizeStyle.js +126 -126
- package/src/style/SideCatStyle.js +172 -172
- package/src/style/SideStyle.js +218 -218
- 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/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
package/src/BackgroundLayer.js
CHANGED
|
@@ -1,182 +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
|
-
}
|
|
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
|
+
}
|
|
@@ -1,131 +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
|
-
}
|
|
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
|
+
}
|