Merge pull request #12463 from MoonE/feature-animation-example

Improve animation examples
This commit is contained in:
MoonE
2021-07-04 15:39:31 +02:00
committed by GitHub
4 changed files with 56 additions and 67 deletions
+16 -17
View File
@@ -16,8 +16,15 @@ const tileLayer = new TileLayer({
}), }),
}); });
const source = new VectorSource({
wrapX: false,
});
const vector = new VectorLayer({
source: source,
});
const map = new Map({ const map = new Map({
layers: [tileLayer], layers: [tileLayer, vector],
target: 'map', target: 'map',
view: new View({ view: new View({
center: [0, 0], center: [0, 0],
@@ -26,17 +33,9 @@ const map = new Map({
}), }),
}); });
const source = new VectorSource({
wrapX: false,
});
const vector = new VectorLayer({
source: source,
});
map.addLayer(vector);
function addRandomFeature() { function addRandomFeature() {
const x = Math.random() * 360 - 180; const x = Math.random() * 360 - 180;
const y = Math.random() * 180 - 90; const y = Math.random() * 170 - 85;
const geom = new Point(fromLonLat([x, y])); const geom = new Point(fromLonLat([x, y]));
const feature = new Feature(geom); const feature = new Feature(geom);
source.addFeature(feature); source.addFeature(feature);
@@ -44,14 +43,18 @@ function addRandomFeature() {
const duration = 3000; const duration = 3000;
function flash(feature) { function flash(feature) {
const start = new Date().getTime(); const start = Date.now();
const flashGeom = feature.getGeometry().clone();
const listenerKey = tileLayer.on('postrender', animate); const listenerKey = tileLayer.on('postrender', animate);
function animate(event) { function animate(event) {
const vectorContext = getVectorContext(event);
const frameState = event.frameState; const frameState = event.frameState;
const flashGeom = feature.getGeometry().clone();
const elapsed = frameState.time - start; const elapsed = frameState.time - start;
if (elapsed >= duration) {
unByKey(listenerKey);
return;
}
const vectorContext = getVectorContext(event);
const elapsedRatio = elapsed / duration; const elapsedRatio = elapsed / duration;
// radius will be 5 at start and 30 at end. // radius will be 5 at start and 30 at end.
const radius = easeOut(elapsedRatio) * 25 + 5; const radius = easeOut(elapsedRatio) * 25 + 5;
@@ -69,10 +72,6 @@ function flash(feature) {
vectorContext.setStyle(style); vectorContext.setStyle(style);
vectorContext.drawGeometry(flashGeom); vectorContext.drawGeometry(flashGeom);
if (elapsed > duration) {
unByKey(listenerKey);
return;
}
// tell OpenLayers to continue postrender animation // tell OpenLayers to continue postrender animation
map.render(); map.render();
} }
+38 -48
View File
@@ -57,17 +57,18 @@ fetch('data/polyline/route.json').then(function (response) {
type: 'route', type: 'route',
geometry: route, geometry: route,
}); });
const geoMarker = new Feature({
type: 'geoMarker',
geometry: new Point(route.getCoordinateAt(0)),
});
const startMarker = new Feature({ const startMarker = new Feature({
type: 'icon', type: 'icon',
geometry: new Point(route.getCoordinateAt(0)), geometry: new Point(route.getFirstCoordinate()),
}); });
const endMarker = new Feature({ const endMarker = new Feature({
type: 'icon', type: 'icon',
geometry: new Point(route.getCoordinateAt(1)), geometry: new Point(route.getLastCoordinate()),
});
const position = startMarker.getGeometry().clone();
const geoMarker = new Feature({
type: 'geoMarker',
geometry: position,
}); });
const styles = { const styles = {
@@ -95,76 +96,65 @@ fetch('data/polyline/route.json').then(function (response) {
}), }),
}; };
let animating = false;
const vectorLayer = new VectorLayer({ const vectorLayer = new VectorLayer({
source: new VectorSource({ source: new VectorSource({
features: [routeFeature, geoMarker, startMarker, endMarker], features: [routeFeature, geoMarker, startMarker, endMarker],
}), }),
style: function (feature) { style: function (feature) {
// hide geoMarker if animation is active
if (animating && feature.get('type') === 'geoMarker') {
return null;
}
return styles[feature.get('type')]; return styles[feature.get('type')];
}, },
}); });
map.addLayer(vectorLayer); map.addLayer(vectorLayer);
let speed, startTime;
const speedInput = document.getElementById('speed'); const speedInput = document.getElementById('speed');
const startButton = document.getElementById('start-animation'); const startButton = document.getElementById('start-animation');
let animating = false;
let distance = 0;
let lastTime;
function moveFeature(event) { function moveFeature(event) {
const speed = Number(speedInput.value);
const time = event.frameState.time;
const elapsedTime = time - lastTime;
distance = (distance + (speed * elapsedTime) / 1e6) % 2;
lastTime = time;
const currentCoordinate = route.getCoordinateAt(
distance > 1 ? 2 - distance : distance
);
position.setCoordinates(currentCoordinate);
const vectorContext = getVectorContext(event); const vectorContext = getVectorContext(event);
const frameState = event.frameState; vectorContext.setStyle(styles.geoMarker);
vectorContext.drawGeometry(position);
if (animating) {
const elapsedTime = frameState.time - startTime;
const distance = (speed * elapsedTime) / 1e6;
if (distance >= 1) {
stopAnimation(true);
return;
}
const currentPoint = new Point(route.getCoordinateAt(distance));
const feature = new Feature(currentPoint);
vectorContext.drawFeature(feature, styles.geoMarker);
}
// tell OpenLayers to continue the postrender animation // tell OpenLayers to continue the postrender animation
map.render(); map.render();
} }
function startAnimation() { function startAnimation() {
if (animating) { animating = true;
stopAnimation(false); lastTime = Date.now();
} else { startButton.textContent = 'Stop Animation';
animating = true; vectorLayer.on('postrender', moveFeature);
startTime = new Date().getTime(); // hide geoMarker and trigger map render through change event
speed = speedInput.value; geoMarker.setGeometry(null);
startButton.textContent = 'Cancel Animation';
// hide geoMarker
geoMarker.changed();
// just in case you pan somewhere else
map.getView().setCenter(center);
vectorLayer.on('postrender', moveFeature);
map.render();
}
} }
function stopAnimation(ended) { function stopAnimation() {
animating = false; animating = false;
startButton.textContent = 'Start Animation'; startButton.textContent = 'Start Animation';
// if animation cancelled set the marker at the beginning // Keep marker at current animation position
const coord = route.getCoordinateAt(ended ? 1 : 0); geoMarker.setGeometry(position);
geoMarker.getGeometry().setCoordinates(coord);
// remove listener
vectorLayer.un('postrender', moveFeature); vectorLayer.un('postrender', moveFeature);
} }
startButton.addEventListener('click', startAnimation, false); startButton.addEventListener('click', function () {
if (animating) {
stopAnimation();
} else {
startAnimation();
}
});
}); });
}); });
+1 -1
View File
@@ -120,7 +120,7 @@ function animateFlights(event) {
function addLater(feature, timeout) { function addLater(feature, timeout) {
window.setTimeout(function () { window.setTimeout(function () {
feature.set('start', new Date().getTime()); feature.set('start', Date.now());
flightsSource.addFeature(feature); flightsSource.addFeature(feature);
}, timeout); }, timeout);
} }
+1 -1
View File
@@ -46,7 +46,7 @@ function updateInfo() {
function setTime() { function setTime() {
startDate.setMinutes(startDate.getMinutes() + 15); startDate.setMinutes(startDate.getMinutes() + 15);
if (startDate > new Date()) { if (startDate > Date.now()) {
startDate = threeHoursAgo(); startDate = threeHoursAgo();
} }
layers[1].getSource().updateParams({'TIME': startDate.toISOString()}); layers[1].getSource().updateParams({'TIME': startDate.toISOString()});