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-json").
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, ferry: 13 },
38 properties: { paved: 1, multilane: 2, bridge: 3, tunnel: 4, footroute: 5, bicycleroute: 6 },
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 },
57 ferry: { foot: 20, horse: 20, wheelchair: 20, bicycle: 20, moped: 20, motorbike: 20, motorcar: 20, goods: 20, hgv: 20, psv: 20 }
62 motorway: { foot: 0, horse: 0, wheelchair: 0, bicycle: 0, moped: 48, motorbike: 112, motorcar: 112, goods: 96, hgv: 89, psv: 89 },
63 trunk: { foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 96, motorcar: 96, goods: 96, hgv: 80, psv: 80 },
64 primary: { foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 96, motorcar: 96, goods: 96, hgv: 80, psv: 80 },
65 secondary: { foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 88, motorcar: 88, goods: 88, hgv: 80, psv: 80 },
66 tertiary: { foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 80, motorcar: 80, goods: 80, hgv: 80, psv: 80 },
67 unclassified: { foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 64, motorcar: 64, goods: 64, hgv: 64, psv: 64 },
68 residential: { foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 48, motorcar: 48, goods: 48, hgv: 48, psv: 48 },
69 service: { foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 32, motorbike: 32, motorcar: 32, goods: 32, hgv: 32, psv: 32 },
70 track: { foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 16, motorbike: 16, motorcar: 16, goods: 16, hgv: 16, psv: 16 },
71 cycleway: { foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 0, motorbike: 0, motorcar: 0, goods: 0, hgv: 0, psv: 0 },
72 path: { foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 0, motorbike: 0, motorcar: 0, goods: 0, hgv: 0, psv: 0 },
73 steps: { foot: 4, horse: 0, wheelchair: 4, bicycle: 0, moped: 0, motorbike: 0, motorcar: 0, goods: 0, hgv: 0, psv: 0 },
74 ferry: { foot: 10, horse: 10, wheelchair: 10, bicycle: 10, moped: 10, motorbike: 10, motorcar: 10, goods: 10, hgv: 10, psv: 10 }
79 paved: { foot: 50, horse: 20, wheelchair: 90, bicycle: 50, moped: 100, motorbike: 100, motorcar: 100, goods: 100, hgv: 100, psv: 100 },
80 multilane: { foot: 25, horse: 25, wheelchair: 25, bicycle: 25, moped: 35, motorbike: 60, motorcar: 60, goods: 60, hgv: 60, psv: 60 },
81 bridge: { foot: 50, horse: 50, wheelchair: 50, bicycle: 50, moped: 50, motorbike: 50, motorcar: 50, goods: 50, hgv: 50, psv: 50 },
82 tunnel: { foot: 50, horse: 50, wheelchair: 50, bicycle: 50, moped: 50, motorbike: 50, motorcar: 50, goods: 50, hgv: 50, psv: 50 },
83 footroute: { foot: 55, horse: 50, wheelchair: 55, bicycle: 50, moped: 50, motorbike: 50, motorcar: 45, goods: 45, hgv: 45, psv: 45 },
84 bicycleroute: { foot: 55, horse: 50, wheelchair: 55, bicycle: 60, moped: 50, motorbike: 50, motorcar: 45, goods: 45, hgv: 45, psv: 45 }
88 profile_restrictions: {
89 oneway: { foot: 0, horse: 1, wheelchair: 0, bicycle: 1, moped: 1, motorbike: 1, motorcar: 1, goods: 1, hgv: 1, psv: 1 },
90 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 },
91 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 },
92 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 },
93 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 }
96 }; // end of routino variable
98 // Make a deep copy of the routino profile.
100 var routino_default={};
101 for(var l1 in routino)
102 if(typeof(routino[l1])!='object')
103 routino_default[l1]=routino[l1];
106 routino_default[l1]={};
107 for(var l2 in routino[l1])
108 if(typeof(routino[l1][l2])!='object')
109 routino_default[l1][l2]=Number(routino[l1][l2]);
112 routino_default[l1][l2]={};
113 for(var l3 in routino[l1][l2])
114 routino_default[l1][l2][l3]=Number(routino[l1][l2][l3]);
119 ////////////////////////////////////////////////////////////////////////////////
120 //////////////////////////////// Form handling /////////////////////////////////
121 ////////////////////////////////////////////////////////////////////////////////
124 // Form initialisation - fill in the uninitialised parts
129 // Update the routino variable with the URL settings (from the HTML).
131 for(var lang=0;lang< document.forms["form"].elements["language"].length;lang++)
132 if(document.forms["form"].elements["language"][lang].checked)
133 formSetLanguage(document.forms["form"].elements["language"][lang].value);
137 for(var key in routino.transports)
138 if(document.forms["form"].elements["transport"][routino.transports[key]-1].checked)
142 formSetTransport(routino.transport);
145 routino.transport=transport;
147 for(var key in routino.profile_highway)
149 if(document.forms["form"].elements["highway-" + key].value=="")
150 document.forms["form"].elements["highway-" + key].value=routino.profile_highway[key][routino.transport];
155 for(var key in routino.profile_speed)
157 if(document.forms["form"].elements["speed-" + key].value=="")
158 document.forms["form"].elements["speed-" + key].value=routino.profile_speed[key][routino.transport];
163 for(var key in routino.profile_property)
165 if(document.forms["form"].elements["property-" + key].value=="")
166 document.forms["form"].elements["property-" + key].value=routino.profile_property[key][routino.transport];
168 formSetProperty(key);
171 for(var key in routino.restrictions)
174 formSetRestriction(key);
177 if(document.forms["form"].elements["restrict-" + key].value=="")
178 document.forms["form"].elements["restrict-" + key].value=routino.profile_restrictions[key][routino.transport];
180 formSetRestriction(key);
185 // Delete the extra empty waypoints
189 for(var marker=nmarkers;marker>=1;marker--)
191 var lon=document.forms["form"].elements["lon" + marker].value;
192 var lat=document.forms["form"].elements["lat" + marker].value;
194 if(lon != "" && lat != "")
197 markerAddMap(marker);
200 markerRemove(marker);
203 // Get the home location cookie and compare to each waypoint
205 var cookies=document.cookie.split('; ');
207 for(var cookie=0;cookie<cookies.length;cookie++)
208 if(cookies[cookie].substr(0,"Routino-home".length)=="Routino-home")
210 var data=cookies[cookie].split(/[=:;]/);
212 if(data[1]=="lon") homelon=Number(data[2]);
213 if(data[3]=="lat") homelat=Number(data[4]);
216 if(homelon!=null && homelat!=null)
218 for(var marker=nmarkers;marker>=1;marker--)
220 var lon=document.forms["form"].elements["lon" + marker].value;
221 var lat=document.forms["form"].elements["lat" + marker].value;
223 if(lon==homelon && lat==homelat)
227 // If the first location is empty and the cookie is set then fill it.
229 if(document.forms["form"].elements["lon1"].value=="" && document.forms["form"].elements["lat1"].value=="")
231 document.forms["form"].elements["lon1"].value=homelon;
232 document.forms["form"].elements["lat1"].value=homelat;
243 // Change of language in the form
246 function formSetLanguage(type)
248 routino.language=type;
255 // Change of transport in the form
258 function formSetTransport(type)
260 routino.transport=type;
262 for(var key in routino.transports)
263 document.forms["form"].elements["transport"][routino.transports[key]-1].checked=(key==routino.transport);
265 for(var key in routino.profile_highway)
266 document.forms["form"].elements["highway-" + key].value=routino.profile_highway[key][routino.transport];
268 for(var key in routino.profile_speed)
269 document.forms["form"].elements["speed-" + key].value=routino.profile_speed[key][routino.transport];
271 for(var key in routino.profile_property)
272 document.forms["form"].elements["property-" + key].value=routino.profile_property[key][routino.transport];
274 for(var key in routino.restrictions)
277 document.forms["form"].elements["restrict-" + key].checked=routino.profile_restrictions[key][routino.transport];
279 document.forms["form"].elements["restrict-" + key].value=routino.profile_restrictions[key][routino.transport];
289 // Change of highway in the form
292 function formSetHighway(type)
294 routino.profile_highway[type][routino.transport]=document.forms["form"].elements["highway-" + type].value;
303 // Change of Speed in the form
306 function formSetSpeed(type)
308 routino.profile_speed[type][routino.transport]=document.forms["form"].elements["speed-" + type].value;
317 // Change of Property in the form
320 function formSetProperty(type)
322 routino.profile_property[type][routino.transport]=document.forms["form"].elements["property-" + type].value;
331 // Change of oneway rule in the form
334 function formSetRestriction(type)
337 routino.profile_restrictions[type][routino.transport]=document.forms["form"].elements["restrict-" + type].checked;
339 routino.profile_restrictions[type][routino.transport]=document.forms["form"].elements["restrict-" + type].value;
348 // Set the feature coordinates from the form when the form changes.
351 function formSetCoords(marker)
353 var lonlat=map.getCenter().clone();
355 lonlat.transform(map.getProjectionObject(),epsg4326);
357 var lon=document.forms["form"].elements["lon" + marker].value;
358 var lat=document.forms["form"].elements["lat" + marker].value;
362 if(lon<-180) lon=-180;
363 if(lon>+180) lon=+180;
369 if(lat<-90 ) lat=-90 ;
370 if(lat>+90 ) lat=+90 ;
374 var point = lonlat.clone();
376 point.transform(epsg4326,map.getProjectionObject());
378 markers[marker].move(point);
382 coordsSetForm(marker);
387 // Set the feature coordinates in the form.
390 function coordsSetForm(marker)
392 var lonlat = new OpenLayers.LonLat(markers[marker].geometry.x, markers[marker].geometry.y);
393 lonlat.transform(map.getProjectionObject(),epsg4326);
395 var lon=format5f(lonlat.lon);
396 var lat=format5f(lonlat.lat);
398 document.forms["form"].elements["lon" + marker].value=lon;
399 document.forms["form"].elements["lat" + marker].value=lat;
408 // Format a number in printf("%.5f") format.
411 function format5f(number)
413 var newnumber=Math.floor(number*100000+0.5);
416 if(newnumber>=0 && newnumber<100000) delta= 100000;
417 if(newnumber<0 && newnumber>-100000) delta=-100000;
419 var string=String(newnumber+delta);
421 var intpart =string.substring(0,string.length-5);
422 var fracpart=string.substring(string.length-5,string.length);
424 if(delta>0) intpart="0";
425 if(delta<0) intpart="-0";
427 return(intpart + "." + fracpart);
432 // Build a set of URL arguments
435 function buildURLArguments(all)
439 url=url + "transport=" + routino.transport;
441 for(var marker=1;marker<=vismarkers;marker++)
442 if(markers[marker].style.display == "" || all)
444 url=url + ";lon" + marker + "=" + document.forms["form"].elements["lon" + marker].value;
445 url=url + ";lat" + marker + "=" + document.forms["form"].elements["lat" + marker].value;
448 for(var key in routino.profile_highway)
449 if(routino.profile_highway[key][routino.transport]!=routino_default.profile_highway[key][routino.transport])
450 url=url + ";highway-" + key + "=" + routino.profile_highway[key][routino.transport];
452 for(var key in routino.profile_speed)
453 if(routino.profile_speed[key][routino.transport]!=routino_default.profile_speed[key][routino.transport])
454 url=url + ";speed-" + key + "=" + routino.profile_speed[key][routino.transport];
456 for(var key in routino.profile_property)
457 if(routino.profile_property[key][routino.transport]!=routino_default.profile_property[key][routino.transport])
458 url=url + ";property-" + key + "=" + routino.profile_property[key][routino.transport];
460 for(var key in routino.restrictions)
461 if(routino.profile_restrictions[key][routino.transport]!=routino_default.profile_restrictions[key][routino.transport])
462 url=url + ";" + key + "=" + routino.profile_restrictions[key][routino.transport];
465 url=url + ";language=" + routino.language;
475 function updateCustomURL()
477 var visualiser_url=document.getElementById("visualiser_url");
478 var link_url =document.getElementById("link_url");
479 var edit_url =document.getElementById("edit_url");
481 visualiser_url.href="customvisualiser.cgi?" + map_args;
482 link_url.href="customrouter.cgi" + buildURLArguments(1) + ";" + map_args;
483 edit_url.href="http://www.openstreetmap.org/edit?" + map_args;
488 // Block the use of the return key to submit the form
491 function block_return_key()
493 var form=document.getElementById("form");
495 if(form.addEventListener)
496 form.addEventListener('keyup', discardReturnKey, false);
497 else if(form.attachEvent)
498 form.attachEvent('keyup', discardReturnKey); // Internet Explorer
502 // Function to discard the return key if pressed
505 function discardReturnKey(ev)
514 ////////////////////////////////////////////////////////////////////////////////
515 ///////////////////////////////// Map handling /////////////////////////////////
516 ////////////////////////////////////////////////////////////////////////////////
519 var layerMapOSM, layerVectors, layerGPX;
520 var epsg4326, epsg900913;
524 // Initialise the 'map' object
527 function map_init(lat,lon,zoom)
529 // Default configuration:
530 // UK coordinate range
531 // West -11.0, South 49.5, East 2.0, North 61.0
532 // Zoom level 4 to 15
534 // EDIT THIS below to change the visible map limits
536 var westedge = -11.0; // Minimum longitude (degrees)
537 var eastedge = 2.0; // Maximum longitude (degrees)
538 var southedge = 49.5; // Minimum latitude (degrees)
539 var northedge = 61.0; // Maximum latitude (degrees)
540 var zoomout = 4; // Minimum zoom
541 var zoomin = 15; // Maximum zoom
543 // EDIT THIS above to change the visible map limits
549 epsg4326=new OpenLayers.Projection("EPSG:4326");
550 epsg900913=new OpenLayers.Projection("EPSG:900913");
552 map = new OpenLayers.Map ("map",
555 new OpenLayers.Control.Navigation(),
556 new OpenLayers.Control.PanZoomBar(),
557 new OpenLayers.Control.ScaleLine(),
558 new OpenLayers.Control.LayerSwitcher()
561 projection: epsg900913,
562 displayProjection: epsg4326,
564 minZoomLevel: zoomout,
565 numZoomLevels: zoomin-zoomout+1,
566 maxResolution: 156543.0339 / Math.pow(2,zoomout),
568 maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
569 restrictedExtent: new OpenLayers.Bounds(westedge,southedge,eastedge,northedge).transform(epsg4326,epsg900913),
574 map.events.register("moveend", map, mapMoved);
576 // Add a map tile layer (OpenStreetMap tiles, direct access)
578 layerMapOSM = new OpenLayers.Layer.TMS("Original OSM map",
579 "http://tile.openstreetmap.org/",
581 emptyUrl: "http://openstreetmap.org/openlayers/img/404.png",
584 displayOutsideMaxExtent: true,
587 map.addLayer(layerMapOSM);
589 // Get a URL for the tile; limited to map restricted extent.
591 function limitedUrl(bounds)
593 var z = map.getZoom() + map.minZoomLevel;
595 if (z>=7 && (bounds.right < map.restrictedExtent.left ||
596 bounds.left > map.restrictedExtent.right ||
597 bounds.top < map.restrictedExtent.bottom ||
598 bounds.bottom > map.restrictedExtent.top))
599 return this.emptyUrl;
601 var res = map.getResolution();
602 var y = Math.round((this.maxExtent.top - bounds.top) / (res * this.tileSize.h));
603 var limit = Math.pow(2, z);
605 if (y < 0 || y >= limit)
606 return this.emptyUrl;
608 var x = Math.round((bounds.left - this.maxExtent.left) / (res * this.tileSize.w));
610 x = ((x % limit) + limit) % limit;
611 return this.url + z + "/" + x + "/" + y + "." + this.type;
614 // Define a GPX layer but don't add it yet
616 layerGPX={shortest: null, quickest: null};
618 gpx_style={shortest: new OpenLayers.Style({},{strokeWidth: 3, strokeColor: "#00FF00"}),
619 quickest: new OpenLayers.Style({},{strokeWidth: 3, strokeColor: "#0000FF"})};
621 // Add a vectors layer
623 layerVectors = new OpenLayers.Layer.Vector("Markers");
624 map.addLayer(layerVectors);
634 for(var marker=1;marker<=nmarkers;marker++)
636 if(document.forms["form"].elements["lon" + marker] != undefined)
638 markers[marker] = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0),{},
639 new OpenLayers.Style({},{externalGraphic: 'icons/marker-' + marker + '-red.png',
646 layerVectors.addFeatures([markers[marker]]);
656 // A function to drag the markers
658 var drag = new OpenLayers.Control.DragFeature(layerVectors,
660 onComplete: dragComplete });
661 map.addControl(drag);
664 // Markers to highlight a selected point
666 for(var highlight in highlights)
668 highlights[highlight] = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0),{},
669 new OpenLayers.Style({},{strokeColor: route_dark_colours[highlight],
676 layerVectors.addFeatures([highlights[highlight]]);
679 // A popup for routing results
681 for(var popup in popups)
682 popups[popup] = createPopup(popup);
684 // Set the map centre to the limited range specified
686 map.setCenter(map.restrictedExtent.getCenterLonLat(), map.getZoomForExtent(map.restrictedExtent,true));
687 map.maxResolution = map.getResolution();
691 if(lon != 'lon' && lat != 'lat' && zoom != 'zoom')
693 var lonlat = new OpenLayers.LonLat(lon,lat).transform(epsg4326,map.getProjectionObject());
695 map.moveTo(lonlat,zoom-map.minZoomLevel);
706 var centre = map.getCenter().clone();
708 var lonlat = centre.transform(map.getProjectionObject(),epsg4326);
710 var zoom = this.getZoom() + map.minZoomLevel;
712 map_args="lat=" + lonlat.lat + ";lon=" + lonlat.lon + ";zoom=" + zoom;
719 // OpenLayers.Control.DragFeature callback for a drag occuring.
722 function dragMove(feature,pixel)
724 for(var marker in markers)
725 if(feature==markers[marker])
729 coordsSetForm(marker);
735 // OpenLayers.Control.DragFeature callback for completing a drag.
738 function dragComplete(feature,pixel)
740 for(var marker in markers)
741 if(feature==markers[marker])
745 coordsSetForm(marker);
750 ////////////////////////////////////////////////////////////////////////////////
751 /////////////////////////////// Marker handling ////////////////////////////////
752 ////////////////////////////////////////////////////////////////////////////////
754 var nmarkers, vismarkers, markers, markersmoved, paramschanged;
755 var homelat=null, homelon=null;
759 // Toggle a marker on the map.
762 function markerToggleMap(marker)
764 if(markers[marker].style.display == "")
765 markerRemoveMap(marker);
767 markerAddMap(marker);
772 // Show a marker on the map.
775 function markerAddMap(marker)
777 markers[marker].style.display = "";
779 formSetCoords(marker);
788 // Remove a marker from the map.
791 function markerRemoveMap(marker)
793 markers[marker].style.display = "none";
802 // Centre the marker on the map
805 function markerCentre(marker)
807 document.forms["form"].elements["lon" + marker].value="";
808 document.forms["form"].elements["lat" + marker].value="";
810 formSetCoords(marker);
817 // Clear the current marker.
820 function markerRemove(marker)
822 for(var marker2=marker;marker2<vismarkers;marker2++)
824 document.forms["form"].elements["lon" + marker2].value=document.forms["form"].elements["lon" + (marker2+1)].value;
825 document.forms["form"].elements["lat" + marker2].value=document.forms["form"].elements["lat" + (marker2+1)].value;
827 if(markers[marker2+1].style.display=="")
828 markerAddMap(marker2);
830 markerRemoveMap(marker2);
833 markerRemoveMap(vismarkers);
835 var marker_tr=document.getElementById("point" + vismarkers);
837 marker_tr.style.display="none";
849 // Add a marker before the current one.
852 function markerAddBefore(marker)
854 if(vismarkers==nmarkers || marker==1)
859 var marker_tr=document.getElementById("point" + vismarkers);
861 marker_tr.style.display="";
863 for(var marker2=vismarkers;marker2>marker;marker2--)
865 document.forms["form"].elements["lon" + marker2].value=document.forms["form"].elements["lon" + (marker2-1)].value;
866 document.forms["form"].elements["lat" + marker2].value=document.forms["form"].elements["lat" + (marker2-1)].value;
868 if(markers[marker2-1].style.display=="")
869 markerAddMap(marker2);
871 markerRemoveMap(marker2);
874 document.forms["form"].elements["lon" + marker].value="";
875 document.forms["form"].elements["lat" + marker].value="";
876 markers[marker].style.display="none";
878 markerRemoveMap(marker);
885 // Add a marker after the current one.
888 function markerAddAfter(marker)
890 if(vismarkers==nmarkers)
895 var marker_tr=document.getElementById("point" + vismarkers);
897 marker_tr.style.display="";
899 for(var marker2=vismarkers;marker2>(marker+1);marker2--)
901 document.forms["form"].elements["lon" + marker2].value=document.forms["form"].elements["lon" + (marker2-1)].value;
902 document.forms["form"].elements["lat" + marker2].value=document.forms["form"].elements["lat" + (marker2-1)].value;
904 if(markers[marker2-1].style.display=="")
905 markerAddMap(marker2);
907 markerRemoveMap(marker2);
910 document.forms["form"].elements["lon" + (marker+1)].value="";
911 document.forms["form"].elements["lat" + (marker+1)].value="";
912 markers[marker+1].style.display="none";
914 markerRemoveMap(marker+1);
921 // Set this marker as the home location.
924 function markerHome(marker)
926 if(markerHomeCookie(marker))
927 for(marker=1;marker<=nmarkers;marker++)
933 // Update an icon to set colours and home or normal marker.
936 function updateIcon(marker)
938 var lon=document.forms["form"].elements["lon" + marker].value;
939 var lat=document.forms["form"].elements["lat" + marker].value;
941 if(lon==homelon && lat==homelat)
943 if(markers[marker].style.display=="")
944 document.images["waypoint" + marker].src="icons/marker-home-red.png";
946 document.images["waypoint" + marker].src="icons/marker-home-grey.png";
948 markers[marker].style.externalGraphic="icons/marker-home-red.png";
952 if(markers[marker].style.display=="")
953 document.images["waypoint" + marker].src="icons/marker-" + marker + "-red.png";
955 document.images["waypoint" + marker].src="icons/marker-" + marker + "-grey.png";
957 markers[marker].style.externalGraphic="icons/marker-" + marker + "-red.png";
960 layerVectors.drawFeature(markers[marker]);
965 // Set or clear the home marker icon
968 function markerHomeCookie(marker)
970 var lon=document.forms["form"].elements["lon" + marker].value;
971 var lat=document.forms["form"].elements["lat" + marker].value;
973 if(lon=="" || lat=="")
977 var date = new Date();
979 if((homelat==null && homelon==null) ||
980 (homelat!=lat && homelon!=lon))
982 cookie="Routino-home=lon:" + lon + ":lat:" + lat;
984 date.setUTCFullYear(date.getUTCFullYear()+5);
991 cookie="Routino-home=unset";
993 date.setUTCFullYear(date.getUTCFullYear()-1);
999 document.cookie=cookie + ";expires=" + date.toGMTString();
1006 // Move this marker up.
1009 function markerMoveUp(marker)
1014 markerSwap(marker,marker-1);
1019 // Move this marker down.
1022 function markerMoveDown(marker)
1024 if(marker==vismarkers)
1027 markerSwap(marker,marker+1);
1032 // Swap a pair of markers.
1035 function markerSwap(marker1,marker2)
1037 var lon=document.forms["form"].elements["lon" + marker1].value;
1038 var lat=document.forms["form"].elements["lat" + marker1].value;
1039 var display=markers[marker1].style.display;
1041 document.forms["form"].elements["lon" + marker1].value=document.forms["form"].elements["lon" + marker2].value;
1042 document.forms["form"].elements["lat" + marker1].value=document.forms["form"].elements["lat" + marker2].value;
1043 if(markers[marker2].style.display=="")
1044 markerAddMap(marker1);
1046 markerRemoveMap(marker1);
1048 document.forms["form"].elements["lon" + marker2].value=lon;
1049 document.forms["form"].elements["lat" + marker2].value=lat;
1051 markerAddMap(marker2);
1053 markerRemoveMap(marker2);
1060 // Reverse the markers.
1063 function markersReverse()
1065 for(var marker=1;marker<=vismarkers/2;marker++)
1066 markerSwap(marker,vismarkers+1-marker);
1072 ////////////////////////////////////////////////////////////////////////////////
1073 //////////////////////////// Route results handling ////////////////////////////
1074 ////////////////////////////////////////////////////////////////////////////////
1076 var route_light_colours={shortest: "#60C060", quickest: "#6060C0"};
1077 var route_dark_colours ={shortest: "#408040", quickest: "#404080"};
1079 var highlights={shortest: null, quickest: null};
1080 var popups={shortest: null, quickest: null};
1081 var routepoints={shortest: {}, quickest: {}};
1082 var gpx_style={shortest: null, quickest: null};
1085 // Zoom to a specific item in the route
1088 function zoomTo(type,line)
1090 var lonlat = new OpenLayers.LonLat(routepoints[type][line].lon,routepoints[type][line].lat).transform(epsg4326,map.getProjectionObject());
1092 map.moveTo(lonlat,map.numZoomLevels-2);
1097 // Highlight a specific item in the route
1100 function highlight(type,line)
1104 highlights[type].style.display = "none";
1106 drawPopup(popups[type],null);
1112 var lonlat = new OpenLayers.LonLat(routepoints[type][line].lon,routepoints[type][line].lat).transform(epsg4326,map.getProjectionObject());
1114 highlights[type].move(lonlat);
1116 if(highlights[type].style.display = "none")
1117 highlights[type].style.display = "";
1121 drawPopup(popups[type],"<table>" + routepoints[type][line].html + "</table>");
1124 layerVectors.drawFeature(highlights[type]);
1129 // Create a popup - not using OpenLayers because want it fixed on screen not fixed on map.
1132 function createPopup(type)
1134 var popup=document.createElement('div');
1136 popup.className = "popup";
1138 popup.innerHTML = "<span></span>";
1140 popup.style.display = "none";
1142 popup.style.position = "fixed";
1143 popup.style.top = "-4000px";
1144 popup.style.left = "-4000px";
1145 popup.style.zIndex = "100";
1147 popup.style.padding = "5px";
1149 popup.style.opacity=0.85;
1150 popup.style.backgroundColor=route_light_colours[type];
1151 popup.style.border="4px solid " + route_dark_colours[type];
1153 document.body.appendChild(popup);
1160 // Draw a popup - not using OpenLayers because want it fixed on screen not fixed on map.
1163 function drawPopup(popup,html)
1167 popup.style.display="none";
1171 if(popup.style.display=="none")
1173 var map_div=document.getElementById("map");
1175 popup.style.left =map_div.offsetParent.offsetLeft+map_div.offsetLeft+60 + "px";
1176 popup.style.top = map_div.offsetTop +30 + "px";
1177 popup.style.width =map_div.clientWidth-100 + "px";
1179 popup.style.display="";
1182 popup.innerHTML=html;
1187 // Remove a GPX trace
1190 function removeGPXTrace(type)
1192 map.removeLayer(layerGPX[type]);
1193 layerGPX[type].destroy();
1194 layerGPX[type]=null;
1196 displayStatus(type,"no_info");
1198 var div_links=document.getElementById(type + "_links");
1199 div_links.style.display = "none";
1201 var div_route=document.getElementById(type + "_route");
1202 div_route.innerHTML = "";
1204 hideshow_hide(type);
1208 ////////////////////////////////////////////////////////////////////////////////
1209 /////////////////////////////// Server handling ////////////////////////////////
1210 ////////////////////////////////////////////////////////////////////////////////
1213 // Display data statistics
1216 function displayStatistics()
1218 // Use AJAX to get the statistics
1220 OpenLayers.loadURL("statistics.cgi",null,null,runStatisticsSuccess);
1225 // Success in running data statistics generation.
1228 function runStatisticsSuccess(response)
1230 var statistics_data=document.getElementById("statistics_data");
1231 var statistics_link=document.getElementById("statistics_link");
1233 statistics_data.innerHTML="<pre>" + response.responseText + "</pre>";
1235 statistics_link.style.display="none";
1240 // Submit form - perform the routing
1243 function findRoute(type)
1245 tab_select("results");
1247 hideshow_hide('help_options');
1248 hideshow_hide('shortest');
1249 hideshow_hide('quickest');
1251 displayStatus("result","running");
1253 var url="router.cgi" + buildURLArguments(0) + ";type=" + type;
1255 // Destroy the existing layer(s)
1257 if(markersmoved || paramschanged)
1259 if(layerGPX.shortest!=null)
1260 removeGPXTrace("shortest");
1261 if(layerGPX.quickest!=null)
1262 removeGPXTrace("quickest");
1264 paramschanged=false;
1266 else if(layerGPX[type]!=null)
1267 removeGPXTrace(type);
1269 // Use AJAX to run the router
1273 OpenLayers.loadURL(url,null,null,runRouterSuccess,runRouterFailure);
1278 // Success in running router.
1281 function runRouterSuccess(response)
1283 var lines=response.responseText.split('\n');
1286 var cpuinfo=lines[1];
1287 var distinfo=lines[2];
1288 var message=lines[3];
1290 // Update the status message
1294 displayStatus("result","error");
1295 hideshow_show('help_route');
1300 displayStatus("result","complete");
1301 hideshow_hide('help_route');
1304 // Update the routing result message
1306 displayStatus(routing_type,"info",distinfo.bold());
1310 link=document.getElementById(routing_type + "_html");
1311 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=html";
1312 link=document.getElementById(routing_type + "_gpx_track");
1313 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-track";
1314 link=document.getElementById(routing_type + "_gpx_route");
1315 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-route";
1316 link=document.getElementById(routing_type + "_text_all");
1317 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=text-all";
1318 link=document.getElementById(routing_type + "_text");
1319 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=text";
1321 var div_links=document.getElementById(routing_type + "_links");
1322 div_links.style.display = "";
1326 var url="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-track";
1328 layerGPX[routing_type] = new OpenLayers.Layer.GML("GPX (" + routing_type + ")", url,
1330 format: OpenLayers.Format.GPX,
1331 style: gpx_style[routing_type],
1332 projection: map.displayProjection
1335 map.addLayer(layerGPX[routing_type]);
1337 hideshow_show(routing_type);
1339 displayResult(routing_type,uuid);
1344 // Failure in running router.
1347 function runRouterFailure(response)
1349 displayStatus("result","failed");
1354 // Display the status
1357 function displayStatus(type,subtype,content)
1359 var div_status=document.getElementById(type + "_status");
1361 var child=div_status.firstChild;
1365 if(child.id != undefined)
1366 child.style.display="none";
1368 child=child.nextSibling;
1370 while(child != undefined);
1372 var span_status=document.getElementById(type + "_status_" + subtype);
1374 span_status.style.display="";
1377 span_status.innerHTML=content;
1382 // Display the route
1385 function displayResult(type,uuid)
1387 routing_type = type;
1391 var url="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=html";
1393 // Use AJAX to get the route
1395 OpenLayers.loadURL(url,null,null,getRouteSuccess,getRouteFailure);
1400 // Success in getting route.
1403 function getRouteSuccess(response)
1405 var lines=response.responseText.split('\n');
1406 var div_route=document.getElementById(routing_type + "_route");
1408 routepoints[routing_type]=[];
1410 var points=routepoints[routing_type];
1414 var total_table,total_word;
1416 for(var line=0;line<lines.length;line++)
1418 var thisline=lines[line];
1422 if(thisline.match('<table>'))
1428 if(thisline.match('</table>'))
1431 if(thisline.match('<tr class=\'([a-z])\'>'))
1433 var rowtype=RegExp.$1;
1437 thisline.match('<td class=\'r\'> *([-0-9.]+) *([-0-9.]+)');
1438 points[point]={lat: Number(RegExp.$1), lon: Number(RegExp.$2), html: "", highway: "", distance: "", total: ""};
1442 else if(rowtype=='n')
1444 points[point-1].html += thisline;
1446 else if(rowtype=='s')
1448 thisline.match('<span class=\'h\'>([^<]+)</span>');
1449 points[point-1].highway = RegExp.$1;
1451 thisline.match('<span class=\'d\'>([^<]+)</span>');
1452 points[point-1].distance = RegExp.$1;
1454 thisline.match('(<span class=\'j\'>[^<]+</span>)');
1455 points[point-1].total = RegExp.$1;
1457 thisline.match('^(.*).<span class=\'j\'>');
1459 points[point-1].html += RegExp.$1;
1461 else if(rowtype=='t')
1463 points[point-1].html += thisline;
1465 thisline.match('^(.*<td class=\'r\'>)');
1466 total_table = RegExp.$1;
1468 thisline.match('<td class=\'l\'>([^<]+)<');
1469 total_word = RegExp.$1;
1471 thisline.match('<span class=\'j\'>([^<]+)</span>');
1472 points[point-1].total = RegExp.$1;
1477 var result="<table onmouseout='highlight(\"" + routing_type + "\",-1)'>";
1479 for(var p=0;p<point-1;p++)
1481 points[p].html += total_table + points[p].total;
1483 result=result + "<tr onclick='zoomTo(\"" + routing_type + "\"," + p + ")'" +
1484 " onmouseover='highlight(\"" + routing_type + "\"," + p + ")'>" +
1485 "<td class='distance' title='" + points[p].distance + "'>#" + (p+1) +
1486 "<td class='highway'>" + points[p].highway;
1489 result=result + "<tr onclick='zoomTo(\"" + routing_type + "\"," + p + ")'" +
1490 " onmouseover='highlight(\"" + routing_type + "\"," + p + ")'>" +
1491 "<td colspan='2'>" + total_word + " " + points[p].total;
1493 result=result + "</table>";
1495 div_route.innerHTML=result;
1500 // Failure in getting route.
1503 function getRouteFailure(response)
1505 var div_route=document.getElementById(routing_type + "_route");
1506 div_route.innerHTML = "";