Created
January 13, 2017 23:57
-
-
Save rfriberg/92fb1b7d644b868bf9914b8f473fbbdf to your computer and use it in GitHub Desktop.
Travel by Map - work in progress
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Travel by Map Example (WIP)</title> | |
<link rel="stylesheet" href="https://mapzen.com/js/mapzen.css"/> | |
<link rel="stylesheet" href="https://unpkg.com/[email protected]/src/easy-button.css"> | |
<link rel="stylesheet" href="https://unpkg.com/lrm-mapzen/dist/lrm-mapzen.css" /> | |
<style> | |
.icon { | |
font-size: 20px; | |
} | |
.icon-mode { | |
font-size: 40px; | |
position: absolute; | |
z-index: 1000; | |
top: 48%; | |
left: 49%; | |
visibility: hidden; | |
} | |
.leaflet-routing-container { | |
display: none; | |
} | |
</style> | |
<script src="https://mapzen.com/js/mapzen.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-routing-machine/3.2.4/leaflet-routing-machine.min.js"></script> | |
<script src="https://unpkg.com/[email protected]/src/easy-button.js"></script> | |
<script src="https://unpkg.com/lrm-mapzen/dist/lrm-mapzen.js"></script> | |
<script src="https://npmcdn.com/@turf/[email protected]/turf.js"></script> | |
</head> | |
<body> | |
<div id="map"></div> | |
<div class="icon-mode" id="pedestrian">🏃</div> | |
<div class="icon-mode" id="bird">✈️️</div> | |
<div class="icon-mode" id="auto">🚗</div> | |
<div class="icon-mode" id="bicycle">🚲</div> | |
<script> | |
// TODO: | |
// - Hide line (optionally) | |
// - Add hash | |
// - Base zoom level on total distance (and mode) | |
// - Re-run route based on new costing level for each mode | |
var map = L.Mapzen.map('map', { | |
scene: L.Mapzen.BasemapStyles.RefillMoreLabels, | |
debugTangram: true | |
}); | |
var la = L.latLng(33.8128,-117.9259), | |
chicago = L.latLng(41.8758,-87.6189), | |
vistapoint = L.latLng(37.839682,-122.485284), | |
fairyland = L.latLng(37.809270,-122.259810); | |
var currentRoute = [], | |
currentTimeouts = [], | |
currentRouteBounds, | |
firstAndLast, | |
currentIcon, | |
zoom, speed, | |
tangramLayer; | |
var modeConfig = { | |
auto: { | |
zoom: 18, | |
speed: 120 | |
}, | |
bicycle: { | |
zoom: 18, | |
speed: 40 | |
}, | |
pedestrian: { | |
zoom: 20, | |
speed: 10 | |
}, | |
bird: { | |
zoom: 12, | |
speed: 1200 | |
} | |
}; | |
var demo = { | |
costing: 'auto' // auto, bicycle, pedestrian, multimodal | |
}; | |
var control = L.Routing.control({ | |
routeLine: function (route, options) { | |
// Update currentRoute | |
currentRoute = route; | |
console.log('This is where you can get info about the current route') | |
// Update first and last route points | |
var lastIndex = currentRoute.coordinates.length - 1; | |
firstAndLast = [currentRoute.coordinates[0], currentRoute.coordinates[lastIndex]]; | |
return L.Routing.mapzenLine(route, options); | |
}, | |
lineOptions: { | |
styles: [{ color: '#f66', opacity: 0.8, weight: 5 }] | |
}, | |
waypoints: [ | |
vistapoint, | |
fairyland | |
], | |
geocoder: L.Mapzen.geocoder('mapzen-JA21Wes'), | |
router: L.Routing.mapzen('mapzen-JA21Wes', demo), | |
formatter: new L.Routing.mapzenFormatter(), | |
summaryTemplate:'<div class="start">{name}</div><div class="info {costing}">{distance}, {time}</div>' | |
}).addTo(map); | |
// Not showing control right now | |
control.hide(); | |
L.Routing.errorControl(control).addTo(map); | |
// Update route bounds anytime new route is selected | |
control.on('routeselected', function(r) { | |
var line = L.Routing.line(r.route) | |
currentRouteBounds = line.getBounds(); | |
}); | |
map.on('tangramloaded', function (e) { | |
tangramLayer = e.tangramLayer; | |
addButtons(); | |
}); | |
function addButtons() { | |
L.easyButton('<span class="icon pedestrian" title="Take a stroll">🏃♀️</span>', function(){ | |
console.log("******** TO DO **********") | |
// TODO: rerun route with different costing mode | |
beginAdventure('pedestrian'); | |
}).addTo(map); | |
L.easyButton('<span class="icon bicycle" title="Let\'s ride bikes">🚲</span>', function(){ | |
beginAdventure('bicycle'); | |
}).addTo(map); | |
L.easyButton('<span class="icon auto" title="We be driving">🚗</span>', function(){ | |
beginAdventure('auto'); | |
}).addTo(map); | |
L.easyButton('<span class="icon bird" title="Fly!">✈</span>', function(){ | |
beginAdventure('bird'); | |
}).addTo(map); | |
L.easyButton( '<span class="icon stop" title="Stop the madness!">🙀</span>', function(){ | |
endAdventure(); | |
}).addTo(map); | |
} | |
function beginAdventure(mode) { | |
if (currentTimeouts.length > 0) { | |
endAdventure(); | |
} | |
zoom = modeConfig[mode].zoom; | |
speed = modeConfig[mode].speed; | |
currentIcon = mode; | |
var route = currentRoute; | |
if (mode == 'bird') { | |
// Use current zoom if that's closer | |
// TODO: link zoom level to total distance of route | |
var currentZoom = map.getZoom(); | |
if (currentZoom > zoom) zoom = currentZoom; | |
route = {coordinates: firstAndLast}; | |
} | |
travelByMap(route); | |
} | |
function endAdventure() { | |
// Clear pending timeouts | |
for (var x = 0; x < currentTimeouts.length; x++) { | |
clearTimeout(currentTimeouts[x]); | |
} | |
currentTimeouts = []; | |
// Hide emoji | |
hideEmojis(); | |
// Back to original view | |
if (currentRouteBounds) map.fitBounds(currentRouteBounds); | |
} | |
function travelByMap(route) { | |
var routeCoords = route.coordinates; | |
// Zoom in on first coordinate | |
map.setView(routeCoords[0], zoom); | |
// Display appropriate emoji | |
document.getElementById(currentIcon).style.visibility = "visible"; | |
// Pause 2 seconds before initiating to let people get their bearings | |
var routeCoords = route.coordinates; | |
setTimeout(initiateTravel, 2000, routeCoords); | |
} | |
function initiateTravel(routeCoords) { | |
var loopTime = 0; | |
for (var x = 0; x < routeCoords.length; x++) { | |
var thisCoord = routeCoords[x], | |
nextCoord = routeCoords[x + 1] ? routeCoords[x + 1] : null, | |
units = 'miles'; | |
var distance = nextCoord ? turf.distance(getGeoJSONPoint(thisCoord), getGeoJSONPoint(nextCoord), units) : 0.001; | |
var durationTime = distance * 3600 / speed; // in seconds // distance (mi) * (seconds to hours conv) / speed (mph) | |
// Rounding to avoid extra micro times in loopTime | |
//durationTime = Math.round(durationTime * 100) / 100; | |
if (nextCoord && distance > 0) { | |
var timeout = setTimeout(function(y) { | |
map.panTo(y.coord, {animate: true, duration: y.time, easeLinearity: 1, noMoveStart: true}); | |
}, loopTime, {coord: nextCoord, time: durationTime}); | |
currentTimeouts.push(timeout); | |
} | |
// Set loopTime for next point | |
loopTime += (durationTime * 1000); // in miliseconds | |
} | |
} | |
// Intercept keypress to change basemap | |
document.onkeydown = function(evt) { | |
if (!tangramLayer) return; | |
evt = evt || window.event; | |
var basemap; | |
switch(evt.key) { | |
case 'r': | |
basemap = L.Mapzen.BasemapStyles.RefillMoreLabels; | |
break; | |
case 't': | |
basemap = L.Mapzen.BasemapStyles.TronMoreLabels; | |
break; | |
case 'w': | |
basemap = L.Mapzen.BasemapStyles.WalkaboutMoreLabels; | |
break; | |
case 'b': | |
basemap = L.Mapzen.BasemapStyles.BubbleWrap; | |
break; | |
default: | |
// do nothing | |
return; | |
} | |
// Update basemap | |
tangramLayer.scene.load(basemap); | |
}; | |
/* HELPERS */ | |
function hideEmojis() { | |
var elements = document.getElementsByClassName('icon-mode'); | |
for (var x = 0; x < elements.length; x ++) { | |
elements[x].style.visibility = "hidden"; | |
} | |
} | |
function getGeoJSONPoint(coord) { | |
return { | |
'type': 'Feature', | |
'properties': {}, | |
'geometry': { | |
'type': 'Point', | |
'coordinates': [coord.lat, coord.lng] | |
} | |
}; | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment