Animate Point on Route
Animate a point along a route using Turf.js<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="stylesheet" href="https://maps-sdk.trimblemaps.com/v3/trimblemaps-3.21.0.css" /> <script src="https://maps-sdk.trimblemaps.com/v3/trimblemaps-3.21.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>
Animate Point on Route
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="stylesheet" href="https://maps-sdk.trimblemaps.com/v3/trimblemaps-3.21.0.css" /> <script src="https://maps-sdk.trimblemaps.com/v3/trimblemaps-3.21.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>