Here’s a quick recap of the series, so far:
- Creating a basic map for our round-the-world itinerary
- Adding a photo for each placemark
- Adding labels for the approximate timing of the journey
- Overlaying the actual path visited from a tracking device
- Downloading the actual path in multiple queries
A few weeks ago – while we were in Tahiti, but again in New Zealand – I noticed that the “visited” path from the Garmin site wasn’t being integrated properly into the Google Map integrated into our family blog. After a little bit of analysis, I realised that the amount of tracking data being pulled down each time the map was being built was large (upwards of 10MB). I figured it was probably related to the connection speed – the page had trouble getting all that data in time – but of course having a page query 10MB+ plus of data (that will result in the same data for every page loaded in every browser) isn’t the best way to build a site.
Attempting to address the problem, I thought about ways to reduce this payload. The obvious one was to take the KML data from previous months of the trip and compress it into a single KMZ. I looked at ways to do this, and found you can load the respective KMLs – which I downloaded via the URLs contained in the source of Part 5, above – into Google Earth using File –> Open:
From here you can right-click Temporary Places (or whichever place you’ve moved the imported data to) and select Save Place As… to export the data to a KMZ file.The KML files I selected – from July to November – weighed in at a whopping 11.9MB and resulted in a KMZ file of just 380KB: a very respectable compression ratio.
One other thing I decided to fix, while I was at it, was to add some points in for the early part of the trip: I’d only picked up the Garmin inReach Explorer+ in West Hartford, so nothing was tracked prior to that point. I started trying to add these points inside Google Earth, but found that really hard: I ended up handrolling a KML with the points I wanted to add and then included these as a separate overlay. There weren’t many, so adding the overhead of an additional 6KB KML file seemed the simplest way to go.
Here’s the KML file, placed in the same folder as the HTML and called pre-tracking.kml:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
<Folder>
<name>Temporary Places</name>
<open>1</open>
<Folder>
<name>Temporary Places</name>
<open>1</open>
<Document>
<name>Pre-Garmin Tracking</name>
<open>1</open>
<Style id="linestyle_857985">
<LineStyle>
<color>ffff5500</color>
</LineStyle>
</Style>
<Style id="style_8579852">
<IconStyle>
<color>ffff5500</color>
<Icon>
<href>http://maps.google.com/mapfiles/kml/paddle/wht-blank.png</href>
</Icon>
</IconStyle>
<BalloonStyle>
<text><![CDATA[<table><tr><td>Id</td><td> $[Id] </td></tr><tr><td>Time</td><td> $[Time] </td></tr><tr><td>Time UTC</td><td> $[Time UTC] </td></tr><tr><td>Name</td><td> $[Name] </td></tr><tr><td>Map Display Name</td><td> $[Map Display Name] </td></tr><tr><td>Device Type</td><td> $[Device Type] </td></tr><tr><td>IMEI</td><td> $[IMEI] </td></tr><tr><td>Incident Id</td><td> $[Incident Id] </td></tr><tr><td>Latitude</td><td> $[Latitude] </td></tr><tr><td>Longitude</td><td> $[Longitude] </td></tr><tr><td>Elevation</td><td> $[Elevation] </td></tr><tr><td>Velocity</td><td> $[Velocity] </td></tr><tr><td>Course</td><td> $[Course] </td></tr><tr><td>Valid GPS Fix</td><td> $[Valid GPS Fix] </td></tr><tr><td>In Emergency</td><td> $[In Emergency] </td></tr><tr><td>Text</td><td> $[Text] </td></tr><tr><td>Event</td><td> $[Event] </td></tr></table>]]></text>
</BalloonStyle>
</Style>
<Folder>
<name>Kean Walmsley</name>
<open>1</open>
<Placemark>
<name>Geneva Airport</name>
<TimeStamp><when>2017-07-07T12:42:45Z</when></TimeStamp>
<styleUrl>#style_8579852</styleUrl>
<Point>
<altitudeMode>absolute</altitudeMode>
<coordinates>6.109156399971248,46.23700969987675,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Marin-Epagnier</name>
<TimeStamp><when>2017-07-02T12:00:00Z</when></TimeStamp>
<styleUrl>#style_8579852</styleUrl>
<Point>
<altitudeMode>absolute</altitudeMode>
<coordinates>7.001589598912035,47.00918080225755,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Heathrow Terminal 5</name>
<TimeStamp><when>2017-07-02T16:00:00Z</when></TimeStamp>
<styleUrl>#style_8579852</styleUrl>
<Point>
<altitudeMode>absolute</altitudeMode>
<coordinates>-0.4879806004656406,51.47146600045286,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Washington Dulles</name>
<TimeStamp><when>2017-07-02T23:00:00Z</when></TimeStamp>
<styleUrl>#style_8579852</styleUrl>
<Point>
<altitudeMode>absolute</altitudeMode>
<coordinates>-77.45653879988311,38.95311619998505,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>University Inn, Washington DC</name>
<TimeStamp><when>2017-07-03T00:00:00Z</when></TimeStamp>
<styleUrl>#style_8579852</styleUrl>
<Point>
<altitudeMode>absolute</altitudeMode>
<coordinates>-77.05284809999405,38.90030650017117,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Union Station</name>
<TimeStamp><when>2017-07-04T12:00:00Z</when></TimeStamp>
<styleUrl>#style_8579852</styleUrl>
<Point>
<altitudeMode>absolute</altitudeMode>
<coordinates>-77.00250794999864,38.90428664917936,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Penn Station, NYC</name>
<TimeStamp><when>2017-07-04T16:00:00Z</when></TimeStamp>
<styleUrl>#style_8579852</styleUrl>
<Point>
<altitudeMode>absolute</altitudeMode>
<coordinates>-73.99352333750556,40.75056537490029,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Sunnyside</name>
<TimeStamp><when>2017-07-04T20:00:00Z</when></TimeStamp>
<styleUrl>#style_8579852</styleUrl>
<Point>
<altitudeMode>absolute</altitudeMode>
<coordinates>-73.91963239878011,40.74327590022647,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Times Square</name>
<TimeStamp><when>2017-07-04T22:00:00Z</when></TimeStamp>
<styleUrl>#style_8579852</styleUrl>
<Point>
<altitudeMode>absolute</altitudeMode>
<coordinates>-73.98512727848284,40.75889951208065,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Central Park, NYC</name>
<TimeStamp><when>2017-07-05T00:00:00Z</when></TimeStamp>
<styleUrl>#style_8579852</styleUrl>
<Point>
<altitudeMode>absolute</altitudeMode>
<coordinates>-73.96535509973162,40.78286469982217,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Hartford</name>
<TimeStamp><when>2017-07-06T12:00:00Z</when></TimeStamp>
<styleUrl>#style_8579852</styleUrl>
<Point>
<altitudeMode>absolute</altitudeMode>
<coordinates>-72.68740885096805,41.76193520621887,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Kean Walmsley</name>
<description>Kean Walmsley's track log</description>
<styleUrl>#linestyle_857985</styleUrl>
<LineString>
<tessellate>1</tessellate>
<coordinates>7.001589598912035,47.00918080225755,0 -0.4879806004656406,51.47146600045286,0 -77.45653879988311,38.95311619998505,0 -77.05284809999405,38.90030650017117,0 -77.00250794999864,38.90428664917936,0 -73.99352333750556,40.75056537490029,0 -73.91963239878011,40.74327590022647,0 -73.98512727848284,40.75889951208065,0 -73.96535509973162,40.78286469982217,0 -73.98512727848284,40.75889951208065,0 -72.68740885096805,41.76193520621887,0</coordinates>
</LineString>
</Placemark>
</Folder>
</Document>
</Folder>
</Folder>
</kml>
Here’s the updated HTML file:
<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=AIzaSyDtsYI6-syxALgcCkz3hjsAnzK8_4C_OSc&libraries=places&callback=initMap"></script>
<script type='text/javascript'>
var map;
var infowindow;
var service;
var overlayBase = 'https://inreach.garmin.com/feed/Share/mondeEnPoche?';
var locals = [ 'pre-tracking.kml', '2017-07-to-12.kmz' ];
var overlays = [
// 'd1=2017-07-01T00:00Z&d2=2017-08-01T00:00Z',
// 'd1=2017-08-01T00:00Z&d2=2017-09-01T00:00Z',
// 'd1=2017-09-01T00:00Z&d2=2017-10-01T00:00Z',
// 'd1=2017-10-01T00:00Z&d2=2017-11-01T00:00Z',
// 'd1=2017-11-01T00:00Z&d2=2017-12-01T00:00Z',
'd1=2017-12-01T00:00Z&d2=2018-01-05T00: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, function() {
var href = window.location.href;
var dir = href.substring(0, href.lastIndexOf('/')) + '/';
for (var i = 0; i < locals.length; i++) {
var kmlLocalOverlayer = new google.maps.KmlLayer(dir + locals[i], {
suppressInfoWindows: true,
preserveViewport: true,
map: map
});
}
for (var i = 0; i < overlays.length; i++) {
var kmlOverlayer = new google.maps.KmlLayer(overlayBase + overlays[i], {
suppressInfoWindows: true,
preserveViewport: true,
map: map
});
}
});
}
function setMarkers(map, callback) {
// Adds markers to the map with a delay
var delay = 50;
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);
if (callback) {
setTimeout(callback, 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 the embedded map (which you can also find on our trip’s website).
The site seems to work well again, now: once the trip is done I’ll integrate the last month of tracking data into the KMZ, to avoid any further visits to the Garmin service.