The demonstrated features have been recreated using a literal style (filtering, pulse animation).
132 lines
3.3 KiB
JavaScript
132 lines
3.3 KiB
JavaScript
import Map from '../src/ol/Map.js';
|
|
import View from '../src/ol/View.js';
|
|
import TileLayer from '../src/ol/layer/Tile.js';
|
|
import Feature from '../src/ol/Feature.js';
|
|
import Point from '../src/ol/geom/Point.js';
|
|
import {Vector} from '../src/ol/source.js';
|
|
import {fromLonLat} from '../src/ol/proj.js';
|
|
import Stamen from '../src/ol/source/Stamen.js';
|
|
import WebGLPointsLayer from '../src/ol/layer/WebGLPoints.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 =
|
|
['pow',
|
|
['/',
|
|
['mod',
|
|
['+',
|
|
['time'],
|
|
['stretch', ['get', 'year'], 1850, 2020, 0, period]
|
|
],
|
|
period
|
|
],
|
|
period
|
|
],
|
|
0.5
|
|
];
|
|
|
|
const style = {
|
|
variables: {
|
|
minYear: 1850,
|
|
maxYear: 2015
|
|
},
|
|
filter: ['between', ['get', 'year'], ['var', 'minYear'], ['var', 'maxYear']],
|
|
symbol: {
|
|
symbolType: 'circle',
|
|
size: ['*',
|
|
['stretch', ['get', 'mass'], 0, 200000, 8, 26],
|
|
['-', 1.5, ['*', animRatio, 0.5]]
|
|
],
|
|
color: ['interpolate',
|
|
animRatio,
|
|
newColor, oldColor],
|
|
opacity: ['-', 1.0, ['*', animRatio, 0.75]]
|
|
}
|
|
};
|
|
|
|
// handle input values & events
|
|
const minYearInput = document.getElementById('min-year');
|
|
const maxYearInput = document.getElementById('max-year');
|
|
|
|
function updateMinYear() {
|
|
style.variables.minYear = parseInt(minYearInput.value);
|
|
updateStatusText();
|
|
}
|
|
function updateMaxYear() {
|
|
style.variables.maxYear = parseInt(maxYearInput.value);
|
|
updateStatusText();
|
|
}
|
|
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', updateMinYear);
|
|
minYearInput.addEventListener('change', updateMinYear);
|
|
maxYearInput.addEventListener('input', updateMaxYear);
|
|
maxYearInput.addEventListener('change', updateMaxYear);
|
|
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
|
|
})
|
|
],
|
|
target: document.getElementById('map'),
|
|
view: new View({
|
|
center: [0, 0],
|
|
zoom: 2
|
|
})
|
|
});
|
|
|
|
// animate the map
|
|
function animate() {
|
|
map.render();
|
|
window.requestAnimationFrame(animate);
|
|
}
|
|
animate();
|