# 八.海面上升
需求背景
模拟陆地随着海平面上升呈现的地图面貌
# 1.WMTS 模拟海面上升
查看代码详情
<template>
<div>
<div ref="map" class="map"></div>
<label>
海平面上升高度:
<input ref="slider" type="range" value="10" max="100" min="-1" />
</label>
<span ref="theinfo"></span>
</div>
</template>
<script>
export default {
mounted() {
let {
proj: { get: getProjection },
Map,
View,
layer: { Tile: TileLayer },
source: { OSM, WMTS },
extent: { getTopLeft, getWidth },
tilegrid: { WMTS: WMTSTileGrid },
} = ol;
const projection = getProjection("EPSG:3857");
const tileSizePixels = 256;
const tileSizeMtrs = getWidth(projection.getExtent()) / tileSizePixels;
const matrixIds = [];
const resolutions = [];
for (let i = 0; i <= 14; i++) {
matrixIds[i] = i;
resolutions[i] = tileSizeMtrs / Math.pow(2, i);
}
const tileGrid = new WMTSTileGrid({
origin: getTopLeft(projection.getExtent()),
resolutions: resolutions,
matrixIds: matrixIds,
});
const wmtsSource = new WMTS({
url: "https://ts2.scalgo.com/olpatch/wmts?token=" + mapkeys.scalgo,
layer: "SRTM_4_1:SRTM_4_1_flooded_sealevels",
format: "image/png",
matrixSet: "EPSG:3857",
attributions: [
'<a href="https://scalgo.com" target="_blank">SCALGO</a>',
'<a href="https://cgiarcsi.community/data/' +
'srtm-90m-digital-elevation-database-v4-1"' +
' target="_blank">CGIAR-CSI SRTM</a>',
],
tileGrid: tileGrid,
style: "default",
dimensions: {
threshold: 100,
},
});
const map = new Map({
target: this.$refs.map,
view: new View({
projection: projection,
center: [12579156, 3274244],
zoom: 6,
}),
layers: [
new TileLayer({
source: new OSM(),
}),
new TileLayer({
opacity: 0.5,
source: wmtsSource,
}),
],
});
const slider = this.$refs.slider;
const updateSourceDimension = function () {
wmtsSource.updateDimensions({ threshold: slider.value });
this.$refs.theinfo.innerHTML = slider.value + " 米";
}.bind(this);
slider.addEventListener("input", updateSourceDimension);
slider.addEventListener("change", updateSourceDimension);
updateSourceDimension();
},
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# 2.XYZ 模拟海平面上升
查看代码详情
<template>
<div>
<div ref="map" class="map"></div>
<label>
海平面
<input ref="level" type="range" min="0" max="100" value="1" />
+<span ref="output"></span> m
</label>
<br />
Go to
<a class="location" data-center="-122.3267,37.8377" data-zoom="11">旧金山</a
>,
<a class="location" data-center="-73.9338,40.6861" data-zoom="11">纽约</a>,
<a class="location" data-center="72.9481,18.9929" data-zoom="11">孟买</a>,
or
<a class="location" data-center="120.831,31.160" data-zoom="9">上海</a>
</div>
</template>
<script>
export default {
mounted() {
let {
Map,
View,
layer: { Tile: TileLayer, Image: ImageLayer },
source: { XYZ, Raster: RasterSource },
proj: { fromLonLat },
} = ol;
function flood(pixels, data) {
const pixel = pixels[0];
if (pixel[3]) {
const height =
-10000 + (pixel[0] * 256 * 256 + pixel[1] * 256 + pixel[2]) * 0.1;
if (height <= data.level) {
pixel[0] = 134;
pixel[1] = 203;
pixel[2] = 249;
pixel[3] = 255;
} else {
pixel[3] = 0;
}
}
return pixel;
}
const attributions =
'<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
const elevation = new XYZ({
url:
"https://api.maptiler.com/tiles/terrain-rgb/{z}/{x}/{y}.png?key=" +
mapkeys.maptiler,
tileSize: 512,
maxZoom: 12,
crossOrigin: "",
interpolate: false,
});
const raster = new RasterSource({
sources: [elevation],
operation: flood,
});
const map = new Map({
target: this.$refs.map,
layers: [
new TileLayer({
source: new XYZ({
attributions: attributions,
url:
"https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=" +
mapkeys.maptiler,
tileSize: 512,
maxZoom: 22,
}),
}),
new ImageLayer({
opacity: 0.6,
source: raster,
}),
],
view: new View({
center: fromLonLat([-122.3267, 37.8377]),
zoom: 11,
}),
});
const control = this.$refs.level;
const output = this.$refs.output;
const listener = function () {
output.innerText = control.value;
raster.changed();
};
control.addEventListener("input", listener);
control.addEventListener("change", listener);
output.innerText = control.value;
raster.on("beforeoperations", function (event) {
event.data.level = control.value;
});
const locations = document.getElementsByClassName("location");
for (let i = 0, ii = locations.length; i < ii; ++i) {
locations[i].addEventListener("click", relocate);
}
function relocate(event) {
const data = event.target.dataset;
const view = map.getView();
view.setCenter(fromLonLat(data.center.split(",").map(Number)));
view.setZoom(Number(data.zoom));
}
},
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# 3.WebGL+XYZ 模拟海平面上升
查看代码详情
<template>
<div>
<div ref="map" class="map"></div>
<label>
Sea level
<input ref="level" type="range" min="0" max="100" value="1" />
+<span ref="output"></span> m
</label>
<br />
Go to
<a class="location" data-center="-122.3267,37.8377" data-zoom="11">旧金山</a
>,
<a class="location" data-center="-73.9338,40.6861" data-zoom="11">纽约</a>,
<a class="location" data-center="72.9481,18.9929" data-zoom="11">孟买</a>,
or
<a class="location" data-center="120.831,31.160" data-zoom="9">上海</a>
</div>
</template>
<script>
export default {
mounted() {
let {
Map,
View,
layer: { WebGLTile: TileLayer },
source: { XYZ },
proj: { fromLonLat },
} = ol;
const attributions =
'<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
const elevation = [
"+",
-10000,
[
"*",
0.1 * 255,
[
"+",
["*", 256 * 256, ["band", 1]],
["+", ["*", 256, ["band", 2]], ["band", 3]],
],
],
];
const layer = new TileLayer({
opacity: 0.6,
source: new XYZ({
url:
"https://api.maptiler.com/tiles/terrain-rgb/{z}/{x}/{y}.png?key=" +
mapkeys.maptiler,
tileSize: 512,
maxZoom: 12,
}),
style: {
variables: {
level: 0,
},
color: [
"case",
["<=", elevation, ["var", "level"]],
[139, 212, 255, 1],
[139, 212, 255, 0],
],
},
});
const map = new Map({
target: this.$refs.map,
layers: [
new TileLayer({
source: new XYZ({
url:
"https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=" +
mapkeys.maptiler,
attributions: attributions,
tileSize: 512,
maxZoom: 22,
}),
}),
layer,
],
view: new View({
center: fromLonLat([-122.3267, 37.8377]),
zoom: 11,
}),
});
const control = this.$refs.level;
const output = this.$refs.output;
const listener = function () {
output.innerText = control.value;
layer.updateStyleVariables({ level: parseFloat(control.value) });
};
control.addEventListener("input", listener);
control.addEventListener("change", listener);
output.innerText = control.value;
const locations = document.getElementsByClassName("location");
for (let i = 0, ii = locations.length; i < ii; ++i) {
locations[i].addEventListener("click", relocate);
}
function relocate(event) {
const data = event.target.dataset;
const view = map.getView();
view.setCenter(fromLonLat(data.center.split(",").map(Number)));
view.setZoom(Number(data.zoom));
}
},
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
← 七.比例线