import Feature from '../src/ol/Feature.js';
import Map from '../src/ol/Map.js';
import Point from '../src/ol/geom/Point.js';
import Polyline from '../src/ol/format/Polyline.js';
import VectorSource from '../src/ol/source/Vector.js';
import View from '../src/ol/View.js';
import XYZ from '../src/ol/source/XYZ.js';
import {
Circle as CircleStyle,
Fill,
Icon,
Stroke,
Style,
} from '../src/ol/style.js';
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import {getVectorContext} from '../src/ol/render.js';
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
const attributions =
'© MapTiler ' +
'© OpenStreetMap contributors';
const center = [-5639523.95, -3501274.52];
const map = new Map({
target: document.getElementById('map'),
view: new View({
center: center,
zoom: 10,
minZoom: 2,
maxZoom: 19,
}),
layers: [
new TileLayer({
source: new XYZ({
attributions: attributions,
url: 'https://api.maptiler.com/maps/hybrid/{z}/{x}/{y}.jpg?key=' + key,
tileSize: 512,
}),
}),
],
});
// The polyline string is read from a JSON similiar to those returned
// by directions APIs such as Openrouteservice and Mapbox.
fetch('data/polyline/route.json').then(function (response) {
response.json().then(function (result) {
const polyline = result.routes[0].geometry;
const route = new Polyline({
factor: 1e6,
}).readGeometry(polyline, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857',
});
const routeFeature = new Feature({
type: 'route',
geometry: route,
});
const geoMarker = new Feature({
type: 'geoMarker',
geometry: new Point(route.getCoordinateAt(0)),
});
const startMarker = new Feature({
type: 'icon',
geometry: new Point(route.getCoordinateAt(0)),
});
const endMarker = new Feature({
type: 'icon',
geometry: new Point(route.getCoordinateAt(1)),
});
const styles = {
'route': new Style({
stroke: new Stroke({
width: 6,
color: [237, 212, 0, 0.8],
}),
}),
'icon': new Style({
image: new Icon({
anchor: [0.5, 1],
src: 'data/icon.png',
}),
}),
'geoMarker': new Style({
image: new CircleStyle({
radius: 7,
fill: new Fill({color: 'black'}),
stroke: new Stroke({
color: 'white',
width: 2,
}),
}),
}),
};
let animating = false;
const vectorLayer = new VectorLayer({
source: new VectorSource({
features: [routeFeature, geoMarker, startMarker, endMarker],
}),
style: function (feature) {
// hide geoMarker if animation is active
if (animating && feature.get('type') === 'geoMarker') {
return null;
}
return styles[feature.get('type')];
},
});
map.addLayer(vectorLayer);
let speed, startTime;
const speedInput = document.getElementById('speed');
const startButton = document.getElementById('start-animation');
function moveFeature(event) {
const vectorContext = getVectorContext(event);
const frameState = event.frameState;
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
map.render();
}
function startAnimation() {
if (animating) {
stopAnimation(false);
} else {
animating = true;
startTime = new Date().getTime();
speed = speedInput.value;
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) {
animating = false;
startButton.textContent = 'Start Animation';
// if animation cancelled set the marker at the beginning
const coord = route.getCoordinateAt(ended ? 1 : 0);
geoMarker.getGeometry().setCoordinates(coord);
// remove listener
vectorLayer.un('postrender', moveFeature);
}
startButton.addEventListener('click', startAnimation, false);
});
});