Routino SVN Repository Browser

Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino

ViewVC logotype

Contents of /trunk/web/www/routino/router.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1001 - (show annotations) (download) (as text)
Tue Jun 5 08:17:57 2012 UTC (12 years, 9 months ago) by amb
File MIME type: application/javascript
File size: 40963 byte(s)
Add a button to replace the lat/long text entry with a location search entry.
Use Nominatim service via CGI to get first search result and fill in coords.

1 //
2 // Routino router web page Javascript
3 //
4 // Part of the Routino routing software.
5 //
6 // This file Copyright 2008-2012 Andrew M. Bishop
7 //
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.
12 //
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.
17 //
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/>.
20 //
21
22 // The number of waypoints to include in the HTML
23 var maxmarkers=9;
24
25 var vismarkers, markers, markersmoved, paramschanged;
26 var homelat=null, homelon=null;
27
28
29 ////////////////////////////////////////////////////////////////////////////////
30 /////////////////////////////// Initialisation /////////////////////////////////
31 ////////////////////////////////////////////////////////////////////////////////
32
33 // Make a deep copy of the routino profile.
34
35 var routino_default={};
36 for(var l1 in routino)
37 if(typeof(routino[l1])!='object')
38 routino_default[l1]=routino[l1];
39 else
40 {
41 routino_default[l1]={};
42 for(var l2 in routino[l1])
43 if(typeof(routino[l1][l2])!='object')
44 routino_default[l1][l2]=Number(routino[l1][l2]);
45 else
46 {
47 routino_default[l1][l2]={};
48 for(var l3 in routino[l1][l2])
49 routino_default[l1][l2][l3]=Number(routino[l1][l2][l3]);
50 }
51 }
52
53 // Store the latitude and longitude in the routino variable
54
55 routino.point=[];
56 for(var marker=1;marker<=maxmarkers;marker++)
57 {
58 routino.point[marker]={};
59
60 routino.point[marker].lon="";
61 routino.point[marker].lat="";
62 routino.point[marker].search="";
63 routino.point[marker].active=false;
64 }
65
66 // Process the URL query string and extract the arguments
67
68 var legal={"^lon" : "^[-0-9.]+$",
69 "^lat" : "^[-0-9.]+$",
70 "^zoom" : "^[0-9]+$",
71
72 "^lon[1-9]" : "^[-0-9.]+$",
73 "^lat[1-9]" : "^[-0-9.]+$",
74 "^search[1-9]" : "^.+$",
75 "^transport" : "^[a-z]+$",
76 "^highway-[a-z]+" : "^[0-9.]+$",
77 "^speed-[a-z]+" : "^[0-9.]+$",
78 "^property-[a-z]+" : "^[0-9.]+$",
79 "^oneway" : "^(1|0|true|false|on|off)$",
80 "^turns" : "^(1|0|true|false|on|off)$",
81 "^weight" : "^[0-9.]+$",
82 "^height" : "^[0-9.]+$",
83 "^width" : "^[0-9.]+$",
84 "^length" : "^[0-9.]+$",
85
86 "^language" : "^[-a-zA-Z]+$"};
87
88 var args={};
89
90 if(location.search.length>1)
91 {
92 var query,queries;
93
94 query=location.search.replace(/^\?/,"");
95 query=query.replace(/;/g,'&');
96 queries=query.split('&');
97
98 for(var i=0;i<queries.length;i++)
99 {
100 queries[i].match(/^([^=]+)(=(.*))?$/);
101
102 k=RegExp.$1;
103 v=unescape(RegExp.$3);
104
105 for(var l in legal)
106 {
107 if(k.match(RegExp(l)) && v.match(RegExp(legal[l])))
108 args[k]=v;
109 }
110 }
111 }
112
113
114 //
115 // Fill in the HTML - add the missing waypoints
116 //
117
118 function html_init()
119 {
120 var waypoints=document.getElementById("waypoints");
121 var waypoint_html=waypoints.rows[0].innerHTML;
122
123 waypoints.deleteRow(0);
124
125 for(var marker=maxmarkers;marker>=1;marker--)
126 {
127 waypoint=waypoints.insertRow(0);
128 waypoint.id="point" + marker;
129
130 var this_waypoint_html=waypoint_html.split('XXX').join(marker);
131
132 waypoint.innerHTML=this_waypoint_html;
133 }
134
135 vismarkers=maxmarkers;
136 }
137
138
139 ////////////////////////////////////////////////////////////////////////////////
140 //////////////////////////////// Form handling /////////////////////////////////
141 ////////////////////////////////////////////////////////////////////////////////
142
143 //
144 // Form initialisation - fill in the uninitialised parts
145 //
146
147 function form_init()
148 {
149 // Fill in the waypoints
150
151 var filled=0;
152
153 for(var marker=maxmarkers;marker>=1;marker--)
154 {
155 var lon=args["lon" + marker];
156 var lat=args["lat" + marker];
157 var search=args["search" + marker];
158
159 if(lon != undefined && lat != undefined && search != undefined && lon != "" && lat != "" && search != "")
160 {
161 formSetSearch(marker,search);
162 formSetCoords(marker,lon,lat,true);
163
164 markerSearch(marker);
165
166 filled++;
167 }
168 else if(lon != undefined && lat != undefined && lon != "" && lat != "")
169 {
170 formSetCoords(marker,lon,lat,true);
171
172 markerCoords(marker);
173
174 filled++;
175 }
176 else if(search != undefined && search != "")
177 {
178 formSetSearch(marker,search);
179
180 markerSearch(marker);
181
182 DoSearch(marker);
183
184 filled++;
185 }
186 else if(filled==0)
187 markerRemove(marker);
188 }
189
190 // Update the transport type with the URL settings which updates all HTML forms to defaults.
191
192 var transport=routino.transport;
193
194 if(args["transport"] != undefined)
195 transport=args["transport"];
196
197 formSetTransport(transport);
198
199 // Update the HTML with the URL settings
200
201 if(args["language"] != undefined)
202 formSetLanguage(args["language"]);
203
204 for(var key in routino.profile_highway)
205 if(args["highway-" + key] != undefined)
206 formSetHighway(key,args["highway-" + key]);
207
208 for(var key in routino.profile_speed)
209 if(args["speed-" + key] != undefined)
210 formSetSpeed(key,args["speed-" + key]);
211
212 for(var key in routino.profile_property)
213 if(args["property-" + key] != undefined)
214 formSetProperty(key,args["property-" + key]);
215
216 for(var key in routino.restrictions)
217 {
218 if(key=="oneway" || key=="turns")
219 {
220 if(args[key] != undefined)
221 formSetRestriction(key,args[key]);
222 }
223 else
224 {
225 if(args["restrict-" + key] != undefined)
226 formSetRestriction(key,args["restrict-" + key]);
227 }
228 }
229
230 // Get the home location cookie and compare to each waypoint
231
232 var cookies=document.cookie.split('; ');
233
234 for(var cookie=0;cookie<cookies.length;cookie++)
235 if(cookies[cookie].substr(0,"Routino-home".length)=="Routino-home")
236 {
237 var data=cookies[cookie].split(/[=:;]/);
238
239 if(data[1]=="lon") homelon=Number(data[2]);
240 if(data[3]=="lat") homelat=Number(data[4]);
241 }
242
243 if(homelon!=null && homelat!=null)
244 {
245 for(var marker=maxmarkers;marker>=1;marker--)
246 {
247 var lon=routino.point[marker].lon;
248 var lat=routino.point[marker].lat;
249
250 if(lon==homelon && lat==homelat)
251 updateIcon(marker);
252 }
253
254 // If the first location is empty and the cookie is set then fill it.
255
256 if(routino.point[1].lon=="" && routino.point[1].lat=="")
257 formSetCoords(1,homelon,homelat,true);
258 }
259 }
260
261
262 //
263 // Change of language in the form
264 //
265
266 function formSetLanguage(value)
267 {
268 if(value == undefined)
269 {
270 for(var lang=0;lang<document.forms["form"].elements["language"].length;lang++)
271 if(document.forms["form"].elements["language"][lang].checked)
272 routino.language=document.forms["form"].elements["language"][lang].value;
273 }
274 else
275 {
276 for(var lang=0;lang<document.forms["form"].elements["language"].length;lang++)
277 if(document.forms["form"].elements["language"][lang].value==value)
278 document.forms["form"].elements["language"][lang].checked=true;
279 else
280 document.forms["form"].elements["language"][lang].checked=false;
281
282 routino.language=value;
283 }
284 }
285
286
287 //
288 // Change of transport in the form
289 //
290
291 function formSetTransport(value)
292 {
293 routino.transport=value;
294
295 for(var key in routino.transports)
296 document.forms["form"].elements["transport"][routino.transports[key]-1].checked=(key==routino.transport);
297
298 for(var key in routino.profile_highway)
299 document.forms["form"].elements["highway-" + key].value=routino.profile_highway[key][routino.transport];
300
301 for(var key in routino.profile_speed)
302 document.forms["form"].elements["speed-" + key].value=routino.profile_speed[key][routino.transport];
303
304 for(var key in routino.profile_property)
305 document.forms["form"].elements["property-" + key].value=routino.profile_property[key][routino.transport];
306
307 for(var key in routino.restrictions)
308 {
309 if(key=="oneway" || key=="turns")
310 document.forms["form"].elements["restrict-" + key].checked=routino.profile_restrictions[key][routino.transport];
311 else
312 document.forms["form"].elements["restrict-" + key].value=routino.profile_restrictions[key][routino.transport];
313 }
314
315 paramschanged=true;
316 }
317
318
319 //
320 // Change of highway in the form
321 //
322
323 function formSetHighway(type,value)
324 {
325 if(value == undefined)
326 routino.profile_highway[type][routino.transport]=document.forms["form"].elements["highway-" + type].value;
327 else
328 {
329 document.forms["form"].elements["highway-" + type].value=value;
330 routino.profile_highway[type][routino.transport]=value;
331 }
332
333 paramschanged=true;
334 }
335
336
337 //
338 // Change of Speed in the form
339 //
340
341 function formSetSpeed(type,value)
342 {
343 if(value == undefined)
344 routino.profile_speed[type][routino.transport]=document.forms["form"].elements["speed-" + type].value;
345 else
346 {
347 document.forms["form"].elements["speed-" + type].value=value;
348 routino.profile_speed[type][routino.transport]=value;
349 }
350
351 paramschanged=true;
352 }
353
354
355 //
356 // Change of Property in the form
357 //
358
359 function formSetProperty(type,value)
360 {
361 if(value == undefined)
362 routino.profile_property[type][routino.transport]=document.forms["form"].elements["property-" + type].value;
363 else
364 {
365 document.forms["form"].elements["property-" + type].value=value;
366 routino.profile_property[type][routino.transport]=value;
367 }
368
369 paramschanged=true;
370 }
371
372
373 //
374 // Change of Restriction rule in the form
375 //
376
377 function formSetRestriction(type,value)
378 {
379 if(value == undefined)
380 {
381 if(type=="oneway" || type=="turns")
382 routino.profile_restrictions[type][routino.transport]=document.forms["form"].elements["restrict-" + type].checked;
383 else
384 routino.profile_restrictions[type][routino.transport]=document.forms["form"].elements["restrict-" + type].value;
385 }
386 else
387 {
388 if(type=="oneway" || type=="turns")
389 document.forms["form"].elements["restrict-" + type].checked=value;
390 else
391 document.forms["form"].elements["restrict-" + type].value=value;
392
393 routino.profile_restrictions[type][routino.transport]=value;
394 }
395
396 paramschanged=true;
397 }
398
399
400 //
401 // Set the feature coordinates from the form when the form changes.
402 //
403
404 function formSetCoords(marker,lon,lat,active)
405 {
406 if(lon == undefined || lat == undefined)
407 {
408 routino.point[marker].lon=document.forms["form"].elements["lon" + marker].value;
409 routino.point[marker].lat=document.forms["form"].elements["lat" + marker].value;
410
411 if(routino.point[marker].lon=="" || routino.point[marker].lat=="")
412 markerCentre(marker);
413 }
414 else
415 {
416 document.forms["form"].elements["lon" + marker].value=format5f(lon);
417 document.forms["form"].elements["lat" + marker].value=format5f(lat);
418
419 routino.point[marker].lon=lon;
420 routino.point[marker].lat=lat;
421
422 if(active != undefined)
423 {
424 if(active)
425 markerAddMap(marker);
426 else
427 markerRemoveMap(marker);
428 }
429 }
430
431 var lonlat=map.getCenter().clone();
432
433 lonlat.transform(map.getProjectionObject(),epsg4326);
434
435 if(routino.point[marker].lon!="")
436 {
437 if(routino.point[marker].lon<-180) routino.point[marker].lon=-180;
438 if(routino.point[marker].lon>+180) routino.point[marker].lon=+180;
439 lonlat.lon=routino.point[marker].lon;
440 }
441
442 if(routino.point[marker].lat!="")
443 {
444 if(routino.point[marker].lat<-90 ) routino.point[marker].lat=-90 ;
445 if(routino.point[marker].lat>+90 ) routino.point[marker].lat=+90 ;
446 lonlat.lat=routino.point[marker].lat;
447 }
448
449 var point = lonlat.clone();
450
451 point.transform(epsg4326,map.getProjectionObject());
452
453 markers[marker].move(point);
454
455 markersmoved=true;
456 }
457
458
459 //
460 // Set the feature coordinates from the form when the form changes.
461 //
462
463 function formSetSearch(marker,search)
464 {
465 if(search == undefined)
466 {
467 routino.point[marker].search=document.forms["form"].elements["search" + marker].value;
468
469 DoSearch(marker);
470 }
471 else
472 {
473 document.forms["form"].elements["search" + marker].value=search;
474
475 routino.point[marker].search=search;
476 }
477 }
478
479
480 //
481 // Format a number in printf("%.5f") format.
482 //
483
484 function format5f(number)
485 {
486 var newnumber=Math.floor(number*100000+0.5);
487 var delta=0;
488
489 if(newnumber>=0 && newnumber<100000) delta= 100000;
490 if(newnumber<0 && newnumber>-100000) delta=-100000;
491
492 var string=String(newnumber+delta);
493
494 var intpart =string.substring(0,string.length-5);
495 var fracpart=string.substring(string.length-5,string.length);
496
497 if(delta>0) intpart="0";
498 if(delta<0) intpart="-0";
499
500 return(intpart + "." + fracpart);
501 }
502
503
504 //
505 // Build a set of URL arguments
506 //
507
508 function buildURLArguments(lang)
509 {
510 var url= "transport=" + routino.transport;
511
512 for(var marker=1;marker<=vismarkers;marker++)
513 if(routino.point[marker].active)
514 {
515 url=url + ";lon" + marker + "=" + routino.point[marker].lon;
516 url=url + ";lat" + marker + "=" + routino.point[marker].lat;
517 if(routino.point[marker].search != "")
518 url=url + ";search" + marker + "=" + encodeURIComponent(routino.point[marker].search);
519 }
520
521 for(var key in routino.profile_highway)
522 if(routino.profile_highway[key][routino.transport]!=routino_default.profile_highway[key][routino.transport])
523 url=url + ";highway-" + key + "=" + routino.profile_highway[key][routino.transport];
524
525 for(var key in routino.profile_speed)
526 if(routino.profile_speed[key][routino.transport]!=routino_default.profile_speed[key][routino.transport])
527 url=url + ";speed-" + key + "=" + routino.profile_speed[key][routino.transport];
528
529 for(var key in routino.profile_property)
530 if(routino.profile_property[key][routino.transport]!=routino_default.profile_property[key][routino.transport])
531 url=url + ";property-" + key + "=" + routino.profile_property[key][routino.transport];
532
533 for(var key in routino.restrictions)
534 if(routino.profile_restrictions[key][routino.transport]!=routino_default.profile_restrictions[key][routino.transport])
535 url=url + ";" + key + "=" + routino.profile_restrictions[key][routino.transport];
536
537 if(lang && routino.language)
538 url=url + ";language=" + routino.language;
539
540 return(url);
541 }
542
543
544 //
545 // Build a set of URL arguments for the map location
546 //
547
548 function buildMapArguments()
549 {
550 var centre = map.getCenter().clone();
551
552 var lonlat = centre.transform(map.getProjectionObject(),epsg4326);
553
554 var zoom = map.getZoom() + map.minZoomLevel;
555
556 return "lat=" + format5f(lonlat.lat) + ";lon=" + format5f(lonlat.lon) + ";zoom=" + zoom;
557 }
558
559
560 //
561 // Update a URL
562 //
563
564 function updateURL(element)
565 {
566 if(element.id == "permalink_url")
567 element.href=location.pathname + "?" + buildURLArguments(true) + ";" + buildMapArguments();
568
569 if(element.id == "visualiser_url")
570 element.href="visualiser.html" + "?" + buildMapArguments();
571
572 if(element.id == "edit_url")
573 element.href="http://www.openstreetmap.org/edit" + "?" + buildMapArguments();
574
575 if(element.id.match(/^lang_([a-zA-Z-]+)_url$/))
576 element.href="router.html" + "." + RegExp.$1 + "?" + buildURLArguments(false) + ";" + buildMapArguments();
577 }
578
579
580 //
581 // Block the use of the return key to submit the form
582 //
583
584 function block_return_key()
585 {
586 var form=document.getElementById("form");
587
588 if(form.addEventListener)
589 form.addEventListener('keyup', discardReturnKey, false);
590 else if(form.attachEvent)
591 form.attachEvent('keyup', discardReturnKey); // Internet Explorer
592 }
593
594 //
595 // Function to discard the return key if pressed
596 //
597
598 function discardReturnKey(ev)
599 {
600 if(ev.keyCode==13)
601 return(false);
602
603 return(true);
604 }
605
606
607 ////////////////////////////////////////////////////////////////////////////////
608 ///////////////////////////////// Map handling /////////////////////////////////
609 ////////////////////////////////////////////////////////////////////////////////
610
611 var map;
612 var layerMap=[], layerVectors, layerGPX;
613 var epsg4326, epsg900913;
614
615 //
616 // Initialise the 'map' object
617 //
618
619 function map_init()
620 {
621 lon =args["lon"];
622 lat =args["lat"];
623 zoom=args["zoom"];
624
625 // Map properties (North/South and East/West limits and zoom in/out limits) are now in mapprops.js
626 // Map URLs are now in mapprops.js
627
628 //
629 // Create the map
630 //
631
632 epsg4326=new OpenLayers.Projection("EPSG:4326");
633 epsg900913=new OpenLayers.Projection("EPSG:900913");
634
635 map = new OpenLayers.Map ("map",
636 {
637 controls:[
638 new OpenLayers.Control.Navigation(),
639 new OpenLayers.Control.PanZoomBar(),
640 new OpenLayers.Control.ScaleLine(),
641 new OpenLayers.Control.LayerSwitcher()
642 ],
643
644 projection: epsg900913,
645 displayProjection: epsg4326,
646
647 minZoomLevel: mapprops.zoomout,
648 numZoomLevels: mapprops.zoomin-mapprops.zoomout+1,
649 maxResolution: 156543.0339 / Math.pow(2,mapprops.zoomout),
650
651 maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
652 restrictedExtent: new OpenLayers.Bounds(mapprops.westedge,mapprops.southedge,mapprops.eastedge,mapprops.northedge).transform(epsg4326,epsg900913),
653
654 units: "m"
655 });
656
657 // Add map tile layers
658
659 for(var l=0;l < mapprops.mapdata.length;l++)
660 {
661 layerMap[l] = new OpenLayers.Layer.TMS(mapprops.mapdata[l].label,
662 mapprops.mapdata[l].baseurl,
663 {
664 emptyUrl: mapprops.mapdata[l].errorurl,
665 type: 'png',
666 getURL: limitedUrl,
667 displayOutsideMaxExtent: true,
668 buffer: 1
669 });
670 map.addLayer(layerMap[l]);
671 }
672
673 // Get a URL for the tile; limited to map restricted extent.
674
675 function limitedUrl(bounds)
676 {
677 var z = map.getZoom() + map.minZoomLevel;
678
679 if (z>=7 && (bounds.right < map.restrictedExtent.left ||
680 bounds.left > map.restrictedExtent.right ||
681 bounds.top < map.restrictedExtent.bottom ||
682 bounds.bottom > map.restrictedExtent.top))
683 return this.emptyUrl;
684
685 var res = map.getResolution();
686 var y = Math.round((this.maxExtent.top - bounds.top) / (res * this.tileSize.h));
687 var limit = Math.pow(2, z);
688
689 if (y < 0 || y >= limit)
690 return this.emptyUrl;
691
692 var x = Math.round((bounds.left - this.maxExtent.left) / (res * this.tileSize.w));
693
694 x = ((x % limit) + limit) % limit;
695 return this.url + z + "/" + x + "/" + y + "." + this.type;
696 }
697
698 // Define a GPX layer but don't add it yet
699
700 layerGPX={shortest: null, quickest: null};
701
702 gpx_style={shortest: new OpenLayers.Style({},{strokeWidth: 3, strokeColor: "#00FF00"}),
703 quickest: new OpenLayers.Style({},{strokeWidth: 3, strokeColor: "#0000FF"})};
704
705 // Add a vectors layer
706
707 layerVectors = new OpenLayers.Layer.Vector("Markers");
708 map.addLayer(layerVectors);
709
710 // A set of markers
711
712 markers={};
713 markersmoved=false;
714 paramschanged=false;
715
716 for(var marker=1;marker<=maxmarkers;marker++)
717 {
718 markers[marker] = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0),{},
719 new OpenLayers.Style({},{externalGraphic: 'icons/marker-' + marker + '-red.png',
720 fillColor: "white",
721 graphicYOffset: -25,
722 graphicWidth: 21,
723 graphicHeight: 25,
724 display: "none"}));
725
726 layerVectors.addFeatures([markers[marker]]);
727 }
728
729 // A function to drag the markers
730
731 var drag = new OpenLayers.Control.DragFeature(layerVectors,
732 {onDrag: dragMove,
733 onComplete: dragComplete });
734 map.addControl(drag);
735 drag.activate();
736
737 // Markers to highlight a selected point
738
739 for(var highlight in highlights)
740 {
741 highlights[highlight] = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0),{},
742 new OpenLayers.Style({},{strokeColor: route_dark_colours[highlight],
743 fillColor: "white",
744 pointRadius: 10,
745 strokeWidth: 4,
746 fillOpacity: 0,
747 display: "none"}));
748
749 layerVectors.addFeatures([highlights[highlight]]);
750 }
751
752 // A popup for routing results
753
754 for(var popup in popups)
755 popups[popup] = createPopup(popup);
756
757 // Set the map centre to the limited range specified
758
759 map.setCenter(map.restrictedExtent.getCenterLonLat(), map.getZoomForExtent(map.restrictedExtent,true));
760 map.maxResolution = map.getResolution();
761
762 // Move the map
763
764 if(lon != undefined && lat != undefined && zoom != undefined)
765 {
766 if(lon<mapprops.westedge) lon=mapprops.westedge;
767 if(lon>mapprops.eastedge) lon=mapprops.eastedge;
768
769 if(lat<mapprops.southedge) lat=mapprops.southedge;
770 if(lat>mapprops.northedge) lat=mapprops.northedge;
771
772 if(zoom<mapprops.zoomout) zoom=mapprops.zoomout;
773 if(zoom>mapprops.zoomin) zoom=mapprops.zoomin;
774
775 var lonlat = new OpenLayers.LonLat(lon,lat).transform(epsg4326,map.getProjectionObject());
776
777 map.moveTo(lonlat,zoom-map.minZoomLevel);
778 }
779 }
780
781
782 //
783 // OpenLayers.Control.DragFeature callback for a drag occuring.
784 //
785
786 function dragMove(feature,pixel)
787 {
788 for(var marker in markers)
789 if(feature==markers[marker])
790 {
791 markersmoved=true;
792
793 dragSetForm(marker);
794 }
795 }
796
797
798 //
799 // OpenLayers.Control.DragFeature callback for completing a drag.
800 //
801
802 function dragComplete(feature,pixel)
803 {
804 for(var marker in markers)
805 if(feature==markers[marker])
806 {
807 markersmoved=true;
808
809 dragSetForm(marker);
810 }
811 }
812
813
814 //
815 // Set the feature coordinates in the form after dragging.
816 //
817
818 function dragSetForm(marker)
819 {
820 var lonlat = new OpenLayers.LonLat(markers[marker].geometry.x, markers[marker].geometry.y);
821 lonlat.transform(map.getProjectionObject(),epsg4326);
822
823 var lon=format5f(lonlat.lon);
824 var lat=format5f(lonlat.lat);
825
826 formSetCoords(marker,lon,lat);
827 }
828
829
830 ////////////////////////////////////////////////////////////////////////////////
831 /////////////////////////////// Marker handling ////////////////////////////////
832 ////////////////////////////////////////////////////////////////////////////////
833
834
835 //
836 // Toggle a marker on the map.
837 //
838
839 function markerToggleMap(marker)
840 {
841 if(routino.point[marker].active)
842 markerRemoveMap(marker);
843 else
844 markerAddMap(marker);
845 }
846
847
848 //
849 // Show a marker on the map.
850 //
851
852 function markerAddMap(marker)
853 {
854 markers[marker].style.display = "";
855 routino.point[marker].active=true;
856
857 updateIcon(marker);
858
859 markersmoved=true;
860 }
861
862
863 //
864 // Remove a marker from the map.
865 //
866
867 function markerRemoveMap(marker)
868 {
869 markers[marker].style.display = "none";
870 routino.point[marker].active=false;
871
872 updateIcon(marker);
873
874 markersmoved=true;
875 }
876
877
878 //
879 // Display search string for the marker
880 //
881
882 function markerSearch(marker)
883 {
884 var search_span=document.getElementById("search" + marker);
885 var coords_span=document.getElementById("coords" + marker);
886
887 search_span.style.display="";
888 coords_span.style.display="none";
889 }
890
891
892 //
893 // Display coordinates for the marker
894 //
895
896 function markerCoords(marker)
897 {
898 var search_span=document.getElementById("search" + marker);
899 var coords_span=document.getElementById("coords" + marker);
900
901 search_span.style.display="none";
902 coords_span.style.display="";
903 }
904
905
906 //
907 // Centre the marker on the map
908 //
909
910 function markerCentre(marker)
911 {
912 var lonlat=map.getCenter().clone();
913
914 lonlat.transform(map.getProjectionObject(),epsg4326);
915
916 formSetCoords(marker,lonlat.lon,lonlat.lat,true);
917 }
918
919
920 //
921 // Centre the map on the marker
922 //
923
924 function markerRecentre(marker)
925 {
926 lon=routino.point[marker].lon;
927 lat=routino.point[marker].lat;
928
929 var lonlat = new OpenLayers.LonLat(lon,lat).transform(epsg4326,map.getProjectionObject());
930
931 map.panTo(lonlat);
932 }
933
934
935 //
936 // Clear the current marker.
937 //
938
939 function markerRemove(marker)
940 {
941 for(var marker2=marker;marker2<vismarkers;marker2++)
942 formSetCoords(marker2,routino.point[marker2+1].lon,routino.point[marker2+1].lat,routino.point[marker2+1].active);
943
944 markerRemoveMap(vismarkers);
945
946 var marker_tr=document.getElementById("point" + vismarkers);
947
948 marker_tr.style.display="none";
949
950 vismarkers--;
951
952 if(vismarkers==1)
953 markerAddAfter(1);
954 }
955
956
957 //
958 // Add a marker before the current one.
959 //
960
961 function markerAddBefore(marker)
962 {
963 if(vismarkers==maxmarkers || marker==1)
964 return false;
965
966 vismarkers++;
967
968 var marker_tr=document.getElementById("point" + vismarkers);
969
970 marker_tr.style.display="";
971
972 for(var marker2=vismarkers;marker2>marker;marker2--)
973 formSetCoords(marker2,routino.point[marker2-1].lon,routino.point[marker2-1].lat,routino.point[marker2-1].active);
974
975 formSetCoords(marker,"","",false);
976
977 markerRemoveMap(marker);
978 }
979
980
981 //
982 // Add a marker after the current one.
983 //
984
985 function markerAddAfter(marker)
986 {
987 if(vismarkers==maxmarkers)
988 return false;
989
990 vismarkers++;
991
992 var marker_tr=document.getElementById("point" + vismarkers);
993
994 marker_tr.style.display="";
995
996 for(var marker2=vismarkers;marker2>(marker+1);marker2--)
997 formSetCoords(marker2,routino.point[marker2-1].lon,routino.point[marker2-1].lat,routino.point[marker2-1].active);
998
999 formSetCoords(marker+1,"","",false);
1000
1001 markerRemoveMap(marker+1);
1002 }
1003
1004
1005 //
1006 // Set this marker as the home location.
1007 //
1008
1009 function markerHome(marker)
1010 {
1011 if(markerHomeCookie(marker))
1012 for(marker=1;marker<=maxmarkers;marker++)
1013 updateIcon(marker);
1014 }
1015
1016
1017 //
1018 // Set this marker as the current location.
1019 //
1020
1021 function markerLocate(marker)
1022 {
1023 if(navigator.geolocation)
1024 navigator.geolocation.getCurrentPosition(
1025 function(position) {
1026 formSetCoords(marker,position.coords.longitude,position.coords.latitude,true);
1027 });
1028 }
1029
1030
1031 //
1032 // Update an icon to set colours and home or normal marker.
1033 //
1034
1035 function updateIcon(marker)
1036 {
1037 var lon=routino.point[marker].lon;
1038 var lat=routino.point[marker].lat;
1039
1040 if(lon==homelon && lat==homelat)
1041 {
1042 if(routino.point[marker].active)
1043 document.images["waypoint" + marker].src="icons/marker-home-red.png";
1044 else
1045 document.images["waypoint" + marker].src="icons/marker-home-grey.png";
1046
1047 markers[marker].style.externalGraphic="icons/marker-home-red.png";
1048 }
1049 else
1050 {
1051 if(routino.point[marker].active)
1052 document.images["waypoint" + marker].src="icons/marker-" + marker + "-red.png";
1053 else
1054 document.images["waypoint" + marker].src="icons/marker-" + marker + "-grey.png";
1055
1056 markers[marker].style.externalGraphic="icons/marker-" + marker + "-red.png";
1057 }
1058
1059 layerVectors.drawFeature(markers[marker]);
1060 }
1061
1062
1063 //
1064 // Set or clear the home marker icon
1065 //
1066
1067 function markerHomeCookie(marker)
1068 {
1069 var lon=routino.point[marker].lon;
1070 var lat=routino.point[marker].lat;
1071
1072 if(lon=="" || lat=="")
1073 return(false);
1074
1075 var cookie;
1076 var date = new Date();
1077
1078 if((homelat==null && homelon==null) ||
1079 (homelat!=lat && homelon!=lon))
1080 {
1081 cookie="Routino-home=lon:" + lon + ":lat:" + lat;
1082
1083 date.setUTCFullYear(date.getUTCFullYear()+5);
1084
1085 homelat=lat;
1086 homelon=lon;
1087 }
1088 else
1089 {
1090 cookie="Routino-home=unset";
1091
1092 date.setUTCFullYear(date.getUTCFullYear()-1);
1093
1094 homelat=null;
1095 homelon=null;
1096 }
1097
1098 document.cookie=cookie + ";expires=" + date.toGMTString();
1099
1100 return(true);
1101 }
1102
1103
1104 //
1105 // Move this marker up.
1106 //
1107
1108 function markerMoveUp(marker)
1109 {
1110 if(marker==1)
1111 {
1112 for(var m=1;m<vismarkers;m++)
1113 markerSwap(m,m+1);
1114 }
1115 else
1116 markerSwap(marker,marker-1);
1117 }
1118
1119
1120 //
1121 // Move this marker down.
1122 //
1123
1124 function markerMoveDown(marker)
1125 {
1126 if(marker==vismarkers)
1127 {
1128 for(var m=vismarkers;m>1;m--)
1129 markerSwap(m,m-1);
1130 }
1131 else
1132 markerSwap(marker,marker+1);
1133 }
1134
1135
1136 //
1137 // Swap a pair of markers.
1138 //
1139
1140 function markerSwap(marker1,marker2)
1141 {
1142 var lon=routino.point[marker1].lon;
1143 var lat=routino.point[marker1].lat;
1144 var active=routino.point[marker1].active;
1145
1146 formSetCoords(marker1,routino.point[marker2].lon,routino.point[marker2].lat,routino.point[marker2].active);
1147
1148 formSetCoords(marker2,lon,lat,active);
1149 }
1150
1151
1152 //
1153 // Reverse the markers.
1154 //
1155
1156 function markersReverse()
1157 {
1158 for(var marker=1;marker<=vismarkers/2;marker++)
1159 markerSwap(marker,vismarkers+1-marker);
1160 }
1161
1162
1163 ////////////////////////////////////////////////////////////////////////////////
1164 //////////////////////////// Route results handling ////////////////////////////
1165 ////////////////////////////////////////////////////////////////////////////////
1166
1167 var route_light_colours={shortest: "#60C060", quickest: "#6060C0"};
1168 var route_dark_colours ={shortest: "#408040", quickest: "#404080"};
1169
1170 var highlights={shortest: null, quickest: null};
1171 var popups={shortest: null, quickest: null};
1172 var routepoints={shortest: {}, quickest: {}};
1173 var gpx_style={shortest: null, quickest: null};
1174
1175 //
1176 // Zoom to a specific item in the route
1177 //
1178
1179 function zoomTo(type,line)
1180 {
1181 var lonlat = new OpenLayers.LonLat(routepoints[type][line].lon,routepoints[type][line].lat).transform(epsg4326,map.getProjectionObject());
1182
1183 map.moveTo(lonlat,map.numZoomLevels-2);
1184 }
1185
1186
1187 //
1188 // Highlight a specific item in the route
1189 //
1190
1191 function highlight(type,line)
1192 {
1193 if(line==-1)
1194 {
1195 highlights[type].style.display = "none";
1196
1197 drawPopup(popups[type],null);
1198 }
1199 else
1200 {
1201 // Marker
1202
1203 var lonlat = new OpenLayers.LonLat(routepoints[type][line].lon,routepoints[type][line].lat).transform(epsg4326,map.getProjectionObject());
1204
1205 highlights[type].move(lonlat);
1206
1207 if(highlights[type].style.display = "none")
1208 highlights[type].style.display = "";
1209
1210 // Popup
1211
1212 drawPopup(popups[type],"<table>" + routepoints[type][line].html + "</table>");
1213 }
1214
1215 layerVectors.drawFeature(highlights[type]);
1216 }
1217
1218
1219 //
1220 // Create a popup - not using OpenLayers because want it fixed on screen not fixed on map.
1221 //
1222
1223 function createPopup(type)
1224 {
1225 var popup=document.createElement('div');
1226
1227 popup.className = "popup";
1228
1229 popup.innerHTML = "<span></span>";
1230
1231 popup.style.display = "none";
1232
1233 popup.style.position = "fixed";
1234 popup.style.top = "-4000px";
1235 popup.style.left = "-4000px";
1236 popup.style.zIndex = "100";
1237
1238 popup.style.padding = "5px";
1239
1240 popup.style.opacity=0.85;
1241 popup.style.backgroundColor=route_light_colours[type];
1242 popup.style.border="4px solid " + route_dark_colours[type];
1243
1244 document.body.appendChild(popup);
1245
1246 return(popup);
1247 }
1248
1249
1250 //
1251 // Draw a popup - not using OpenLayers because want it fixed on screen not fixed on map.
1252 //
1253
1254 function drawPopup(popup,html)
1255 {
1256 if(html==null)
1257 {
1258 popup.style.display="none";
1259 return;
1260 }
1261
1262 if(popup.style.display=="none")
1263 {
1264 var map_div=document.getElementById("map");
1265
1266 popup.style.left =map_div.offsetParent.offsetLeft+map_div.offsetLeft+60 + "px";
1267 popup.style.top = map_div.offsetTop +30 + "px";
1268 popup.style.width =map_div.clientWidth-100 + "px";
1269
1270 popup.style.display="";
1271 }
1272
1273 popup.innerHTML=html;
1274 }
1275
1276
1277 //
1278 // Remove a GPX trace
1279 //
1280
1281 function removeGPXTrace(type)
1282 {
1283 map.removeLayer(layerGPX[type]);
1284 layerGPX[type].destroy();
1285 layerGPX[type]=null;
1286
1287 displayStatus(type,"no_info");
1288
1289 var div_links=document.getElementById(type + "_links");
1290 div_links.style.display = "none";
1291
1292 var div_route=document.getElementById(type + "_route");
1293 div_route.innerHTML = "";
1294
1295 hideshow_hide(type);
1296 }
1297
1298
1299 ////////////////////////////////////////////////////////////////////////////////
1300 /////////////////////////////// Server handling ////////////////////////////////
1301 ////////////////////////////////////////////////////////////////////////////////
1302
1303 //
1304 // Display data statistics
1305 //
1306
1307 function displayStatistics()
1308 {
1309 // Use AJAX to get the statistics
1310
1311 OpenLayers.loadURL("statistics.cgi",null,null,runStatisticsSuccess);
1312 }
1313
1314
1315 //
1316 // Success in running data statistics generation.
1317 //
1318
1319 function runStatisticsSuccess(response)
1320 {
1321 var statistics_data=document.getElementById("statistics_data");
1322 var statistics_link=document.getElementById("statistics_link");
1323
1324 statistics_data.innerHTML="<pre>" + response.responseText + "</pre>";
1325
1326 statistics_link.style.display="none";
1327 }
1328
1329
1330 //
1331 // Submit form - perform the routing
1332 //
1333
1334 function findRoute(type)
1335 {
1336 tab_select("results");
1337
1338 hideshow_hide('help_options');
1339 hideshow_hide('shortest');
1340 hideshow_hide('quickest');
1341
1342 displayStatus("result","running");
1343
1344 var url="router.cgi" + "?" + buildURLArguments(true) + ";type=" + type;
1345
1346 // Destroy the existing layer(s)
1347
1348 if(markersmoved || paramschanged)
1349 {
1350 if(layerGPX.shortest!=null)
1351 removeGPXTrace("shortest");
1352 if(layerGPX.quickest!=null)
1353 removeGPXTrace("quickest");
1354 markersmoved=false;
1355 paramschanged=false;
1356 }
1357 else if(layerGPX[type]!=null)
1358 removeGPXTrace(type);
1359
1360 // Use AJAX to run the router
1361
1362 routing_type=type;
1363
1364 OpenLayers.loadURL(url,null,null,runRouterSuccess,runRouterFailure);
1365 }
1366
1367
1368 //
1369 // Success in running router.
1370 //
1371
1372 function runRouterSuccess(response)
1373 {
1374 var lines=response.responseText.split('\n');
1375
1376 var uuid=lines[0];
1377 var cpuinfo=lines[1]; // not used
1378 var distinfo=lines[2]; // not used
1379 var message=lines[3]; // content not used
1380
1381 var link;
1382
1383 // Update the status message
1384
1385 if(message!="")
1386 {
1387 displayStatus("result","error");
1388 hideshow_show('help_route');
1389
1390 link=document.getElementById("router_log_error");
1391 link.href="results.cgi?uuid=" + uuid + ";type=router;format=log";
1392
1393 return;
1394 }
1395 else
1396 {
1397 displayStatus("result","complete");
1398 hideshow_hide('help_route');
1399
1400 link=document.getElementById("router_log_complete");
1401 link.href="results.cgi?uuid=" + uuid + ";type=router;format=log";
1402 }
1403
1404 // Update the routing result message
1405
1406 link=document.getElementById(routing_type + "_html");
1407 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=html";
1408 link=document.getElementById(routing_type + "_gpx_track");
1409 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-track";
1410 link=document.getElementById(routing_type + "_gpx_route");
1411 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-route";
1412 link=document.getElementById(routing_type + "_text_all");
1413 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=text-all";
1414 link=document.getElementById(routing_type + "_text");
1415 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=text";
1416
1417 var div_links=document.getElementById(routing_type + "_links");
1418 div_links.style.display = "";
1419
1420 // Add a GPX layer
1421
1422 var url="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-track";
1423
1424 layerGPX[routing_type] = new OpenLayers.Layer.GML("GPX (" + routing_type + ")", url,
1425 {
1426 format: OpenLayers.Format.GPX,
1427 style: gpx_style[routing_type],
1428 projection: map.displayProjection
1429 });
1430
1431 map.addLayer(layerGPX[routing_type]);
1432
1433 hideshow_show(routing_type);
1434
1435 displayResult(routing_type,uuid);
1436 }
1437
1438
1439 //
1440 // Failure in running router.
1441 //
1442
1443 function runRouterFailure(response)
1444 {
1445 displayStatus("result","failed");
1446 }
1447
1448
1449 //
1450 // Display the status
1451 //
1452
1453 function displayStatus(type,subtype,content)
1454 {
1455 var div_status=document.getElementById(type + "_status");
1456
1457 var child=div_status.firstChild;
1458
1459 do
1460 {
1461 if(child.id != undefined)
1462 child.style.display="none";
1463
1464 child=child.nextSibling;
1465 }
1466 while(child != undefined);
1467
1468 var chosen_status=document.getElementById(type + "_status_" + subtype);
1469
1470 chosen_status.style.display="";
1471
1472 if(content != null)
1473 chosen_status.innerHTML=content;
1474 }
1475
1476
1477 //
1478 // Display the route
1479 //
1480
1481 function displayResult(type,uuid)
1482 {
1483 routing_type = type;
1484
1485 // Add the route
1486
1487 var url="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=html";
1488
1489 // Use AJAX to get the route
1490
1491 OpenLayers.loadURL(url,null,null,getRouteSuccess,getRouteFailure);
1492 }
1493
1494
1495 //
1496 // Success in getting route.
1497 //
1498
1499 function getRouteSuccess(response)
1500 {
1501 var lines=response.responseText.split('\n');
1502 var div_route=document.getElementById(routing_type + "_route");
1503
1504 routepoints[routing_type]=[];
1505
1506 var points=routepoints[routing_type];
1507
1508 var table=0;
1509 var point=0;
1510 var total_table,total_word;
1511
1512 for(var line=0;line<lines.length;line++)
1513 {
1514 var thisline=lines[line];
1515
1516 if(table==0)
1517 {
1518 if(thisline.match('<table>'))
1519 table=1;
1520 else
1521 continue;
1522 }
1523
1524 if(thisline.match('</table>'))
1525 break;
1526
1527 if(thisline.match('<tr class=\'([a-z])\'>'))
1528 {
1529 var rowtype=RegExp.$1;
1530
1531 if(rowtype=='c')
1532 {
1533 thisline.match('<td class=\'r\'> *([-0-9.]+) *([-0-9.]+)');
1534 points[point]={lat: Number(RegExp.$1), lon: Number(RegExp.$2), html: "", highway: "", distance: "", total: ""};
1535
1536 point++;
1537 }
1538 else if(rowtype=='n')
1539 {
1540 points[point-1].html += thisline;
1541 }
1542 else if(rowtype=='s')
1543 {
1544 thisline.match('<span class=\'h\'>([^<]+)</span>');
1545 points[point-1].highway = RegExp.$1;
1546
1547 thisline.match('<span class=\'d\'>([^<]+)</span>');
1548 points[point-1].distance = RegExp.$1;
1549
1550 thisline.match('(<span class=\'j\'>[^<]+</span>)');
1551 points[point-1].total = RegExp.$1;
1552
1553 thisline.match('^(.*).<span class=\'j\'>');
1554
1555 points[point-1].html += RegExp.$1;
1556 }
1557 else if(rowtype=='t')
1558 {
1559 points[point-1].html += thisline;
1560
1561 thisline.match('^(.*<td class=\'r\'>)');
1562 total_table = RegExp.$1;
1563
1564 thisline.match('<td class=\'l\'>([^<]+)<');
1565 total_word = RegExp.$1;
1566
1567 thisline.match('<span class=\'j\'>([^<]+)</span>');
1568 points[point-1].total = RegExp.$1;
1569 }
1570 }
1571 }
1572
1573 displayStatus(routing_type,"info",points[point-1].total.bold());
1574
1575 var result="<table onmouseout='highlight(\"" + routing_type + "\",-1)'>";
1576
1577 for(var p=0;p<point-1;p++)
1578 {
1579 points[p].html += total_table + points[p].total;
1580
1581 result=result + "<tr onclick='zoomTo(\"" + routing_type + "\"," + p + ")'" +
1582 " onmouseover='highlight(\"" + routing_type + "\"," + p + ")'>" +
1583 "<td class='distance' title='" + points[p].distance + "'>#" + (p+1) +
1584 "<td class='highway'>" + points[p].highway;
1585 }
1586
1587 result=result + "<tr onclick='zoomTo(\"" + routing_type + "\"," + p + ")'" +
1588 " onmouseover='highlight(\"" + routing_type + "\"," + p + ")'>" +
1589 "<td colspan='2'>" + total_word + " " + points[p].total;
1590
1591 result=result + "</table>";
1592
1593 div_route.innerHTML=result;
1594 }
1595
1596
1597 //
1598 // Failure in getting route.
1599 //
1600
1601 function getRouteFailure(response)
1602 {
1603 var div_route=document.getElementById(routing_type + "_route");
1604 div_route.innerHTML = "";
1605 }
1606
1607
1608 //
1609 // Perform a search
1610 //
1611
1612 function DoSearch(marker)
1613 {
1614 // Use AJAX to get the search result
1615
1616 var search=routino.point[marker].search;
1617
1618 var url="search.cgi?marker=" + marker + ";search=" + encodeURIComponent(search);
1619
1620 OpenLayers.loadURL(url,null,null,runSearchSuccess);
1621 }
1622
1623
1624 //
1625 // Success in running search.
1626 //
1627
1628 function runSearchSuccess(response)
1629 {
1630 var lines=response.responseText.split('\n');
1631
1632 var marker=lines[0];
1633 var cpuinfo=lines[1]; // not used
1634 var latlon=lines[2];
1635 var message=lines[3]; // not used
1636
1637 latlon.match('([-.0-9]+) ([-.0-9]+)');
1638 lat = RegExp.$1;
1639 lon = RegExp.$2;
1640
1641 formSetCoords(marker,lon,lat,true);
1642 }