Files
openlayers/examples/webgl-points-layer.js
Tomas Burleigh d524d46969 WebGLPointsLayer wrapX support - partially addressing #11131
WebGLPointsLayer renderFrame and renderHitDetection will now draw
multiple worlds if the source and projection support wrapX.

Hit detection needs additional improvement. It stops working after
more than one wrap around the world. If 0 is the middle world, then
the hit detection works for worlds -1, 0, and -1, but not for worlds
> 2 or < -2.

The example has hit detection enabled, demonstrated with a colour
change on hover for the circle styles. When moving the mouse, the hit
detection is unreliable and flickers on/off. This needs improvement.

The webgl-points renderer test has been updated.
2022-04-01 13:35:13 +13:00

240 lines
5.0 KiB
JavaScript

import GeoJSON from '../src/ol/format/GeoJSON.js';
import Map from '../src/ol/Map.js';
import OSM from '../src/ol/source/OSM.js';
import TileLayer from '../src/ol/layer/Tile.js';
import Vector from '../src/ol/source/Vector.js';
import View from '../src/ol/View.js';
import WebGLPointsLayer from '../src/ol/layer/WebGLPoints.js';
const vectorSource = new Vector({
url: 'data/geojson/world-cities.geojson',
format: new GeoJSON(),
wrapX: true,
});
const predefinedStyles = {
'icons': {
symbol: {
symbolType: 'image',
src: 'data/icon.png',
size: [18, 28],
color: 'lightyellow',
rotateWithView: false,
offset: [0, 9],
},
},
'triangles': {
symbol: {
symbolType: 'triangle',
size: 18,
color: [
'interpolate',
['linear'],
['get', 'population'],
20000,
'#5aca5b',
300000,
'#ff6a19',
],
rotateWithView: true,
},
},
'triangles-latitude': {
symbol: {
symbolType: 'triangle',
size: [
'interpolate',
['linear'],
['get', 'population'],
40000,
12,
2000000,
24,
],
color: [
'interpolate',
['linear'],
['get', 'latitude'],
-60,
'#ff14c3',
-20,
'#ff621d',
20,
'#ffed02',
60,
'#00ff67',
],
offset: [0, 0],
opacity: 0.95,
},
},
'circles': {
symbol: {
symbolType: 'circle',
size: [
'interpolate',
['linear'],
['get', 'population'],
40000,
8,
2000000,
28,
],
color: ['match', ['get', 'hover'], 1, '#ff3f3f', '#006688'],
rotateWithView: false,
offset: [0, 0],
opacity: [
'interpolate',
['linear'],
['get', 'population'],
40000,
0.6,
2000000,
0.92,
],
},
},
'circles-zoom': {
symbol: {
symbolType: 'circle',
size: ['interpolate', ['exponential', 2.5], ['zoom'], 2, 1, 14, 32],
color: ['match', ['get', 'hover'], 1, '#ff3f3f', '#006688'],
offset: [0, 0],
opacity: 0.95,
},
},
'rotating-bars': {
symbol: {
symbolType: 'square',
rotation: ['*', ['time'], 0.1],
size: [
'array',
4,
[
'interpolate',
['linear'],
['get', 'population'],
20000,
4,
300000,
28,
],
],
color: [
'interpolate',
['linear'],
['get', 'population'],
20000,
'#ffdc00',
300000,
'#ff5b19',
],
offset: [
'array',
0,
[
'interpolate',
['linear'],
['get', 'population'],
20000,
2,
300000,
14,
],
],
},
},
};
const map = new Map({
layers: [
new TileLayer({
source: new OSM(),
}),
],
target: document.getElementById('map'),
view: new View({
center: [0, 0],
zoom: 2,
}),
});
let literalStyle;
let pointsLayer;
let selected = null;
map.on('pointermove', function (ev) {
if (selected !== null) {
selected.set('hover', 0);
selected = null;
}
map.forEachFeatureAtPixel(ev.pixel, function (feature) {
feature.set('hover', 1);
selected = feature;
return true;
});
});
function refreshLayer(newStyle) {
const previousLayer = pointsLayer;
pointsLayer = new WebGLPointsLayer({
source: vectorSource,
style: newStyle,
});
map.addLayer(pointsLayer);
if (previousLayer) {
map.removeLayer(previousLayer);
previousLayer.dispose();
}
literalStyle = newStyle;
}
const spanValid = document.getElementById('style-valid');
const spanInvalid = document.getElementById('style-invalid');
function setStyleStatus(errorMsg) {
const isError = typeof errorMsg === 'string';
spanValid.style.display = errorMsg === null ? 'initial' : 'none';
spanInvalid.firstElementChild.innerText = isError ? errorMsg : '';
spanInvalid.style.display = isError ? 'initial' : 'none';
}
const editor = document.getElementById('style-editor');
editor.addEventListener('input', function () {
const textStyle = editor.value;
try {
const newLiteralStyle = JSON.parse(textStyle);
if (JSON.stringify(newLiteralStyle) !== JSON.stringify(literalStyle)) {
refreshLayer(newLiteralStyle);
}
setStyleStatus(null);
} catch (e) {
setStyleStatus(e.message);
}
});
const select = document.getElementById('style-select');
select.value = 'circles';
function onSelectChange() {
const style = select.value;
const newLiteralStyle = predefinedStyles[style];
editor.value = JSON.stringify(newLiteralStyle, null, 2);
try {
refreshLayer(newLiteralStyle);
setStyleStatus();
} catch (e) {
setStyleStatus(e.message);
}
}
onSelectChange();
select.addEventListener('change', onSelectChange);
// animate the map
function animate() {
map.render();
window.requestAnimationFrame(animate);
}
animate();