beautified comments, moved language settings to config, moved timeout settings to config, corrected bug with route link and via nodes, removed old files, corrected spelling error for roundabout
456 lines
16 KiB
JavaScript
456 lines
16 KiB
JavaScript
/*
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU AFFERO General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
or see http://www.gnu.org/licenses/agpl.txt.
|
|
*/
|
|
|
|
// OSRM routing routines
|
|
// [management of routing/direction requests and processing of responses]
|
|
// [TODO: major refactoring scheduled]
|
|
|
|
// some variables
|
|
var my_route = undefined;
|
|
var my_markers = undefined;
|
|
|
|
OSRM.NO_DESCRIPTION = 0;
|
|
OSRM.FULL_DESCRIPTION = 1;
|
|
OSRM.dragging = false;
|
|
OSRM.pending = false;
|
|
OSRM.pendingTimer = undefined;
|
|
|
|
|
|
// init routing data structures
|
|
function initRouting() {
|
|
my_route = new OSRM.Route();
|
|
my_markers = new OSRM.Markers();
|
|
}
|
|
|
|
|
|
// -- JSONP processing --
|
|
|
|
// process JSONP response of routing server
|
|
function timeoutRouteSimple() {
|
|
showNoRouteGeometry();
|
|
showNoRouteDescription();
|
|
document.getElementById('information-box').innerHTML = "<br><p style='font-size:14px;font-weight:bold;text-align:center;'>"+OSRM.loc("TIMED_OUT")+".<p>";
|
|
}
|
|
function timeoutRoute() {
|
|
showNoRouteGeometry();
|
|
my_route.hideUnnamedRoute();
|
|
showNoRouteDescription();
|
|
document.getElementById('information-box').innerHTML = "<br><p style='font-size:14px;font-weight:bold;text-align:center;'>"+OSRM.loc("TIMED_OUT")+".<p>";
|
|
}
|
|
function showRouteSimple(response) {
|
|
if(!response)
|
|
return;
|
|
|
|
if (OSRM.JSONP.fences.route) // prevent simple routing when real routing is done!
|
|
return;
|
|
|
|
if( response.status == 207) {
|
|
showNoRouteGeometry();
|
|
showNoRouteDescription();
|
|
document.getElementById('information-box').innerHTML = "<br><p style='font-size:14px;font-weight:bold;text-align:center;'>"+OSRM.loc("YOUR_ROUTE_IS_BEING_COMPUTED")+".<p>";
|
|
} else {
|
|
showRouteGeometry(response);
|
|
showRouteDescriptionSimple(response);
|
|
}
|
|
updateHints(response);
|
|
|
|
// // TODO: hack to process final drag event, if it was fenced, but we are still dragging (alternative approach)
|
|
// if(OSRM.pending) {
|
|
// clearTimeout(OSRM.pendingTimer);
|
|
// OSRM.pendingTimer = setTimeout(timeoutDrag,100);
|
|
// }
|
|
}
|
|
function showRoute(response) {
|
|
if(!response)
|
|
return;
|
|
|
|
if(response.status == 207) {
|
|
showNoRouteGeometry();
|
|
my_route.hideUnnamedRoute();
|
|
showNoRouteDescription();
|
|
document.getElementById('information-box').innerHTML = "<br><p style='font-size:14px;font-weight:bold;text-align:center;'>"+OSRM.loc("NO_ROUTE_FOUND")+".<p>";
|
|
} else {
|
|
showRouteGeometry(response);
|
|
showRouteNonames(response);
|
|
showRouteDescription(response);
|
|
snapRoute();
|
|
}
|
|
updateHints(response);
|
|
}
|
|
|
|
|
|
// show route geometry
|
|
function showNoRouteGeometry() {
|
|
var positions = [];
|
|
for(var i=0; i<my_markers.route.length;i++)
|
|
positions.push( my_markers.route[i].getPosition() );
|
|
|
|
my_route.showRoute(positions, OSRM.Route.NOROUTE);
|
|
}
|
|
function showRouteGeometry(response) {
|
|
via_points = response.via_points.slice(0);
|
|
|
|
var geometry = decodeRouteGeometry(response.route_geometry, 5);
|
|
|
|
var points = [];
|
|
for( var i=0; i < geometry.length; i++) {
|
|
points.push( new L.LatLng(geometry[i][0], geometry[i][1]) );
|
|
}
|
|
my_route.showRoute(points, OSRM.Route.ROUTE);
|
|
}
|
|
|
|
|
|
// route description display (and helper functions)
|
|
function onClickRouteDescription(geometry_index) {
|
|
var positions = my_route.getPositions();
|
|
|
|
my_markers.highlight.setPosition( positions[geometry_index] );
|
|
my_markers.highlight.show();
|
|
my_markers.highlight.centerView();
|
|
}
|
|
function onClickCreateShortcut(src){
|
|
OSRM.JSONP.call(OSRM.DEFAULTS.HOST_SHORTENER_URL+src+'&jsonp=showRouteLink', showRouteLink, showRouteLink_TimeOut, 2000, 'shortener');
|
|
}
|
|
function showRouteLink(response){
|
|
document.getElementById('route-link').innerHTML = '[<a id="gpx-link" href="' +response.ShortURL+ '">'+OSRM.loc("LINK_TO_ROUTE")+'</a>]';
|
|
}
|
|
function showRouteLink_TimeOut(){
|
|
document.getElementById('route-link').innerHTML = '['+OSRM.loc("LINK_TO_ROUTE_TIMEOUT")+']';
|
|
}
|
|
function showRouteDescription(response) {
|
|
// compute query string
|
|
var query_string = '?z='+ map.getZoom();
|
|
for(var i=0; i<my_markers.route.length; i++)
|
|
query_string += '&loc=' + my_markers.route[i].getLat() + ',' + my_markers.route[i].getLng();
|
|
|
|
// create link to the route
|
|
var route_link ='<span class="route-summary" id="route-link">[<a id="gpx-link" onclick="onClickCreateShortcut(\'' + OSRM.DEFAULTS.WEBSITE_URL + query_string + '\')">'+OSRM.loc("GET_LINK")+'</a>]</span>';
|
|
//var route_link ='<span class="route-summary" id="route-link">[<a id="gpx-link" href="#" onclick="onClickCreateShortcut(\'' + document.URL + query_string + '\')">'+OSRM.loc("GET_LINK")+'</a>]</span>';
|
|
|
|
// create GPX link
|
|
var gpx_link = '<span class="route-summary">[<a id="gpx-link" onClick="javascript: document.location.href=\'' + OSRM.DEFAULTS.HOST_ROUTING_URL + query_string + '&output=gpx\';">'+OSRM.loc("GPX_FILE")+'</a>]</span>';
|
|
|
|
// create route description
|
|
var route_desc = "";
|
|
route_desc += '<table class="results-table">';
|
|
|
|
for(var i=0; i < response.route_instructions.length; i++){
|
|
//odd or even ?
|
|
var rowstyle='results-odd';
|
|
if(i%2==0) { rowstyle='results-even'; }
|
|
|
|
route_desc += '<tr class="'+rowstyle+'">';
|
|
|
|
route_desc += '<td class="result-directions">';
|
|
route_desc += '<img width="18px" src="images/'+getDirectionIcon(response.route_instructions[i][0])+'"/>';
|
|
route_desc += "</td>";
|
|
|
|
route_desc += '<td class="result-items">';
|
|
route_desc += '<span class="result-item" onclick="onClickRouteDescription('+response.route_instructions[i][3]+')">'
|
|
+ response.route_instructions[i][0] + ' on ';
|
|
if( response.route_instructions[i][2] > 0 )
|
|
route_desc += response.route_instructions[i][1] + ' for '
|
|
+ getDistanceWithUnit(response.route_instructions[i][2])
|
|
+ '</span>';
|
|
route_desc += "</td>";
|
|
|
|
route_desc += "</tr>";
|
|
}
|
|
|
|
route_desc += '</table>';
|
|
headline = "";
|
|
headline += OSRM.loc("ROUTE_DESCRIPTION")+":<br>";
|
|
headline += '<div style="float:left;width:70%">';
|
|
headline += "<span class='route-summary'>"
|
|
+ OSRM.loc("DISTANCE")+": " + getDistanceWithUnit(response.route_summary.total_distance)
|
|
+ " - "
|
|
+ OSRM.loc("DURATION")+": " + secondsToTime(response.route_summary.total_time)
|
|
+ "</span>";
|
|
headline += '</div>';
|
|
headline += '<div style="float:left;text-align:right;width:30%;">'+route_link+'<br>'+gpx_link+'</div>';
|
|
|
|
var output = "";
|
|
output += route_desc;
|
|
|
|
document.getElementById('information-box-headline').innerHTML = headline;
|
|
document.getElementById('information-box').innerHTML = output;
|
|
}
|
|
function showRouteDescriptionSimple(response) {
|
|
headline = OSRM.loc("ROUTE_DESCRIPTION")+":<br>";
|
|
headline += "<span class='route-summary'>"
|
|
+ OSRM.loc("DISTANCE")+": " + getDistanceWithUnit(response.route_summary.total_distance)
|
|
+ " - "
|
|
+ OSRM.loc("DURATION")+": " + secondsToTime(response.route_summary.total_time)
|
|
+ "</span>";
|
|
headline += '<br><br>';
|
|
|
|
document.getElementById('information-box-headline').innerHTML = headline;
|
|
document.getElementById('information-box').innerHTML = "<br><p style='font-size:14px;font-weight:bold;text-align:center;'>"+OSRM.loc("YOUR_ROUTE_IS_BEING_COMPUTED")+".<p>";
|
|
}
|
|
function showNoRouteDescription() {
|
|
headline = OSRM.loc("ROUTE_DESCRIPTION")+":<br>";
|
|
headline += "<span class='route-summary'>"
|
|
+ OSRM.loc("DISTANCE")+": N/A"
|
|
+ " - "
|
|
+ OSRM.loc("DURATION")+": N/A"
|
|
+ "</span>";
|
|
headline += '<br><br>';
|
|
|
|
document.getElementById('information-box-headline').innerHTML = headline;
|
|
document.getElementById('information-box').innerHTML = "<br><p style='font-size:14px;font-weight:bold;text-align:center;'>"+OSRM.loc("YOUR_ROUTE_IS_BEING_COMPUTED")+".<p>";
|
|
}
|
|
|
|
|
|
// unnamed streets display
|
|
function showRouteNonames(response) {
|
|
// do not display unnamed streets?
|
|
if( document.getElementById('option-highlight-nonames').checked == false) {
|
|
my_route.hideUnnamedRoute();
|
|
return;
|
|
}
|
|
|
|
// mark geometry positions where unnamed/named streets switch
|
|
var named = [];
|
|
for (var i = 0; i < response.route_instructions.length; i++) {
|
|
if( response.route_instructions[i][1] == '' )
|
|
named[ response.route_instructions[i][3] ] = false; // no street name
|
|
else
|
|
named[ response.route_instructions[i][3] ] = true; // yes street name
|
|
}
|
|
|
|
// aggregate geometry for unnamed streets
|
|
var geometry = decodeRouteGeometry(response.route_geometry, 5);
|
|
var is_named = true;
|
|
var current_positions = [];
|
|
var all_positions = [];
|
|
for( var i=0; i < geometry.length; i++) {
|
|
current_positions.push( new L.LatLng(geometry[i][0], geometry[i][1]) );
|
|
|
|
// still named/unnamed?
|
|
if( (named[i] == is_named || named[i] == undefined) && i != geometry.length-1 )
|
|
continue;
|
|
|
|
// switch between named/unnamed!
|
|
if(is_named == false)
|
|
all_positions.push( current_positions );
|
|
current_positions = [];
|
|
current_positions.push( new L.LatLng(geometry[i][0], geometry[i][1]) );
|
|
is_named = named[i];
|
|
}
|
|
|
|
// display unnamed streets
|
|
my_route.showUnnamedRoute(all_positions);
|
|
}
|
|
|
|
|
|
//-- main function --
|
|
|
|
// generate server calls to query routes
|
|
function getRoute(do_description) {
|
|
|
|
// if source or target are not set -> hide route
|
|
if( my_markers.route.length < 2 ) {
|
|
my_route.hideRoute();
|
|
return;
|
|
}
|
|
|
|
// prepare JSONP call
|
|
var type = undefined;
|
|
var callback = undefined;
|
|
var timeout = undefined;
|
|
|
|
var source = OSRM.DEFAULTS.HOST_ROUTING_URL;
|
|
source += '?z=' + map.getZoom() + '&output=json' + '&geomformat=cmp';
|
|
if(my_markers.checksum)
|
|
source += '&checksum=' + my_markers.checksum;
|
|
for(var i=0; i<my_markers.route.length; i++) {
|
|
source += '&loc=' + my_markers.route[i].getLat() + ',' + my_markers.route[i].getLng();
|
|
if( my_markers.route[i].hint)
|
|
source += '&hint=' + my_markers.route[i].hint;
|
|
}
|
|
|
|
// decide whether it is a dragging call or a normal one
|
|
if (do_description) {
|
|
callback = showRoute;
|
|
timeout = timeoutRoute;
|
|
source +='&instructions=true';
|
|
type = 'route';
|
|
} else {
|
|
callback = showRouteSimple;
|
|
timeout = timeoutRouteSimple;
|
|
source +='&instructions=false';
|
|
type = 'dragging';
|
|
}
|
|
|
|
// do call
|
|
var called = OSRM.JSONP.call(source, callback, timeout, OSRM.DEFAULTS.JSONP_TIMEOUT, type);
|
|
|
|
// TODO: hack to process final drag event, if it was fenced, but we are still dragging
|
|
if(called == false && !do_description) {
|
|
clearTimeout(OSRM.pendingTimer);
|
|
OSRM.pendingTimer = setTimeout(timeoutDrag,OSRM.DEFAULTS.JSONP_TIMEOUT);
|
|
}
|
|
else {
|
|
clearTimeout(OSRM.pendingTimer);
|
|
}
|
|
// // TODO: hack to process final drag event, if it was fenced, but we are still dragging (alternative approach)
|
|
// if(called == false && !do_description) {
|
|
// OSRM.pending = true;
|
|
// } else {
|
|
// clearTimeout(OSRM.pendingTimer);
|
|
// OSRM.pending = false;
|
|
// }
|
|
}
|
|
function timeoutDrag() {
|
|
my_markers.route[OSRM.dragid].hint = undefined;
|
|
getRoute(OSRM.NO_DESCRIPTION);
|
|
}
|
|
|
|
|
|
//-- helper functions --
|
|
|
|
//decode compressed route geometry
|
|
function decodeRouteGeometry(encoded, precision) {
|
|
precision = Math.pow(10, -precision);
|
|
var len = encoded.length, index=0, lat=0, lng = 0, array = [];
|
|
while (index < len) {
|
|
var b, shift = 0, result = 0;
|
|
do {
|
|
b = encoded.charCodeAt(index++) - 63;
|
|
result |= (b & 0x1f) << shift;
|
|
shift += 5;
|
|
} while (b >= 0x20);
|
|
var dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
|
|
lat += dlat;
|
|
shift = 0;
|
|
result = 0;
|
|
do {
|
|
b = encoded.charCodeAt(index++) - 63;
|
|
result |= (b & 0x1f) << shift;
|
|
shift += 5;
|
|
} while (b >= 0x20);
|
|
var dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
|
|
lng += dlng;
|
|
array.push([lat * precision, lng * precision]);
|
|
}
|
|
return array;
|
|
}
|
|
|
|
// update hints of all markers
|
|
function updateHints(response) {
|
|
var hint_locations = response.hint_data.locations;
|
|
my_markers.checksum = response.hint_data.checksum;
|
|
for(var i=0; i<hint_locations.length; i++)
|
|
my_markers.route[i].hint = hint_locations[i];
|
|
}
|
|
|
|
// snap all markers to the received route
|
|
function snapRoute() {
|
|
var positions = my_route.getPositions();
|
|
|
|
my_markers.route[0].setPosition( positions[0] );
|
|
my_markers.route[my_markers.route.length-1].setPosition( positions[positions.length-1] );
|
|
for(var i=0; i<via_points.length; i++)
|
|
my_markers.route[i+1].setPosition( new L.LatLng(via_points[i][0], via_points[i][1]) );
|
|
|
|
updateLocation( "source" );
|
|
updateLocation( "target" );
|
|
}
|
|
|
|
// map driving instructions to images
|
|
// [TODO: better implementation, language-safe]
|
|
function getDirectionIcon(name) {
|
|
var directions = {
|
|
"Turn left":"turn-left.png",
|
|
"Turn right":"turn-right.png",
|
|
"U-Turn":"u-turn.png",
|
|
"Head":"continue.png",
|
|
"Continue":"continue.png",
|
|
"Turn slight left":"slight-left.png",
|
|
"Turn slight right":"slight-right.png",
|
|
"Turn sharp left":"sharp-left.png",
|
|
"Turn sharp right":"sharp-right.png",
|
|
"Enter roundabout and leave at first exit":"round-about.png",
|
|
"Enter roundabout and leave at second exit":"round-about.png",
|
|
"Enter roundabout and leave at third exit":"round-about.png",
|
|
"Enter roundabout and leave at forth exit":"round-about.png",
|
|
"Enter roundabout and leave at fifth exit":"round-about.png",
|
|
"Enter roundabout and leave at sixth exit":"round-about.png",
|
|
"Enter roundabout and leave at seventh exit":"round-about.png",
|
|
"Enter roundabout and leave at eighth exit":"round-about.png",
|
|
"Enter roundabout and leave at nineth exit":"round-about.png",
|
|
"Enter roundabout and leave at tenth exit":"round-about.png",
|
|
"Enter roundabout and leave at one of the too many exit":"round-about.png",
|
|
};
|
|
|
|
if( directions[name] )
|
|
return directions[name];
|
|
else
|
|
return "default.png";
|
|
}
|
|
|
|
|
|
// -- gui functions --
|
|
|
|
// click: button "route"
|
|
function startRouting() {
|
|
getRoute(OSRM.FULL_DESCRIPTION);
|
|
}
|
|
|
|
// click: button "reset"
|
|
function resetRouting() {
|
|
document.getElementById('input-source-name').value = "";
|
|
document.getElementById('input-target-name').value = "";
|
|
|
|
my_route.hideRoute();
|
|
my_markers.removeAll();
|
|
my_markers.highlight.hide();
|
|
|
|
document.getElementById('information-box').innerHTML = "";
|
|
document.getElementById('information-box-headline').innerHTML = "";
|
|
}
|
|
|
|
// click: button "reverse"
|
|
function reverseRouting() {
|
|
// invert input boxes
|
|
var tmp = document.getElementById("input-source-name").value;
|
|
document.getElementById("input-source-name").value = document.getElementById("input-target-name").value;
|
|
document.getElementById("input-target-name").value = tmp;
|
|
|
|
// invert route
|
|
my_markers.route.reverse();
|
|
if(my_markers.route.length == 1) {
|
|
if(my_markers.route[0].label == OSRM.TARGET_MARKER_LABEL) {
|
|
my_markers.route[0].label = OSRM.SOURCE_MARKER_LABEL;
|
|
my_markers.route[0].marker.setIcon( new L.Icon('images/marker-source.png') );
|
|
} else if(my_markers.route[0].label == OSRM.SOURCE_MARKER_LABEL) {
|
|
my_markers.route[0].label = OSRM.TARGET_MARKER_LABEL;
|
|
my_markers.route[0].marker.setIcon( new L.Icon('images/marker-target.png') );
|
|
}
|
|
} else if(my_markers.route.length > 1){
|
|
my_markers.route[0].label = OSRM.SOURCE_MARKER_LABEL;
|
|
my_markers.route[0].marker.setIcon( new L.Icon('images/marker-source.png') );
|
|
|
|
my_markers.route[my_markers.route.length-1].label = OSRM.TARGET_MARKER_LABEL;
|
|
my_markers.route[my_markers.route.length-1].marker.setIcon( new L.Icon('images/marker-target.png') );
|
|
}
|
|
|
|
// recompute route
|
|
getRoute(OSRM.FULL_DESCRIPTION);
|
|
my_markers.highlight.hide();
|
|
}
|