In the first parts of this series we saw a basic, embedded map and then added information windows and labels. In this post we’re going to overlay data being recorded by a tracking device to show our progress in real-time.
This was made pretty easy thanks to Garmin’s MapShare service: our Iridium-connected inReach Explorer+ device publishes tracking information automagically to our MapShare page, which has a KML feed that can be embedded as an overlay on Google Maps. The additional code, below, is trivial. It’s possible to zoom into the location of the latest data on map load, but I’ve chosen to leave it as is: the information is there for people to zoom into, of they choose, but we’ve chosen the option to “preserve the viewport”, otherwise.
Here’s the updated code:
<html>
<head>
<style>
html,
body {
padding: 0;
margin: 0;
}
#map {
height: 100%;
width: 100%;
overflow: hidden;
float: left;
border: thin solid #333;
}
h3 {
margin: 0 0 5px 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
p {
margin: 0 0 10px 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
</head>
<body>
<div id="map"></div>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=[ENTER_YOUR_KEY_HERE]&libraries=places&callback=initMap"></script>
<script type='text/javascript'>
var map;
var infowindow;
var service;
var overlay = 'https://inreach.garmin.com/feed/Share/mondeEnPoche?d1=2017-07-01T00:00Z&d2=2018-01-10T00:00Z';
// Data for the markers consisting of a name, a LatLng and a zIndex for the
// order in which these markers should display on top of each other.
var stops = [
['Marin-Epagnier', 'ChIJt4RhN0UJjkcR9dxtPHTvIRY', 47.0091808, 7.0015896, 1, 'Start & End'],
['Washington', 'ChIJW-T2Wt7Gt4kRKl2I1CJFUsI', 38.9071923, -77.0368707, 2],
['New York', 'ChIJOwg_06VPwokRYv534QaPC8g', 40.7127837, -74.0059413, 3],
['West Hartford', 'ChIJ_RQEifWs54kRfDtRDlPX-Wc', 41.7620842, -72.7420151, 4],
['Boston', 'ChIJGzE9DS1l44kRoOhiASS_fHg', 42.3600825, -71.0588801, 5, 'July'],
['Toronto', 'ChIJpTvG15DL1IkRd8S0KlBVNTI', 43.653226, -79.3831843, 6],
['Bozeman', 'ChIJE4i6T0xERVMRqmA792TQ9WM', 45.6769979, -111.0429339, 7],
['Yellowstone National Park', 'ChIJVVVVVVXlUVMRu-GPNDD5qKw', 44.427963, -110.588455, 8],
['Grand Teton National Park', 'ChIJqRtdyZ5RUlMRN6ORzI64oKU', 43.7904282, -110.6817627, 9],
['Salt Lake City', 'ChIJ7THRiJQ9UocRyjFNSKC3U1s', 40.7607793, -111.8910474, 10],
['Bryce Canyon', 'ChIJbUw47h9pNYcRYv1Jemw3nHU', 37.6283161, -112.1676947, 11],
['Zion National Park', 'ChIJ2fhEiNDqyoAR9VY2qhU6Lnw', 37.2982022, -113.0263005, 12],
['Las Vegas', 'ChIJ0X31pIK3voARo3mz1ebVzDo', 36.1699412, -115.1398296, 13],
['Death Valley', 'ChIJsf-PHqI5x4ARJd0j14NziRw', 36.5322649, -116.9325408, 14],
['Sequoia National Park', 'ChIJeWUZLX37v4ARZPQen_nfCkQ', 36.4863668, -118.5657516, 15],
['Big Sur', 'ChIJVVikTfuPjYARYuO38cfXpRY', 36.2704212, -121.807976, 16],
['Monterey', 'ChIJkfu1cFLkjYARXj1K2AlJSO4', 36.6002378, -121.8946761, 17],
['San Francisco', 'ChIJIQBpAG2ahYAR_6128GcTUEo', 37.7749295, -122.4194155, 18, 'August'],
['Lima', 'ChIJ3-EpLOzDBZERRBEzku1Ooak', -12.0463667, -77.0427891, 19],
['Machu Picchu', 'ChIJVVVViV-abZERJxqgpA43EDo', -13.1631412, -72.5449629, 20],
['Cusco', 'ChIJMYRZJtjVbZERXTEYI8yWqSo', -13.53195, -71.9674626, 21],
['São Paulo', 'ChIJ0WGkg4FEzpQRrlsz_whLqZs', -23.5505199, -46.6333094, 22],
['Rio de Janeiro', 'ChIJW6AIkVXemwARTtIvZ2xC3FA', -22.9068467, -43.1728965, 23, 'September'],
['Iguazu Falls', 'ChIJbRuqowzq9pQRfphenBd1e5E', -25.695259, -54.4388549, 24],
['Córdoba', 'ChIJaVuPR1-YMpQRkrBmU5pPorA', -31.4200833, -64.1887761, 25],
['Parque Provincial Ischigualasto', 'ChIJwynmBT3sgpYR0J11F_1O5cw', -30.167266,-67.9860327, 26],
['Parque Nacional Talampaya', 'ChIJUUxbf6rPgpYRaEkBxpGDANQ', -29.8906226, -67.853468, 27],
['Catamarca', 'ChIJzZ8PHb8oJJQRGoYJFkvdHn4', -28.469581, -65.7795441, 28],
['San Miguel de Tucumán', 'ChIJA2nF1pI3IpQRJ2XFtZJbjfg', -26.8082848, -65.2175903, 29],
['Salta', 'ChIJ-bdRUaPDG5QRBvKH1SyZzaU', -24.7821269, -65.4231976, 30],
['Salar de Uyuni', 'ChIJh9rdHuC6_5MRkFuFng0T5RI', -20.1595348, -67.4054025, 31],
['San Pedro de Atacama', 'ChIJP78qqXpMqJYR0Zf5rExh9Ho', -22.9087073, -68.1997156, 32],
['Pan de Azúcar National Park', 'ChIJM6BM4cewvJYRbC7GcVat_6U', -26.177565, -70.5495396, 33],
['Raúl Marine Balmaceda', 'ChIJ4V-JqObIkZYRiGptmZGVUn8', -29.9695076, -71.3416309, 34],
['Santiago', 'ChIJuzrymgbQYpYRl0jtCfRZnYc', -33.4378305, -70.6504492, 35],
['Easter Island', 'ChIJK67UqBfwR5kRti0qwO2z5bs', -27.112723, -109.3496865, 36],
['Tahiti', 'ChIJTddtfNB1GHQREVfDCXp6wJs', -17.6509195, -149.4260421, 37],
['Auckland', 'ChIJ--acWvtHDW0RF5miQ2HvAAU', -36.8484597, 174.7633315, 38],
['Rotorua', 'ChIJK7L2gj2Ybm0RMZmjQ2HvAAU', -38.1368478, 176.2497461, 39, 'October'],
['Wellington', 'ChIJy3TpSfyxOG0RcLQTomPvAAo', -41.2864603, 174.776236, 40],
['Paparoa National Park', 'ChIJbZoxICBxJW0RIPF5hIbvAAU', -42.1632433, 171.366731, 41],
['Queenstown', 'ChIJX96o1_Ed1akRAKZ5hIbvAAU', -45.0311622, 168.6626435, 42],
['Sydney', 'ChIJP5iLHkCuEmsRwMwyFmh9AQU', -33.8688197, 151.2092955, 43],
['Brisbane', 'ChIJM9KTrJpXkWsRQK_e81qjAgQ', -27.4697707, 153.0251235, 44],
['Cairns', 'ChIJEySiW1VieGkRYHggf_HuAAQ', -16.9185514, 145.7780548, 45],
['Kuala Lumpur', 'ChIJ5-rvAcdJzDERfSgcL1uO2fQ', 3.139003, 101.686855, 46],
['Singapore', 'ChIJdZOLiiMR2jERxPWrUs9peIg', 1.352083, 103.819836, 47],
['Coimbatore', 'ChIJtRyXL69ZqDsRgtI-GB7IwS8', 11.0168445, 76.9558321, 48],
['Kodaikanal', 'ChIJhwMKf2NmBzsRPMFYNzfp-p8', 10.2381136, 77.4891822, 49],
['Bangalore', 'ChIJbU60yXAWrjsR4E9-UejD3_g', 12.9715987, 77.5945627, 50, 'November'],
['Durban', 'ChIJt2G8AQCq9x4RgW6qxEZVp8w', -29.8586804, 31.0218404, 51],
['Lesotho', 'ChIJ64xf1idIjB4Rsx7ReLhXLSM', -29.609988, 28.233608, 52, 'December'],
['Addo Elephant National Park', 'ChIJY2nuzYRPex4RCsT--8cm454', -33.4833333, 25.75, 53],
['Tsitsikamma', 'ChIJaTwmTQ5ueR4R5_kNGLX6RBs', -32.2178721, 26.5772048, 54],
['Knysna', 'ChIJ2QwBlkDqeB4Rzc5QdeG5Kr4', -34.0350856, 23.0464693, 55],
['Oudtshoorn', 'ChIJtRO16obB1R0RYesIjnRHQ40', -33.6007225, 22.2026347, 56],
['Franschhoek', 'ChIJz7IFaAe9zR0R-bJW01SGtDw', -33.8974833, 19.1523292, 57],
['Stellenbosch', 'ChIJpeKIUfeyzR0R4mvj3gCqCXA', -33.9321045, 18.860152, 58],
['Cape Town', 'ChIJ1-4miA9QzB0Rh6ooKPzhf2g', -33.9248685, 18.4240553, 59]
];
var labels = [
['Start & End', 47.0091808, 7.0015896, 1],
['July', 42.409143, -102.280372, 2],
['August', 5.247246, -73.979869, 3],
['September', -36.753594, -65.018287, 4],
['October', -33.622306, 160.985311, 5],
['November', 16.921484, 91.724302, 6],
['December', -16.011953, 23.167125, 7]
];
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: new google.maps.LatLng(15, -30),
zoom: 2,
mapTypeId: 'satellite'
});
infowindow = new google.maps.InfoWindow();
service = new google.maps.places.PlacesService(map);
loadJS('./maplabel-compiled.js', onInit, document.body);
}
function loadJS(url, implementationCode, location){
var scriptTag = document.createElement('script');
scriptTag.src = url;
scriptTag.onload = implementationCode;
scriptTag.onreadystatechange = implementationCode;
location.appendChild(scriptTag);
};
function onInit(){
setMarkers(map);
var kmlOverlayer = new google.maps.KmlLayer(overlay, {
suppressInfoWindows: true,
preserveViewport: true,
map: map
});
}
function setMarkers(map) {
// Adds markers to the map with a delay
var delay = 100;
for (var i = 0; i <= stops.length; i++) {
var timeout = i * delay;
// If this is the last segment, just add the line
if (i === stops.length) {
addConnectingLineWithTimeout(stops[i - 1], stops[0], timeout + delay);
} else if (i >= 0) {
// Otherwise add a marker after a delay, followed by the
// connecting line to the previous marker, if there is one
addMarkerWithTimeout(stops[i], timeout);
if (i > 0) {
addConnectingLineWithTimeout(stops[i], stops[i - 1], timeout + delay);
}
}
}
}
function addMarkerWithTimeout(stop, timeout) {
setTimeout(function() {
var marker = new google.maps.Marker({
map: map,
title: stop[0],
placeId: stop[1],
position: {
lat: stop[2],
lng: stop[3]
},
label: stop[4].toString(),
zIndex: stop[4]
//animation: google.maps.Animation.DROP, // Cool but too much
});
// If we have a label listed, find out which and add it to the map
if (stop.length > 5) {
var idx = labels.findIndex(function(val) {
return val[0] === stop[5];
});
if (idx >= 0) {
var label = labels[idx];
addLabelWithTimeout(label[1], label[2], label[0], 0);
}
}
// Register the callback for when the marker is clicked
google.maps.event.addListener(marker, 'click', function() {
onItemClick(event, marker);
});
}, timeout);
}
function addLabelWithTimeout(lat, long, text, timeout) {
setTimeout(function() {
var pos = new google.maps.LatLng(lat, long);
var mapLabel = new MapLabel({
text: text,
position: pos,
map: map,
fontSize: 14
});
mapLabel.set('position', new google.maps.LatLng(lat, long));
}, timeout);
}
function addConnectingLineWithTimeout(stop1, stop2, timeout) {
setTimeout(function() {
var flightPath = new google.maps.Polyline({
path: [{
lat: stop1[2],
lng: stop1[3]
}, {
lat: stop2[2],
lng: stop2[3]
}],
geodesic: true,
strokeColor: '#D34038',
strokeOpacity: 1.0,
strokeWeight: 4
});
flightPath.setMap(map);
}, timeout);
}
// Info window trigger function
function onItemClick(event, pin) {
service.getDetails({
placeId: pin.placeId
}, function(place, status) {
var cont =
'<div><h3>' + place.name + '</h3><p>' + place.formatted_address + '</p>' +
(place.photos && place.photos.length > 0 ?
('<img src="' +
place.photos[0].getUrl({
'maxWidth': 300,
'maxHeight': 200
}) + '" />') : '') +
'</div>'
infowindow.setContent(cont);
infowindow.open(map, pin);
});
}
</script>
</body>
</html>
Here’s how it looks when we zoom in on an area with tracking data (Toronto, which is where I am right now):
Here’s the embedded map for you to try yourself.
You can always find the embedded map on our website, and be sure to subscribe to our Instagram feed if you want to keep up-to-date with what we’re up to (this is where we’re posting most regularly, it turns out).
Tomorrow we’re leaving Toronto (and Canada) to head across to Montana and Yellowstone Park. From there we’ll be travelling through the US, camping in various National Parks, which should be quite the adventure. We’ll see!