2 // Routino router web page Javascript
4 // Part of the Routino routing software.
6 // This file Copyright 2008-2010 Andrew M. Bishop
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as published by
10 // the Free Software Foundation, either version 3 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 ////////////////////////////////////////////////////////////////////////////////
23 /////////////////////////// Routino default profile ////////////////////////////
24 ////////////////////////////////////////////////////////////////////////////////
26 var routino={ // contains all default Routino options (generated using "--help-profile-js").
28 // Default transport type
29 transport: 'motorcar',
32 transports: {foot: 1, horse: 2, wheelchair: 3, bicycle: 4, moped: 5, motorbike: 6, motorcar: 7, goods: 8, hgv: 9, psv: 10},
35 highways: {motorway: 1, trunk: 2, primary: 3, secondary: 4, tertiary: 5, unclassified: 6, residential: 7, service: 8, track: 9, cycleway: 10, path: 11, steps: 12},
38 properties: {paved: 1, multilane: 2, bridge: 3, tunnel: 4},
41 restrictions: {oneway: 1, weight: 2, height: 3, width: 4, length: 5},
45 motorway: {foot: 0, horse: 0, wheelchair: 0, bicycle: 0, moped: 0, motorbike: 100, motorcar: 100, goods: 100, hgv: 100, psv: 100},
46 trunk: {foot: 40, horse: 25, wheelchair: 40, bicycle: 30, moped: 90, motorbike: 100, motorcar: 100, goods: 100, hgv: 100, psv: 100},
47 primary: {foot: 50, horse: 50, wheelchair: 50, bicycle: 70, moped: 100, motorbike: 90, motorcar: 90, goods: 90, hgv: 90, psv: 90},
48 secondary: {foot: 60, horse: 50, wheelchair: 60, bicycle: 80, moped: 90, motorbike: 80, motorcar: 80, goods: 80, hgv: 80, psv: 80},
49 tertiary: {foot: 70, horse: 75, wheelchair: 70, bicycle: 90, moped: 80, motorbike: 70, motorcar: 70, goods: 70, hgv: 70, psv: 70},
50 unclassified: {foot: 80, horse: 75, wheelchair: 80, bicycle: 90, moped: 70, motorbike: 60, motorcar: 60, goods: 60, hgv: 60, psv: 60},
51 residential: {foot: 90, horse: 75, wheelchair: 90, bicycle: 90, moped: 60, motorbike: 50, motorcar: 50, goods: 50, hgv: 50, psv: 50},
52 service: {foot: 90, horse: 75, wheelchair: 90, bicycle: 90, moped: 80, motorbike: 80, motorcar: 80, goods: 80, hgv: 80, psv: 80},
53 track: {foot: 95, horse: 100, wheelchair: 95, bicycle: 90, moped: 0, motorbike: 0, motorcar: 0, goods: 0, hgv: 0, psv: 0},
54 cycleway: {foot: 95, horse: 90, wheelchair: 95, bicycle: 100, moped: 0, motorbike: 0, motorcar: 0, goods: 0, hgv: 0, psv: 0},
55 path: {foot: 100, horse: 100, wheelchair: 100, bicycle: 90, moped: 0, motorbike: 0, motorcar: 0, goods: 0, hgv: 0, psv: 0},
56 steps: {foot: 80, horse: 0, wheelchair: 0, bicycle: 0, moped: 0, motorbike: 0, motorcar: 0, goods: 0, hgv: 0, psv: 0}
61 motorway: {foot: 0, horse: 0, wheelchair: 0, bicycle: 0, moped: 48, motorbike: 112, motorcar: 112, goods: 96, hgv: 89, psv: 89},
62 trunk: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 96, motorcar: 96, goods: 96, hgv: 80, psv: 80},
63 primary: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 96, motorcar: 96, goods: 96, hgv: 80, psv: 80},
64 secondary: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 88, motorcar: 88, goods: 88, hgv: 80, psv: 80},
65 tertiary: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 80, motorcar: 80, goods: 80, hgv: 80, psv: 80},
66 unclassified: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 64, motorcar: 64, goods: 64, hgv: 64, psv: 64},
67 residential: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 48, motorcar: 48, goods: 48, hgv: 48, psv: 48},
68 service: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 32, motorbike: 32, motorcar: 32, goods: 32, hgv: 32, psv: 32},
69 track: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 16, motorbike: 16, motorcar: 16, goods: 16, hgv: 16, psv: 16},
70 cycleway: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 0, motorbike: 0, motorcar: 0, goods: 0, hgv: 0, psv: 0},
71 path: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 0, motorbike: 0, motorcar: 0, goods: 0, hgv: 0, psv: 0},
72 steps: {foot: 4, horse: 0, wheelchair: 4, bicycle: 0, moped: 0, motorbike: 0, motorcar: 0, goods: 0, hgv: 0, psv: 0}
77 paved: {foot: 50, horse: 20, wheelchair: 90, bicycle: 50, moped: 100, motorbike: 100, motorcar: 100, goods: 100, hgv: 100, psv: 100},
78 multilane: {foot: 25, horse: 25, wheelchair: 25, bicycle: 25, moped: 25, motorbike: 75, motorcar: 75, goods: 75, hgv: 75, psv: 75},
79 bridge: {foot: 50, horse: 50, wheelchair: 50, bicycle: 50, moped: 50, motorbike: 50, motorcar: 50, goods: 50, hgv: 50, psv: 50},
80 tunnel: {foot: 50, horse: 50, wheelchair: 50, bicycle: 50, moped: 50, motorbike: 50, motorcar: 50, goods: 50, hgv: 50, psv: 50}
84 profile_restrictions: {
85 oneway: {foot: 0, horse: 1, wheelchair: 0, bicycle: 1, moped: 1, motorbike: 1, motorcar: 1, goods: 1, hgv: 1, psv: 1},
86 weight: {foot: 0.0, horse: 0.0, wheelchair: 0.0, bicycle: 0.0, moped: 0.0, motorbike: 0.0, motorcar: 0.0, goods: 5.0, hgv: 10.0, psv: 15.0},
87 height: {foot: 0.0, horse: 0.0, wheelchair: 0.0, bicycle: 0.0, moped: 0.0, motorbike: 0.0, motorcar: 0.0, goods: 2.5, hgv: 3.0, psv: 3.0},
88 width: {foot: 0.0, horse: 0.0, wheelchair: 0.0, bicycle: 0.0, moped: 0.0, motorbike: 0.0, motorcar: 0.0, goods: 2.0, hgv: 2.5, psv: 2.5},
89 length: {foot: 0.0, horse: 0.0, wheelchair: 0.0, bicycle: 0.0, moped: 0.0, motorbike: 0.0, motorcar: 0.0, goods: 5.0, hgv: 6.0, psv: 6.0}
92 }; // end of routino variable
94 // Make a deep copy of the routino profile.
96 var routino_default={};
97 for(var l1 in routino)
98 if(typeof(routino[l1])!='object')
99 routino_default[l1]=routino[l1];
102 routino_default[l1]={};
103 for(var l2 in routino[l1])
104 if(typeof(routino[l1][l2])!='object')
105 routino_default[l1][l2]=Number(routino[l1][l2]);
108 routino_default[l1][l2]={};
109 for(var l3 in routino[l1][l2])
110 routino_default[l1][l2][l3]=Number(routino[l1][l2][l3]);
115 ////////////////////////////////////////////////////////////////////////////////
116 //////////////////////////////// Form handling /////////////////////////////////
117 ////////////////////////////////////////////////////////////////////////////////
120 // Form initialisation - fill in the uninitialised parts
125 // Update the routino variable with the URL settings (from the HTML).
127 for(var lang=0;lang< document.forms["form"].elements["language"].length;lang++)
128 if(document.forms["form"].elements["language"][lang].checked)
129 formSetLanguage(document.forms["form"].elements["language"][lang].value);
133 for(var key in routino.transports)
134 if(document.forms["form"].elements["transport"][routino.transports[key]-1].checked)
138 formSetTransport(routino.transport);
141 routino.transport=transport;
143 for(var key in routino.profile_highway)
145 if(document.forms["form"].elements["highway-" + key].value=="")
146 document.forms["form"].elements["highway-" + key].value=routino.profile_highway[key][routino.transport];
151 for(var key in routino.profile_speed)
153 if(document.forms["form"].elements["speed-" + key].value=="")
154 document.forms["form"].elements["speed-" + key].value=routino.profile_speed[key][routino.transport];
159 for(var key in routino.profile_property)
161 if(document.forms["form"].elements["property-" + key].value=="")
162 document.forms["form"].elements["property-" + key].value=routino.profile_property[key][routino.transport];
164 formSetProperty(key);
167 for(var key in routino.restrictions)
170 formSetRestriction(key);
173 if(document.forms["form"].elements["restrict-" + key].value=="")
174 document.forms["form"].elements["restrict-" + key].value=routino.profile_restrictions[key][routino.transport];
176 formSetRestriction(key);
181 // Delete the extra empty waypoints
185 for(var marker=nmarkers;marker>=1;marker--)
187 var lon=document.forms["form"].elements["lon" + marker].value;
188 var lat=document.forms["form"].elements["lat" + marker].value;
190 if(lon != "" && lat != "")
193 markerAddMap(marker);
196 markerRemove(marker);
199 // Get the home location cookie and compare to each waypoint
201 var cookies=document.cookie.split('; ');
203 for(var cookie=0;cookie<cookies.length;cookie++)
204 if(cookies[cookie].substr(0,"Routino-home".length)=="Routino-home")
206 var data=cookies[cookie].split(/[=:;]/);
208 if(data[1]=="lon") homelon=Number(data[2]);
209 if(data[3]=="lat") homelat=Number(data[4]);
212 if(homelon!=null && homelat!=null)
214 for(var marker=nmarkers;marker>=1;marker--)
216 var lon=document.forms["form"].elements["lon" + marker].value;
217 var lat=document.forms["form"].elements["lat" + marker].value;
219 if(lon==homelon && lat==homelat)
223 // If the first location is empty and the cookie is set then fill it.
225 if(document.forms["form"].elements["lon1"].value=="" && document.forms["form"].elements["lat1"].value=="")
227 document.forms["form"].elements["lon1"].value=homelon;
228 document.forms["form"].elements["lat1"].value=homelat;
239 // Change of language in the form
242 function formSetLanguage(type)
244 routino.language=type;
251 // Change of transport in the form
254 function formSetTransport(type)
256 routino.transport=type;
258 for(var key in routino.transports)
259 document.forms["form"].elements["transport"][routino.transports[key]-1].checked=(key==routino.transport);
261 for(var key in routino.profile_highway)
262 document.forms["form"].elements["highway-" + key].value=routino.profile_highway[key][routino.transport];
264 for(var key in routino.profile_speed)
265 document.forms["form"].elements["speed-" + key].value=routino.profile_speed[key][routino.transport];
267 for(var key in routino.profile_property)
268 document.forms["form"].elements["property-" + key].value=routino.profile_property[key][routino.transport];
270 for(var key in routino.restrictions)
273 document.forms["form"].elements["restrict-" + key].checked=routino.profile_restrictions[key][routino.transport];
275 document.forms["form"].elements["restrict-" + key].value=routino.profile_restrictions[key][routino.transport];
285 // Change of highway in the form
288 function formSetHighway(type)
290 routino.profile_highway[type][routino.transport]=document.forms["form"].elements["highway-" + type].value;
299 // Change of Speed in the form
302 function formSetSpeed(type)
304 routino.profile_speed[type][routino.transport]=document.forms["form"].elements["speed-" + type].value;
313 // Change of Property in the form
316 function formSetProperty(type)
318 routino.profile_property[type][routino.transport]=document.forms["form"].elements["property-" + type].value;
327 // Change of oneway rule in the form
330 function formSetRestriction(type)
333 routino.profile_restrictions[type][routino.transport]=document.forms["form"].elements["restrict-" + type].checked;
335 routino.profile_restrictions[type][routino.transport]=document.forms["form"].elements["restrict-" + type].value;
344 // Set the feature coordinates from the form when the form changes.
347 function formSetCoords(marker)
349 var lonlat=map.getCenter().clone();
351 lonlat.transform(map.getProjectionObject(),epsg4326);
353 var lon=document.forms["form"].elements["lon" + marker].value;
354 var lat=document.forms["form"].elements["lat" + marker].value;
358 if(lon<-180) lon=-180;
359 if(lon>+180) lon=+180;
365 if(lat<-90 ) lat=-90 ;
366 if(lat>+90 ) lat=+90 ;
370 var point = lonlat.clone();
372 point.transform(epsg4326,map.getProjectionObject());
374 markers[marker].move(point);
378 coordsSetForm(marker);
383 // Set the feature coordinates in the form.
386 function coordsSetForm(marker)
388 var lonlat = new OpenLayers.LonLat(markers[marker].geometry.x, markers[marker].geometry.y);
389 lonlat.transform(map.getProjectionObject(),epsg4326);
391 var lon=format5f(lonlat.lon);
392 var lat=format5f(lonlat.lat);
394 document.forms["form"].elements["lon" + marker].value=lon;
395 document.forms["form"].elements["lat" + marker].value=lat;
404 // Format a number in printf("%.5f") format.
407 function format5f(number)
409 var newnumber=Math.floor(number*100000+0.5);
412 if(newnumber>=0 && newnumber<100000) delta= 100000;
413 if(newnumber<0 && newnumber>-100000) delta=-100000;
415 var string=String(newnumber+delta);
417 var intpart =string.substring(0,string.length-5);
418 var fracpart=string.substring(string.length-5,string.length);
420 if(delta>0) intpart="0";
421 if(delta<0) intpart="-0";
423 return(intpart + "." + fracpart);
428 // Build a set of URL arguments
431 function buildURLArguments(all)
435 url=url + "transport=" + routino.transport;
437 for(var marker=1;marker<=vismarkers;marker++)
438 if(markers[marker].style.display == "" || all)
440 url=url + ";lon" + marker + "=" + document.forms["form"].elements["lon" + marker].value;
441 url=url + ";lat" + marker + "=" + document.forms["form"].elements["lat" + marker].value;
444 for(var key in routino.profile_highway)
445 if(routino.profile_highway[key][routino.transport]!=routino_default.profile_highway[key][routino.transport])
446 url=url + ";highway-" + key + "=" + routino.profile_highway[key][routino.transport];
448 for(var key in routino.profile_speed)
449 if(routino.profile_speed[key][routino.transport]!=routino_default.profile_speed[key][routino.transport])
450 url=url + ";speed-" + key + "=" + routino.profile_speed[key][routino.transport];
452 for(var key in routino.profile_property)
453 if(routino.profile_property[key][routino.transport]!=routino_default.profile_property[key][routino.transport])
454 url=url + ";property-" + key + "=" + routino.profile_property[key][routino.transport];
456 for(var key in routino.restrictions)
457 if(routino.profile_restrictions[key][routino.transport]!=routino_default.profile_restrictions[key][routino.transport])
458 url=url + ";" + key + "=" + routino.profile_restrictions[key][routino.transport];
461 url=url + ";language=" + routino.language;
471 function updateCustomURL()
473 var visualiser_url=document.getElementById("visualiser_url");
474 var link_url =document.getElementById("link_url");
475 var edit_url =document.getElementById("edit_url");
477 visualiser_url.href="customvisualiser.cgi?" + map_args;
478 link_url.href="customrouter.cgi" + buildURLArguments(1) + ";" + map_args;
479 edit_url.href="http://www.openstreetmap.org/edit?" + map_args;
484 // Block the use of the return key to submit the form
487 function block_return_key()
489 var form=document.getElementById("form");
491 if(form.addEventListener)
492 form.addEventListener('keyup', discardReturnKey, false);
493 else if(form.attachEvent)
494 form.attachEvent('keyup', discardReturnKey); // Internet Explorer
498 // Function to discard the return key if pressed
501 function discardReturnKey(ev)
510 ////////////////////////////////////////////////////////////////////////////////
511 ///////////////////////////////// Map handling /////////////////////////////////
512 ////////////////////////////////////////////////////////////////////////////////
515 var layerMapOSM, layerVectors, layerGPX;
516 var epsg4326, epsg900913;
520 // Initialise the 'map' object
523 function map_init(lat,lon,zoom)
525 // Default configuration:
526 // UK coordinate range
527 // West -11.0, South 49.5, East 2.0, North 61.0
528 // Zoom level 4 to 15
530 // EDIT THIS below to change the visible map limits
532 var westedge = -11.0; // Minimum longitude (degrees)
533 var eastedge = 2.0; // Maximum longitude (degrees)
534 var southedge = 49.5; // Minimum latitude (degrees)
535 var northedge = 61.0; // Maximum latitude (degrees)
536 var zoomout = 4; // Minimum zoom
537 var zoomin = 15; // Maximum zoom
539 // EDIT THIS above to change the visible map limits
545 epsg4326=new OpenLayers.Projection("EPSG:4326");
546 epsg900913=new OpenLayers.Projection("EPSG:900913");
548 map = new OpenLayers.Map ("map",
551 new OpenLayers.Control.Navigation(),
552 new OpenLayers.Control.PanZoomBar(),
553 new OpenLayers.Control.ScaleLine(),
554 new OpenLayers.Control.LayerSwitcher()
557 projection: epsg900913,
558 displayProjection: epsg4326,
560 minZoomLevel: zoomout,
561 numZoomLevels: zoomin-zoomout+1,
562 maxResolution: 156543.0339 / Math.pow(2,zoomout),
564 maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
565 restrictedExtent: new OpenLayers.Bounds(westedge,southedge,eastedge,northedge).transform(epsg4326,epsg900913),
570 map.events.register("moveend", map, mapMoved);
572 // Add a map tile layer (OpenStreetMap tiles, direct access)
574 layerMapOSM = new OpenLayers.Layer.TMS("Original OSM map",
575 "http://tile.openstreetmap.org/",
577 emptyUrl: "http://openstreetmap.org/openlayers/img/404.png",
580 displayOutsideMaxExtent: true,
583 map.addLayer(layerMapOSM);
585 // Get a URL for the tile; limited to map restricted extent.
587 function limitedUrl(bounds)
589 var z = map.getZoom() + map.minZoomLevel;
591 if (z>=7 && (bounds.right < map.restrictedExtent.left ||
592 bounds.left > map.restrictedExtent.right ||
593 bounds.top < map.restrictedExtent.bottom ||
594 bounds.bottom > map.restrictedExtent.top))
595 return this.emptyUrl;
597 var res = map.getResolution();
598 var y = Math.round((this.maxExtent.top - bounds.top) / (res * this.tileSize.h));
599 var limit = Math.pow(2, z);
601 if (y < 0 || y >= limit)
602 return this.emptyUrl;
604 var x = Math.round((bounds.left - this.maxExtent.left) / (res * this.tileSize.w));
606 x = ((x % limit) + limit) % limit;
607 return this.url + z + "/" + x + "/" + y + "." + this.type;
610 // Define a GPX layer but don't add it yet
612 layerGPX={shortest: null, quickest: null};
614 gpx_style={shortest: new OpenLayers.Style({},{strokeWidth: 3, strokeColor: "#00FF00"}),
615 quickest: new OpenLayers.Style({},{strokeWidth: 3, strokeColor: "#0000FF"})};
617 // Add a vectors layer
619 layerVectors = new OpenLayers.Layer.Vector("Markers");
620 map.addLayer(layerVectors);
630 for(var marker=1;marker<=nmarkers;marker++)
632 if(document.forms["form"].elements["lon" + marker] != undefined)
634 markers[marker] = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0),{},
635 new OpenLayers.Style({},{externalGraphic: 'icons/marker-' + marker + '-red.png',
642 layerVectors.addFeatures([markers[marker]]);
652 // A function to drag the markers
654 var drag = new OpenLayers.Control.DragFeature(layerVectors,
656 onComplete: dragComplete });
657 map.addControl(drag);
660 // Markers to highlight a selected point
662 for(var highlight in highlights)
664 highlights[highlight] = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0),{},
665 new OpenLayers.Style({},{strokeColor: route_dark_colours[highlight],
672 layerVectors.addFeatures([highlights[highlight]]);
675 // A popup for routing results
677 for(var popup in popups)
678 popups[popup] = createPopup(popup);
680 // Set the map centre to the limited range specified
682 map.setCenter(map.restrictedExtent.getCenterLonLat(), map.getZoomForExtent(map.restrictedExtent,true));
683 map.maxResolution = map.getResolution();
687 if(lon != 'lon' && lat != 'lat' && zoom != 'zoom')
689 var lonlat = new OpenLayers.LonLat(lon,lat).transform(epsg4326,map.getProjectionObject());
691 map.moveTo(lonlat,zoom-map.minZoomLevel);
702 var centre = map.getCenter().clone();
704 var lonlat = centre.transform(map.getProjectionObject(),epsg4326);
706 var zoom = this.getZoom() + map.minZoomLevel;
708 map_args="lat=" + lonlat.lat + ";lon=" + lonlat.lon + ";zoom=" + zoom;
715 // OpenLayers.Control.DragFeature callback for a drag occuring.
718 function dragMove(feature,pixel)
720 for(var marker in markers)
721 if(feature==markers[marker])
725 coordsSetForm(marker);
731 // OpenLayers.Control.DragFeature callback for completing a drag.
734 function dragComplete(feature,pixel)
736 for(var marker in markers)
737 if(feature==markers[marker])
741 coordsSetForm(marker);
746 ////////////////////////////////////////////////////////////////////////////////
747 /////////////////////////////// Marker handling ////////////////////////////////
748 ////////////////////////////////////////////////////////////////////////////////
750 var nmarkers, vismarkers, markers, markersmoved, paramschanged;
751 var homelat=null, homelon=null;
755 // Toggle a marker on the map.
758 function markerToggleMap(marker)
760 if(markers[marker].style.display == "")
761 markerRemoveMap(marker);
763 markerAddMap(marker);
768 // Show a marker on the map.
771 function markerAddMap(marker)
773 markers[marker].style.display = "";
775 formSetCoords(marker);
784 // Remove a marker from the map.
787 function markerRemoveMap(marker)
789 markers[marker].style.display = "none";
798 // Centre the marker on the map
801 function markerCentre(marker)
803 document.forms["form"].elements["lon" + marker].value="";
804 document.forms["form"].elements["lat" + marker].value="";
806 formSetCoords(marker);
813 // Clear the current marker.
816 function markerRemove(marker)
818 for(var marker2=marker;marker2<vismarkers;marker2++)
820 document.forms["form"].elements["lon" + marker2].value=document.forms["form"].elements["lon" + (marker2+1)].value;
821 document.forms["form"].elements["lat" + marker2].value=document.forms["form"].elements["lat" + (marker2+1)].value;
823 if(markers[marker2+1].style.display=="")
824 markerAddMap(marker2);
826 markerRemoveMap(marker2);
829 markerRemoveMap(vismarkers);
831 var marker_tr=document.getElementById("point" + vismarkers);
833 marker_tr.style.display="none";
845 // Add a marker before the current one.
848 function markerAddBefore(marker)
850 if(vismarkers==nmarkers || marker==1)
855 var marker_tr=document.getElementById("point" + vismarkers);
857 marker_tr.style.display="";
859 for(var marker2=vismarkers;marker2>marker;marker2--)
861 document.forms["form"].elements["lon" + marker2].value=document.forms["form"].elements["lon" + (marker2-1)].value;
862 document.forms["form"].elements["lat" + marker2].value=document.forms["form"].elements["lat" + (marker2-1)].value;
864 if(markers[marker2-1].style.display=="")
865 markerAddMap(marker2);
867 markerRemoveMap(marker2);
870 document.forms["form"].elements["lon" + marker].value="";
871 document.forms["form"].elements["lat" + marker].value="";
872 markers[marker].style.display="none";
874 markerRemoveMap(marker);
881 // Add a marker after the current one.
884 function markerAddAfter(marker)
886 if(vismarkers==nmarkers)
891 var marker_tr=document.getElementById("point" + vismarkers);
893 marker_tr.style.display="";
895 for(var marker2=vismarkers;marker2>(marker+1);marker2--)
897 document.forms["form"].elements["lon" + marker2].value=document.forms["form"].elements["lon" + (marker2-1)].value;
898 document.forms["form"].elements["lat" + marker2].value=document.forms["form"].elements["lat" + (marker2-1)].value;
900 if(markers[marker2-1].style.display=="")
901 markerAddMap(marker2);
903 markerRemoveMap(marker2);
906 document.forms["form"].elements["lon" + (marker+1)].value="";
907 document.forms["form"].elements["lat" + (marker+1)].value="";
908 markers[marker+1].style.display="none";
910 markerRemoveMap(marker+1);
917 // Set this marker as the home location.
920 function markerHome(marker)
922 if(markerHomeCookie(marker))
923 for(marker=1;marker<=nmarkers;marker++)
929 // Update an icon to set colours and home or normal marker.
932 function updateIcon(marker)
934 var lon=document.forms["form"].elements["lon" + marker].value;
935 var lat=document.forms["form"].elements["lat" + marker].value;
937 if(lon==homelon && lat==homelat)
939 if(markers[marker].style.display=="")
940 document.images["waypoint" + marker].src="icons/marker-home-red.png";
942 document.images["waypoint" + marker].src="icons/marker-home-grey.png";
944 markers[marker].style.externalGraphic="icons/marker-home-red.png";
948 if(markers[marker].style.display=="")
949 document.images["waypoint" + marker].src="icons/marker-" + marker + "-red.png";
951 document.images["waypoint" + marker].src="icons/marker-" + marker + "-grey.png";
953 markers[marker].style.externalGraphic="icons/marker-" + marker + "-red.png";
956 layerVectors.drawFeature(markers[marker]);
961 // Set or clear the home marker icon
964 function markerHomeCookie(marker)
966 var lon=document.forms["form"].elements["lon" + marker].value;
967 var lat=document.forms["form"].elements["lat" + marker].value;
969 if(lon=="" || lat=="")
973 var date = new Date();
975 if((homelat==null && homelon==null) ||
976 (homelat!=lat && homelon!=lon))
978 cookie="Routino-home=lon:" + lon + ":lat:" + lat;
980 date.setUTCFullYear(date.getUTCFullYear()+5);
987 cookie="Routino-home=unset";
989 date.setUTCFullYear(date.getUTCFullYear()-1);
995 document.cookie=cookie + ";expires=" + date.toGMTString();
1002 // Move this marker up.
1005 function markerMoveUp(marker)
1010 markerSwap(marker,marker-1);
1015 // Move this marker down.
1018 function markerMoveDown(marker)
1020 if(marker==vismarkers)
1023 markerSwap(marker,marker+1);
1028 // Swap a pair of markers.
1031 function markerSwap(marker1,marker2)
1033 var lon=document.forms["form"].elements["lon" + marker1].value;
1034 var lat=document.forms["form"].elements["lat" + marker1].value;
1035 var display=markers[marker1].style.display;
1037 document.forms["form"].elements["lon" + marker1].value=document.forms["form"].elements["lon" + marker2].value;
1038 document.forms["form"].elements["lat" + marker1].value=document.forms["form"].elements["lat" + marker2].value;
1039 if(markers[marker2].style.display=="")
1040 markerAddMap(marker1);
1042 markerRemoveMap(marker1);
1044 document.forms["form"].elements["lon" + marker2].value=lon;
1045 document.forms["form"].elements["lat" + marker2].value=lat;
1047 markerAddMap(marker2);
1049 markerRemoveMap(marker2);
1056 // Reverse the markers.
1059 function markersReverse()
1061 for(var marker=1;marker<=vismarkers/2;marker++)
1062 markerSwap(marker,vismarkers+1-marker);
1068 ////////////////////////////////////////////////////////////////////////////////
1069 //////////////////////////// Route results handling ////////////////////////////
1070 ////////////////////////////////////////////////////////////////////////////////
1072 var route_light_colours={shortest: "#60C060", quickest: "#6060C0"};
1073 var route_dark_colours ={shortest: "#408040", quickest: "#404080"};
1075 var highlights={shortest: null, quickest: null};
1076 var popups={shortest: null, quickest: null};
1077 var routepoints={shortest: {}, quickest: {}};
1078 var gpx_style={shortest: null, quickest: null};
1081 // Zoom to a specific item in the route
1084 function zoomTo(type,line)
1086 var lonlat = new OpenLayers.LonLat(routepoints[type][line].lon,routepoints[type][line].lat).transform(epsg4326,map.getProjectionObject());
1088 map.moveTo(lonlat,map.numZoomLevels-2);
1093 // Highlight a specific item in the route
1096 function highlight(type,line)
1100 highlights[type].style.display = "none";
1102 drawPopup(popups[type],null);
1108 var lonlat = new OpenLayers.LonLat(routepoints[type][line].lon,routepoints[type][line].lat).transform(epsg4326,map.getProjectionObject());
1110 highlights[type].move(lonlat);
1112 if(highlights[type].style.display = "none")
1113 highlights[type].style.display = "";
1117 drawPopup(popups[type],"<table>" + routepoints[type][line].html + "</table>");
1120 layerVectors.drawFeature(highlights[type]);
1125 // Create a popup - not using OpenLayers because want it fixed on screen not fixed on map.
1128 function createPopup(type)
1130 var popup=document.createElement('div');
1132 popup.className = "popup";
1134 popup.innerHTML = "<span></span>";
1136 popup.style.display = "none";
1138 popup.style.position = "fixed";
1139 popup.style.top = "-4000px";
1140 popup.style.left = "-4000px";
1141 popup.style.zIndex = "100";
1143 popup.style.padding = "5px";
1145 popup.style.opacity=0.85;
1146 popup.style.backgroundColor=route_light_colours[type];
1147 popup.style.border="4px solid " + route_dark_colours[type];
1149 document.body.appendChild(popup);
1156 // Draw a popup - not using OpenLayers because want it fixed on screen not fixed on map.
1159 function drawPopup(popup,html)
1163 popup.style.display="none";
1167 if(popup.style.display=="none")
1169 var map_div=document.getElementById("map");
1171 popup.style.left =map_div.offsetParent.offsetLeft+map_div.offsetLeft+60 + "px";
1172 popup.style.top = map_div.offsetTop +30 + "px";
1173 popup.style.width =map_div.clientWidth-100 + "px";
1175 popup.style.display="";
1178 popup.innerHTML=html;
1183 // Remove a GPX trace
1186 function removeGPXTrace(type)
1188 map.removeLayer(layerGPX[type]);
1189 layerGPX[type].destroy();
1190 layerGPX[type]=null;
1192 displayStatus(type,"no_info");
1194 var div_links=document.getElementById(type + "_links");
1195 div_links.style.display = "none";
1197 var div_route=document.getElementById(type + "_route");
1198 div_route.innerHTML = "";
1200 hideshow_hide(type);
1204 ////////////////////////////////////////////////////////////////////////////////
1205 /////////////////////////////// Server handling ////////////////////////////////
1206 ////////////////////////////////////////////////////////////////////////////////
1209 // Display data statistics
1212 function displayStatistics()
1214 // Use AJAX to get the statistics
1216 OpenLayers.loadURL("statistics.cgi",null,null,runStatisticsSuccess);
1221 // Success in running data statistics generation.
1224 function runStatisticsSuccess(response)
1226 var statistics_data=document.getElementById("statistics_data");
1227 var statistics_link=document.getElementById("statistics_link");
1229 statistics_data.innerHTML="<pre>" + response.responseText + "</pre>";
1231 statistics_link.style.display="none";
1236 // Submit form - perform the routing
1239 function findRoute(type)
1241 tab_select("results");
1243 hideshow_hide('help_options');
1244 hideshow_hide('shortest');
1245 hideshow_hide('quickest');
1247 displayStatus("result","running");
1249 var url="router.cgi" + buildURLArguments(0) + ";type=" + type;
1251 // Destroy the existing layer(s)
1253 if(markersmoved || paramschanged)
1255 if(layerGPX.shortest!=null)
1256 removeGPXTrace("shortest");
1257 if(layerGPX.quickest!=null)
1258 removeGPXTrace("quickest");
1260 paramschanged=false;
1262 else if(layerGPX[type]!=null)
1263 removeGPXTrace(type);
1265 // Use AJAX to run the router
1269 OpenLayers.loadURL(url,null,null,runRouterSuccess,runRouterFailure);
1274 // Success in running router.
1277 function runRouterSuccess(response)
1279 var lines=response.responseText.split('\n');
1282 var cpuinfo=lines[1];
1283 var distinfo=lines[2];
1284 var message=lines[3];
1286 // Update the status message
1290 displayStatus("result","error");
1291 hideshow_show('help_route');
1296 displayStatus("result","complete");
1297 hideshow_hide('help_route');
1300 // Update the routing result message
1302 displayStatus(routing_type,"info",distinfo.bold());
1306 link=document.getElementById(routing_type + "_html");
1307 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=html";
1308 link=document.getElementById(routing_type + "_gpx_track");
1309 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-track";
1310 link=document.getElementById(routing_type + "_gpx_route");
1311 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-route";
1312 link=document.getElementById(routing_type + "_text_all");
1313 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=text-all";
1314 link=document.getElementById(routing_type + "_text");
1315 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=text";
1317 var div_links=document.getElementById(routing_type + "_links");
1318 div_links.style.display = "";
1322 var url="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-track";
1324 layerGPX[routing_type] = new OpenLayers.Layer.GML("GPX (" + routing_type + ")", url,
1326 format: OpenLayers.Format.GPX,
1327 style: gpx_style[routing_type],
1328 projection: map.displayProjection
1331 map.addLayer(layerGPX[routing_type]);
1333 hideshow_show(routing_type);
1335 displayResult(routing_type,uuid);
1340 // Failure in running router.
1343 function runRouterFailure(response)
1345 displayStatus("result","failed");
1350 // Display the status
1353 function displayStatus(type,subtype,content)
1355 var div_status=document.getElementById(type + "_status");
1357 var child=div_status.firstChild;
1361 if(child.id != undefined)
1362 child.style.display="none";
1364 child=child.nextSibling;
1366 while(child != undefined);
1368 var span_status=document.getElementById(type + "_status_" + subtype);
1370 span_status.style.display="";
1373 span_status.innerHTML=content;
1378 // Display the route
1381 function displayResult(type,uuid)
1383 routing_type = type;
1387 var url="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=html";
1389 // Use AJAX to get the route
1391 OpenLayers.loadURL(url,null,null,getRouteSuccess,getRouteFailure);
1396 // Success in getting route.
1399 function getRouteSuccess(response)
1401 var lines=response.responseText.split('\n');
1402 var div_route=document.getElementById(routing_type + "_route");
1404 routepoints[routing_type]=[];
1406 var points=routepoints[routing_type];
1410 var total_table,total_word;
1412 for(var line=0;line<lines.length;line++)
1414 var thisline=lines[line];
1418 if(thisline.match('<table>'))
1424 if(thisline.match('</table>'))
1427 if(thisline.match('<tr class=\'([a-z])\'>'))
1429 var rowtype=RegExp.$1;
1433 thisline.match('<td class=\'r\'> *([-0-9.]+) *([-0-9.]+)');
1434 points[point]={lat: Number(RegExp.$1), lon: Number(RegExp.$2), html: "", highway: "", distance: "", total: ""};
1438 else if(rowtype=='n')
1440 points[point-1].html += thisline;
1442 else if(rowtype=='s')
1444 thisline.match('<span class=\'h\'>([^<]+)</span>');
1445 points[point-1].highway = RegExp.$1;
1447 thisline.match('<span class=\'d\'>([^<]+)</span>');
1448 points[point-1].distance = RegExp.$1;
1450 thisline.match('(<span class=\'j\'>[^<]+</span>)');
1451 points[point-1].total = RegExp.$1;
1453 thisline.match('^(.*).<span class=\'j\'>');
1455 points[point-1].html += RegExp.$1;
1457 else if(rowtype=='t')
1459 points[point-1].html += thisline;
1461 thisline.match('^(.*<td class=\'r\'>)');
1462 total_table = RegExp.$1;
1464 thisline.match('<td class=\'l\'>([^<]+)<');
1465 total_word = RegExp.$1;
1467 thisline.match('<span class=\'j\'>([^<]+)</span>');
1468 points[point-1].total = RegExp.$1;
1473 var result="<table onmouseout='highlight(\"" + routing_type + "\",-1)'>";
1475 for(var p=0;p<point-1;p++)
1477 points[p].html += total_table + points[p].total;
1479 result=result + "<tr onclick='zoomTo(\"" + routing_type + "\"," + p + ")'" +
1480 " onmouseover='highlight(\"" + routing_type + "\"," + p + ")'>" +
1481 "<td class='distance' title='" + points[p].distance + "'>#" + (p+1) +
1482 "<td class='highway'>" + points[p].highway;
1485 result=result + "<tr onclick='zoomTo(\"" + routing_type + "\"," + p + ")'" +
1486 " onmouseover='highlight(\"" + routing_type + "\"," + p + ")'>" +
1487 "<td colspan='2'>" + total_word + " " + points[p].total;
1489 result=result + "</table>";
1491 div_route.innerHTML=result;
1496 // Failure in getting route.
1499 function getRouteFailure(response)
1501 var div_route=document.getElementById(routing_type + "_route");
1502 div_route.innerHTML = "";