<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="stylesheet" href="https://maps-sdk.trimblemaps.com/v3/trimblemaps-3.11.0.css" />
<script src="https://maps-sdk.trimblemaps.com/v3/trimblemaps-3.11.0.js"></script>
<script src="https://unpkg.com/@turf/turf/turf.min.js"></script>
<style>
body { margin: 0; padding: 0; }
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
.overlay {
position: absolute;
top: 10px;
left: 10px;
}
.overlay button {
font: 600 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
background-color: #3386C0;
color: #fff;
display: inline-block;
margin: 0;
padding: 10px 20px;
border: none;
cursor: pointer;
border-radius: 3px;
}
.overlay button:hover {
background-color: #4EA0DA;
}
</style>
</head>
<body>
<div id="map"></div>
<div class= "overlay">
<button id="replay">Replay</button>
</div>
<script>
TrimbleMaps.APIKey = 'YOUR_API_KEY_HERE';
const map = window.map = new TrimbleMaps.Map({
container: 'map', // container id
style: TrimbleMaps.Common.Style.TRANSPORTATION, //hosted style id
center: [-96, 37.8], // starting position
zoom: 3 // starting zoom
});
// Los Angeles
var origin = [-118.2437, 34.0522];
// NYC
var destination = [-73.99906, 40.72185 ];
var route = {
type: 'FeatureCollection',
features:[
{
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: [origin, destination]
}
}
]
};
var point = {
type: 'FeatureCollection',
features:[
{
type: 'Feature',
properties: {},
geometry: {
type: 'Point',
coordinates: origin
}
}
]
};
// Getting distance in miles between LA (origin) and NYC (destination)
var length = turf.length(route.features[0], {units: 'miles'});
var arc = [];
var steps = 500;
for (var i = 0; i < length; i += length / steps) {
var segment = turf.along(route.features[0], i, {units: 'miles'});
arc.push(segment.geometry.coordinates);
}
// Update route with calculated arc coord.
route.features[0].geometry.coordinates = arc;
// Used to increment the value of the point measurement against the route.
var counter = 0;
map.on('load', function() {
map.addSource('route', {
type: 'geojson',
data: route
});
map.addSource('point', {
type: 'geojson',
data: point
});
map.addLayer({
'id': 'route',
'source': 'route',
'type': 'line',
'paint': {
'line-width': 2,
'line-color': '#005F9E'
}
});
map.addLayer({
'id': 'point',
'source': 'point',
'type': 'symbol',
'layout': {
'icon-image': 'poi_airport',
'icon-rotate': ['get', 'bearing'],
'icon-rotation-alignment': 'map',
'icon-allow-overlap': true,
'icon-ignore-placement': true
}
});
// Update point coordinates based on counter denoting.
function animate() {
point.features[0].geometry.coordinates =
route.features[0].geometry.coordinates[counter];
// Calculate the bearing to ensure the icon is rotated to match the route arc
// The bearing is calculate between the current point and the next point, except
// at the end of the arc use the previous point and the current point.
point.features[0].properties.bearing =
turf.bearing(
turf.point(
route.features[0].geometry.coordinates[
counter >= steps ?
counter - 1 : counter
]
),
turf.point(
route.features[0].geometry.coordinates[
counter >= steps ? counter : counter +1
]
)
) -53;
map.getSource('point').setData(point);
if (counter < steps) {
window.requestAnimationFrame(animate);
}
counter = counter + 1;
}
document.getElementById('replay').addEventListener('click', function() {
point.features[0].geometry.coordinates = origin;
map.getSource('point').setData(point);
counter = 0;
animate(counter);
});
animate(counter);
});
</script>
</body>
</html>