原文链接及内容

: 本例使用的功能不是稳定API的一部分,可能会在不同版本之间发生变化。请参考API文档以了解最新版本中支持的内容。

运行界面

这个例子展示了如何使用ol/layer/WebGLPoints字面样式(literal style)动态过滤大量的点几何图形。上面的地图是基于NASA的数据集,其中包含了45k个记录的陨石着陆点。每颗陨石在地图上都用一个圆圈标出(圆圈越大,物体越重)。还增加了一个脉冲效果,它会被影响年份略微抵消。

调整要渲染的年份

调整地图下面的滑块会导致日期范围之外的要素对象被过滤出地图,这是通过改变WebGL图层的样式对象中的变量来实现的。还要注意,最后的代码片段是必要的,以确保地图每帧都会刷新自己。

main.js代码如下:

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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import Feature from 'ol/Feature.js';
import Map from 'ol/Map.js';
import Point from 'ol/geom/Point.js';
import Stamen from 'ol/source/Stamen.js';
import TileLayer from 'ol/layer/Tile.js';
import View from 'ol/View.js';
import WebGLPointsLayer from 'ol/layer/WebGLPoints.js';
import {Vector} from 'ol/source.js';
import {fromLonLat} from 'ol/proj.js';

const vectorSource = new Vector({
attributions: 'NASA',
});

const oldColor = 'rgba(242,56,22,0.61)';
const newColor = '#ffe52c';
const period = 12; // animation period in seconds
const animRatio = [
'^',
[
'/',
[
'%',
[
'+',
['time'],
['interpolate', ['linear'], ['get', 'year'], 1850, 0, 2015, period],
],
period,
],
period,
],
0.5,
];

const style = {
variables: {
minYear: 1850,
maxYear: 2015,
},
filter: ['between', ['get', 'year'], ['var', 'minYear'], ['var', 'maxYear']],
symbol: {
symbolType: 'circle',
size: [
'*',
['interpolate', ['linear'], ['get', 'mass'], 0, 8, 200000, 26],
['-', 1.75, ['*', animRatio, 0.75]],
],
color: ['interpolate', ['linear'], animRatio, 0, newColor, 1, oldColor],
opacity: ['-', 1.0, ['*', animRatio, 0.75]],
},
};

// handle input values & events
const minYearInput = document.getElementById('min-year');
const maxYearInput = document.getElementById('max-year');

function updateStatusText() {
const div = document.getElementById('status');
div.querySelector('span.min-year').textContent = minYearInput.value;
div.querySelector('span.max-year').textContent = maxYearInput.value;
}

minYearInput.addEventListener('input', function () {
style.variables.minYear = parseInt(minYearInput.value);
updateStatusText();
});
maxYearInput.addEventListener('input', function () {
style.variables.maxYear = parseInt(maxYearInput.value);
updateStatusText();
});
updateStatusText();

// load data;
const client = new XMLHttpRequest();
client.open('GET', 'data/csv/meteorite_landings.csv');
client.onload = function () {
const csv = client.responseText;
const features = [];

let prevIndex = csv.indexOf('\n') + 1; // scan past the header line

let curIndex;
while ((curIndex = csv.indexOf('\n', prevIndex)) != -1) {
const line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
prevIndex = curIndex + 1;

const coords = fromLonLat([parseFloat(line[4]), parseFloat(line[3])]);
if (isNaN(coords[0]) || isNaN(coords[1])) {
// guard against bad data
continue;
}

features.push(
new Feature({
mass: parseFloat(line[1]) || 0,
year: parseInt(line[2]) || 0,
geometry: new Point(coords),
})
);
}

vectorSource.addFeatures(features);
};
client.send();

const map = new Map({
layers: [
new TileLayer({
source: new Stamen({
layer: 'toner',
}),
}),
new WebGLPointsLayer({
style: style,
source: vectorSource,
disableHitDetection: true,
}),
],
target: document.getElementById('map'),
view: new View({
center: [0, 0],
zoom: 2,
}),
});

// animate the map
function animate() {
map.render();
window.requestAnimationFrame(animate);
}
animate();

界面布局文件index.html代码如下:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Filtering features with WebGL</title>
<link rel="stylesheet" href="node_modules/ol/ol.css">
<style>
.map {
width: 100%;
height: 400px;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<form>
<div id="status">Show impacts between <span class="min-year"></span> and <span class="max-year"></span></div>

<label for="min-year">Minimum year:</label>
<input id="min-year" type="range" min="1850" max="2015" step="1" value="1850"/>
<label for="max-year">Maximum year:</label>
<input id="max-year" type="range" min="1850" max="2015" step="1" value="2015"/>
</form>
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
<script src="https://cdn.jsdelivr.net/npm/elm-pep@1.0.6/dist/elm-pep.js"></script>
<script type="module" src="main.js"></script>
</body>
</html>