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.openlayers2.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2064 - (show annotations) (download) (as text)
Mon Aug 10 17:53:26 2020 UTC (4 years, 7 months ago) by amb
File MIME type: application/javascript
File size: 57826 byte(s)
Fix errors when zooming to the markers from the URL for openlayers.

1 //
2 // Routino router web page Javascript
3 //
4 // Part of the Routino routing software.
5 //
6 // This file Copyright 2008-2020 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
23 var vismarkers, markers, markersmoved, paramschanged;
24 var homelat=null, homelon=null;
25
26
27 ////////////////////////////////////////////////////////////////////////////////
28 /////////////////////////////// Initialisation /////////////////////////////////
29 ////////////////////////////////////////////////////////////////////////////////
30
31 // Make a deep copy of the routino profile.
32
33 var routino_default={};
34 for(var l1 in routino)
35 if(typeof(routino[l1])!="object")
36 routino_default[l1]=routino[l1];
37 else
38 {
39 routino_default[l1]={};
40 for(var l2 in routino[l1])
41 if(typeof(routino[l1][l2])!="object")
42 routino_default[l1][l2]=Number(routino[l1][l2]);
43 else
44 {
45 routino_default[l1][l2]={};
46 for(var l3 in routino[l1][l2])
47 routino_default[l1][l2][l3]=Number(routino[l1][l2][l3]);
48 }
49 }
50
51 // Store the latitude and longitude in the routino variable
52
53 routino.point=[];
54 for(var marker=1;marker<=mapprops.maxmarkers;marker++)
55 {
56 routino.point[marker]={};
57
58 routino.point[marker].lon="";
59 routino.point[marker].lat="";
60 routino.point[marker].search="";
61 routino.point[marker].active=false;
62 routino.point[marker].used=false;
63 routino.point[marker].home=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 "^reverse" : "(1|0|true|false|on|off)",
89 "^loop" : "(1|0|true|false|on|off)"};
90
91 var args={};
92
93 if(location.search.length>1)
94 {
95 var query,queries;
96
97 query=location.search.replace(/^\?/,"");
98 query=query.replace(/;/g,"&");
99 queries=query.split("&");
100
101 for(var i=0;i<queries.length;i++)
102 {
103 queries[i].match(/^([^=]+)(=(.*))?$/);
104
105 var k=RegExp.$1;
106 var v=decodeURIComponent(RegExp.$3);
107
108 for(var l in legal)
109 {
110 if(k.match(RegExp(l)) && v.match(RegExp(legal[l])))
111 args[k]=v;
112 }
113 }
114 }
115
116
117 //
118 // Fill in the HTML - add the missing waypoints
119 //
120
121 function html_init() // called from router.html
122 {
123 var waypoints=document.getElementById("waypoints");
124
125 var waypoint_html=waypoints.firstElementChild.outerHTML.split("XXX");
126
127 waypoints.removeChild(waypoints.firstElementChild);
128
129 for(var marker=1;marker<=mapprops.maxmarkers;marker++)
130 {
131 var waypoint=document.createElement('div');
132
133 waypoints.appendChild(waypoint);
134
135 waypoint.outerHTML=waypoint_html.join(marker);
136 }
137
138 waypoints.addEventListener('dragstart',dragWaypointStart,false);
139 waypoints.addEventListener('dragend' ,dragWaypointEnd ,false);
140 waypoints.addEventListener('dragenter',dragWaypointEnter,false);
141 waypoints.addEventListener('dragover' ,dragWaypointOver ,false);
142 waypoints.addEventListener('dragleave',dragWaypointLeave,false);
143 waypoints.addEventListener('drop' ,dragWaypointDrop ,false);
144
145
146 var map=document.getElementById("map");
147
148 map.addEventListener('dragenter',dragWaypointMapEnter,false);
149 map.addEventListener('dragover' ,dragWaypointMapOver ,false);
150 map.addEventListener('dragleave',dragWaypointMapLeave,false);
151 map.addEventListener('drop' ,dragWaypointMapDrop ,false);
152 }
153
154
155 ////////////////////////////////////////////////////////////////////////////////
156 //////////////////////////////// Form handling /////////////////////////////////
157 ////////////////////////////////////////////////////////////////////////////////
158
159 //
160 // Form initialisation - fill in the uninitialised parts
161 //
162
163 function form_init() // called from router.html
164 {
165 // Fill in the waypoints
166
167 vismarkers=0;
168 urlmarkers=0;
169
170 minlat=90;
171 maxlat=-90;
172 minlon=180;
173 maxlon=-180;
174
175 for(var marker=mapprops.maxmarkers;marker>=1;marker--)
176 {
177 var lon=args["lon" + marker];
178 var lat=args["lat" + marker];
179 var search=args["search" + marker];
180
181 if(lon !== undefined && lat !== undefined && search !== undefined && lon !== "" && lat !== "" && search !== "")
182 {
183 markerAddForm(marker);
184
185 formSetSearch(marker,search);
186 formSetCoords(marker,lon,lat);
187
188 lat=Number(lat);
189 lon=Number(lon);
190
191 if(lat<minlat) minlat=lat;
192 if(lat>maxlat) maxlat=lat;
193
194 if(lon<minlon) minlon=lon;
195 if(lon>maxlon) maxlon=lon;
196
197 markerAddMap(marker);
198
199 markerSearch(marker);
200
201 vismarkers++;
202 urlmarkers++;
203 }
204 else if(lon !== undefined && lat !== undefined && lon !== "" && lat !== "")
205 {
206 markerAddForm(marker);
207
208 formSetCoords(marker,lon,lat);
209
210 lat=Number(lat);
211 lon=Number(lon);
212
213 if(lat<minlat) minlat=lat;
214 if(lat>maxlat) maxlat=lat;
215
216 if(lon<minlon) minlon=lon;
217 if(lon>maxlon) maxlon=lon;
218
219 markerAddMap(marker);
220
221 markerCoords(marker);
222
223 vismarkers++;
224 urlmarkers++;
225 }
226 else if(search !== undefined && search !== "")
227 {
228 markerAddForm(marker);
229
230 formSetSearch(marker,search);
231
232 markerSearch(marker);
233
234 DoSearch(marker);
235
236 vismarkers++;
237 }
238 else if(vismarkers || marker<=2)
239 {
240 markerAddForm(marker);
241
242 vismarkers++;
243 }
244
245 var searchfield=document.forms["form"].elements["search" + marker];
246
247 if(searchfield.addEventListener)
248 searchfield.addEventListener("keyup", searchOnReturnKey, false);
249 else if(searchfield.attachEvent)
250 searchfield.attachEvent("keyup", searchOnReturnKey); // Internet Explorer
251 }
252
253 if(args["loop"] !== undefined)
254 formSetLoopReverse("loop",args["loop"]);
255 else
256 formSetLoopReverse("loop",false);
257
258 if(args["reverse"] !== undefined)
259 formSetLoopReverse("reverse",args["reverse"]);
260 else
261 formSetLoopReverse("reverse",false);
262
263 // Zoom the map
264
265 if(urlmarkers>1)
266 {
267 var lon =args["lon"];
268 var lat =args["lat"];
269 var zoom=args["zoom"];
270
271 if(lon === undefined || lat === undefined || zoom === undefined)
272 {
273 var markerextent=new OpenLayers.Bounds(minlon,minlat,maxlon,maxlat).transform(epsg4326,epsg900913);
274
275 map.setCenter(markerextent.getCenterLonLat(), map.getZoomForExtent(markerextent,false));
276 }
277 }
278
279 // Update the transport type with the URL settings which updates all HTML forms to defaults.
280
281 var transport=routino.transport;
282
283 if(args["transport"] !== undefined)
284 transport=args["transport"];
285
286 formSetTransport(transport);
287
288 // Update the HTML with the URL settings
289
290 if(args["language"] !== undefined)
291 formSetLanguage(args["language"]);
292 else
293 formSetLanguage();
294
295 for(var key in routino.profile_highway)
296 if(args["highway-" + key] !== undefined)
297 formSetHighway(key,args["highway-" + key]);
298
299 for(var key in routino.profile_speed)
300 if(args["speed-" + key] !== undefined)
301 formSetSpeed(key,args["speed-" + key]);
302
303 for(var key in routino.profile_property)
304 if(args["property-" + key] !== undefined)
305 formSetProperty(key,args["property-" + key]);
306
307 for(var key in routino.restrictions)
308 {
309 if(key=="oneway" || key=="turns")
310 {
311 if(args[key] !== undefined)
312 formSetRestriction(key,args[key]);
313 }
314 else
315 {
316 if(args["restrict-" + key] !== undefined)
317 formSetRestriction(key,args["restrict-" + key]);
318 }
319 }
320
321 // Get the home location cookie and compare to each waypoint
322
323 var cookies=document.cookie.split("; ");
324
325 for(var cookie=0;cookie<cookies.length;cookie++)
326 if(cookies[cookie].startsWith("Routino-home"))
327 {
328 var data=cookies[cookie].split(/[=:;]/);
329
330 if(data[1]=="lon") homelon=Number(data[2]);
331 if(data[3]=="lat") homelat=Number(data[4]);
332 }
333
334 if(homelon!==null && homelat!==null)
335 {
336 for(var m=1;m<=vismarkers;m++)
337 markerCheckHome(m);
338
339 // If the first location is empty and the cookie is set then fill it.
340
341 if(!routino.point[1].used)
342 markerMoveHome(1);
343 }
344
345 updateURLs();
346
347 updateSearchButtons();
348 }
349
350
351 //
352 // Function to perform the search if the return key is pressed.
353 // (using 'onchange' only triggers once and is confusing when clicking outside the field).
354 //
355
356 function searchOnReturnKey(ev)
357 {
358 if(ev.keyCode==13)
359 if(this.name.match(/^search([0-9]+)$/))
360 formSetSearch(RegExp.$1);
361
362 return(true);
363 }
364
365
366 //
367 // Change of language in the form
368 //
369
370 function formSetLanguage(value) // called from router.html (with no arguments)
371 {
372 if(value === undefined)
373 {
374 for(var lang=0;lang<document.forms["form"].elements["language"].length;lang++)
375 if(document.forms["form"].elements["language"][lang].checked)
376 routino.language=document.forms["form"].elements["language"][lang].value;
377 }
378 else
379 {
380 for(var lang=0;lang<document.forms["form"].elements["language"].length;lang++)
381 if(document.forms["form"].elements["language"][lang].value==value)
382 document.forms["form"].elements["language"][lang].checked=true;
383 else
384 document.forms["form"].elements["language"][lang].checked=false;
385
386 routino.language=value;
387 }
388
389 updateURLs();
390 }
391
392
393 //
394 // Change of transport in the form
395 //
396
397 function formSetTransport(value) // called from router.html
398 {
399 routino.transport=value;
400
401 for(var key in routino.transports)
402 document.forms["form"].elements["transport"][routino.transports[key]-1].checked=(key==routino.transport);
403
404 for(var key in routino.profile_highway)
405 document.forms["form"].elements["highway-" + key].value=routino.profile_highway[key][routino.transport];
406
407 for(var key in routino.profile_speed)
408 document.forms["form"].elements["speed-" + key].value=routino.profile_speed[key][routino.transport];
409
410 for(var key in routino.profile_property)
411 document.forms["form"].elements["property-" + key].value=routino.profile_property[key][routino.transport];
412
413 for(var key in routino.restrictions)
414 {
415 if(key=="oneway" || key=="turns")
416 document.forms["form"].elements["restrict-" + key].checked=routino.profile_restrictions[key][routino.transport];
417 else
418 document.forms["form"].elements["restrict-" + key].value=routino.profile_restrictions[key][routino.transport];
419 }
420
421 paramschanged=true;
422
423 updateURLs();
424 }
425
426
427 //
428 // Change of highway in the form
429 //
430
431 function formSetHighway(type,value) // called from router.html (with one argument)
432 {
433 if(value == "+")
434 {
435 value=routino.profile_highway[type][routino.transport];
436 value=10*Math.floor(value/10)+10;
437 }
438 else if(value == "-")
439 {
440 value=routino.profile_highway[type][routino.transport]-10;
441 value=10*Math.ceil(value/10)-10;
442 }
443 else if(value == "=")
444 value=document.forms["form"].elements["highway-" + type].value;
445
446 value=Number(value);
447 if(isNaN(value)) value= 50;
448 if(value>100) value=100;
449 if(value< 0) value= 0;
450
451 document.forms["form"].elements["highway-" + type].value=value;
452 routino.profile_highway[type][routino.transport]=value;
453
454 paramschanged=true;
455
456 updateURLs();
457 }
458
459
460 //
461 // Change of Speed in the form
462 //
463
464 function formSetSpeed(type,value) // called from router.html (with one argument)
465 {
466 if(value == "+")
467 {
468 value=routino.profile_speed[type][routino.transport];
469 if(value<10) value=2*Math.floor(value/2)+2;
470 else if(value<30) value=5*Math.floor(value/5)+5;
471 else value=10*Math.floor(value/10)+10;
472 }
473 else if(value == "-")
474 {
475 value=routino.profile_speed[type][routino.transport];
476 if(value<=10) value=2*Math.ceil(value/2)-2;
477 else if(value<=30) value=5*Math.ceil(value/5)-5;
478 else value=10*Math.ceil(value/10)-10;
479 }
480 else if(value == "=")
481 value=document.forms["form"].elements["speed-" + type].value;
482
483 value=Number(value);
484 if(isNaN(value)) value= 60;
485 if(value>150) value=150;
486 if(value< 0) value= 0;
487
488 document.forms["form"].elements["speed-" + type].value=value;
489 routino.profile_speed[type][routino.transport]=value;
490
491 paramschanged=true;
492
493 updateURLs();
494 }
495
496
497 //
498 // Change of Property in the form
499 //
500
501 function formSetProperty(type,value) // called from router.html (with one argument)
502 {
503 if(value == "+")
504 {
505 value=routino.profile_property[type][routino.transport];
506 if(value>=40 && value<60) value=2*Math.floor(value/2)+2;
507 else value=5*Math.floor(value/5)+5;
508 }
509 else if(value == "-")
510 {
511 value=routino.profile_property[type][routino.transport];
512 if(value>40 && value<=60) value=2*Math.ceil(value/2)-2;
513 else value=5*Math.ceil(value/5)-5;
514 }
515 else if(value == "=")
516 value=document.forms["form"].elements["property-" + type].value;
517
518 value=Number(value);
519 if(isNaN(value)) value= 50;
520 if(value>100) value=100;
521 if(value< 0) value= 0;
522
523 document.forms["form"].elements["property-" + type].value=value;
524 routino.profile_property[type][routino.transport]=value;
525
526 paramschanged=true;
527
528 updateURLs();
529 }
530
531
532 //
533 // Change of Restriction rule in the form
534 //
535
536 function formSetRestriction(type,value) // called from router.html (with one argument)
537 {
538 if(type=="oneway" || type=="turns")
539 {
540 if(value === undefined)
541 value=document.forms["form"].elements["restrict-" + type].checked;
542
543 document.forms["form"].elements["restrict-" + type].checked=value;
544 routino.profile_restrictions[type][routino.transport]=value;
545 }
546 else if(type=="weight")
547 {
548 if(value == "+")
549 value=routino.profile_restrictions[type][routino.transport]+5;
550 else if(value == "-")
551 value=routino.profile_restrictions[type][routino.transport]-5;
552 else if(value == "=")
553 value=document.forms["form"].elements["restrict-" + type].value;
554
555 value=Number(value);
556 if(isNaN(value)) value= 0;
557 if(value>50) value=50;
558 if(value< 0) value= 0;
559
560 document.forms["form"].elements["restrict-" + type].value=value;
561 routino.profile_restrictions[type][routino.transport]=value;
562 }
563 else /* if(type=="height" || type=="width" || type=="length") */
564 {
565 if(value == "+")
566 value=routino.profile_restrictions[type][routino.transport]+1;
567 else if(value == "-")
568 value=routino.profile_restrictions[type][routino.transport]-1;
569 else if(value == "=")
570 value=document.forms["form"].elements["restrict-" + type].value;
571
572 value=Number(value);
573 if(isNaN(value)) value= 0;
574 if(value>25) value=25;
575 if(value< 0) value= 0;
576
577 document.forms["form"].elements["restrict-" + type].value=value;
578 routino.profile_restrictions[type][routino.transport]=value;
579 }
580
581 paramschanged=true;
582
583 updateURLs();
584 }
585
586
587 //
588 // Set the feature coordinates from the form when the form changes.
589 //
590
591 function formSetCoords(marker,lon,lat) // called from router.html (with one argument)
592 {
593 clearSearchResult(marker);
594
595 if(lon === undefined && lat === undefined)
596 {
597 lon=document.forms["form"].elements["lon" + marker].value;
598 lat=document.forms["form"].elements["lat" + marker].value;
599 }
600
601 if(lon === "" && lat === "")
602 {
603 document.forms["form"].elements["lon" + marker].value="";
604 document.forms["form"].elements["lat" + marker].value="";
605
606 routino.point[marker].lon="";
607 routino.point[marker].lat="";
608
609 updateURLs();
610 }
611 else
612 {
613 var lonlat;
614
615 if(lon==="")
616 {
617 lonlat=map.getCenter().clone();
618 lonlat.transform(epsg900913,epsg4326);
619
620 lon=lonlat.lon;
621 }
622 else
623 lon=Number(lon);
624
625 if(lon<-180) lon=-180;
626 if(lon>+180) lon=+180;
627
628 if(lat==="")
629 {
630 lonlat=map.getCenter().clone();
631 lonlat.transform(epsg900913,epsg4326);
632
633 lat=lonlat.lat;
634 }
635 else
636 lat=Number(lat);
637
638 if(lat<-90 ) lat=-90 ;
639 if(lat>+90 ) lat=+90 ;
640
641 lonlat = new OpenLayers.LonLat(lon,lat);
642 lonlat.transform(epsg4326,epsg900913);
643
644 markers[marker].move(lonlat);
645
646 markersmoved=true;
647
648 document.forms["form"].elements["lon" + marker].value=format5f(lon);
649 document.forms["form"].elements["lat" + marker].value=format5f(lat);
650
651 routino.point[marker].lon=format5f(lon);
652 routino.point[marker].lat=format5f(lat);
653 routino.point[marker].used=true;
654
655 markerCheckHome(marker);
656 }
657 }
658
659
660 //
661 // Set the search field from the form when the form changes.
662 //
663
664 function formSetSearch(marker,search) // called from event handler linked to router.html (with one argument)
665 {
666 clearSearchResult(marker);
667
668 if(search === undefined)
669 {
670 routino.point[marker].search=document.forms["form"].elements["search" + marker].value;
671
672 DoSearch(marker);
673 }
674 else
675 {
676 document.forms["form"].elements["search" + marker].value=search;
677
678 routino.point[marker].search=search;
679 }
680 }
681
682
683 //
684 // Change of loop or reverse option in the form
685 //
686
687 function formSetLoopReverse(type,value) // called from router.html (with one argument)
688 {
689 if(value === undefined)
690 value=document.forms["form"].elements[type].checked;
691
692 document.forms["form"].elements[type].checked=value;
693
694 if(type == "loop")
695 routino.loop=value;
696 else
697 routino.reverse=value;
698
699 updateURLs();
700 }
701
702
703 //
704 // Format a number in printf("%.5f") format.
705 //
706
707 function format5f(number)
708 {
709 var newnumber=Math.floor(number*100000+0.5);
710 var delta=0;
711
712 if(newnumber>=0 && newnumber<100000) delta= 100000;
713 if(newnumber<0 && newnumber>-100000) delta=-100000;
714
715 var string=String(newnumber+delta);
716
717 var intpart =string.substring(0,string.length-5);
718 var fracpart=string.substring(string.length-5,string.length);
719
720 if(delta>0) intpart="0";
721 if(delta<0) intpart="-0";
722
723 return(intpart + "." + fracpart);
724 }
725
726
727 //
728 // Build a set of URL arguments
729 //
730
731 function buildURLArguments(lang)
732 {
733 var url= "transport=" + routino.transport;
734
735 for(var marker=1;marker<=vismarkers;marker++)
736 if(routino.point[marker].active)
737 {
738 url=url + ";lon" + marker + "=" + format5f(routino.point[marker].lon);
739 url=url + ";lat" + marker + "=" + format5f(routino.point[marker].lat);
740 if(routino.point[marker].search !== "")
741 url=url + ";search" + marker + "=" + encodeURIComponent(routino.point[marker].search);
742 }
743
744 for(var key in routino.profile_highway)
745 if(routino.profile_highway[key][routino.transport]!=routino_default.profile_highway[key][routino.transport])
746 url=url + ";highway-" + key + "=" + routino.profile_highway[key][routino.transport];
747
748 for(var key in routino.profile_speed)
749 if(routino.profile_speed[key][routino.transport]!=routino_default.profile_speed[key][routino.transport])
750 url=url + ";speed-" + key + "=" + routino.profile_speed[key][routino.transport];
751
752 for(var key in routino.profile_property)
753 if(routino.profile_property[key][routino.transport]!=routino_default.profile_property[key][routino.transport])
754 url=url + ";property-" + key + "=" + routino.profile_property[key][routino.transport];
755
756 for(var key in routino.restrictions)
757 if(routino.profile_restrictions[key][routino.transport]!=routino_default.profile_restrictions[key][routino.transport])
758 url=url + ";" + key + "=" + routino.profile_restrictions[key][routino.transport];
759
760 if(routino.loop)
761 url=url + ";loop=true";
762
763 if(routino.reverse)
764 url=url + ";reverse=true";
765
766 if(lang && routino.language)
767 url=url + ";language=" + routino.language;
768
769 return(url);
770 }
771
772
773 //
774 // Build a set of URL arguments for the map location
775 //
776
777 function buildMapArguments()
778 {
779 var lonlat = map.getCenter().clone();
780 lonlat.transform(epsg900913,epsg4326);
781
782 var zoom = map.getZoom() + map.minZoomLevel;
783
784 return "lat=" + format5f(lonlat.lat) + ";lon=" + format5f(lonlat.lon) + ";zoom=" + zoom;
785 }
786
787
788 //
789 // Update the URLs
790 //
791
792 function updateURLs()
793 {
794 var urlargs1=buildURLArguments(true);
795 var urlargs2=buildURLArguments(false);
796 var mapargs=buildMapArguments();
797
798 var links=document.getElementsByTagName("a");
799
800 for(var i=0; i<links.length; i++)
801 {
802 var element=links[i];
803
804 if(element.id == "permalink_url")
805 element.href=location.pathname + "?" + urlargs1 + ";" + mapargs;
806
807 if(element.id == "visualiser_url")
808 if(location.pathname.match(/router\.html\.([a-zA-Z-]+)$/))
809 element.href="visualiser.html." + RegExp.$1 + "?" + mapargs;
810 else
811 element.href="visualiser.html" + "?" + mapargs;
812
813 if(element.id == "edit_url")
814 element.href=mapprops.editurl + "?" + mapargs;
815
816 if(element.id.match(/^lang_([a-zA-Z-]+)_url$/))
817 element.href="router.html" + "." + RegExp.$1 + "?" + urlargs2 + ";" + mapargs;
818 }
819 }
820
821
822 ////////////////////////////////////////////////////////////////////////////////
823 ///////////////////////////////// Map handling /////////////////////////////////
824 ////////////////////////////////////////////////////////////////////////////////
825
826 var map;
827 var layerMap=[], layerVectors, layerGPX;
828 var epsg4326, epsg900913;
829 var routing_type;
830
831 //
832 // Initialise the 'map' object
833 //
834
835 function map_init() // called from router.html
836 {
837 // Create the map (Map URLs and limits are in mapprops.js)
838
839 epsg4326=new OpenLayers.Projection("EPSG:4326");
840 epsg900913=new OpenLayers.Projection("EPSG:900913");
841
842 map = new OpenLayers.Map ("map",
843 {
844 controls:[
845 new OpenLayers.Control.Navigation(),
846 new OpenLayers.Control.PanZoomBar(),
847 new OpenLayers.Control.ScaleLine(),
848 new OpenLayers.Control.LayerSwitcher()
849 ],
850
851 projection: epsg900913,
852 displayProjection: epsg4326,
853
854 minZoomLevel: mapprops.zoomout,
855 numZoomLevels: mapprops.zoomin-mapprops.zoomout+1,
856 maxResolution: 156543.03390625 / Math.pow(2,mapprops.zoomout),
857
858 restrictedExtent: new OpenLayers.Bounds(mapprops.westedge,mapprops.southedge,mapprops.eastedge,mapprops.northedge).transform(epsg4326,epsg900913)
859 });
860
861 // Get a URL for the tile (mostly copied from OpenLayers/Layer/XYZ.js).
862
863 function limitedUrl(bounds)
864 {
865 var res = this.map.getResolution();
866
867 var x = Math.round((bounds.left - this.maxExtent.left) / (res * this.tileSize.w));
868 var y = Math.round((this.maxExtent.top - bounds.top) / (res * this.tileSize.h));
869 var z = this.map.getZoom() + this.map.minZoomLevel;
870
871 var limit = Math.pow(2, z);
872 x = ((x % limit) + limit) % limit;
873
874 var xyz = {"x": x, "y": y, "z": z};
875 var url = this.url;
876
877 if (OpenLayers.Util.isArray(url))
878 {
879 var s = "" + xyz.x + xyz.y + xyz.z;
880 url = this.selectUrl(s, url);
881 }
882
883 return OpenLayers.String.format(url, xyz);
884 }
885
886 // Add map tile layers
887
888 for(var l=0; l<mapprops.mapdata.length; l++)
889 {
890 var urls;
891
892 if(OpenLayers.Util.isArray(mapprops.mapdata[l].tiles.subdomains))
893 {
894 urls=[];
895
896 for(var s=0; s<mapprops.mapdata[l].tiles.subdomains.length; s++)
897 urls.push(mapprops.mapdata[l].tiles.url.replace(/\${s}/,mapprops.mapdata[l].tiles.subdomains[s]));
898 }
899 else
900 urls=mapprops.mapdata[l].tiles.url;
901
902 layerMap[l] = new OpenLayers.Layer.TMS(mapprops.mapdata[l].label,
903 urls,
904 {
905 getURL: limitedUrl,
906 displayOutsideMaxExtent: true,
907 buffer: 1
908 });
909 map.addLayer(layerMap[l]);
910 }
911
912 // Update the attribution if the layer changes
913
914 function change_attribution_event(event)
915 {
916 for(var l=0; l<mapprops.mapdata.length; l++)
917 if(layerMap[l] == event.layer)
918 change_attribution(l);
919 }
920
921 map.events.register("changelayer",layerMap,change_attribution_event);
922
923 function change_attribution(l)
924 {
925 var data_url =mapprops.mapdata[l].attribution.data_url;
926 var data_text=mapprops.mapdata[l].attribution.data_text;
927 var tile_url =mapprops.mapdata[l].attribution.tile_url;
928 var tile_text=mapprops.mapdata[l].attribution.tile_text;
929
930 document.getElementById("attribution_data").innerHTML="<a href=\"" + data_url + "\" target=\"data_attribution\">" + data_text + "</a>";
931 document.getElementById("attribution_tile").innerHTML="<a href=\"" + tile_url + "\" target=\"tile_attribution\">" + tile_text + "</a>";
932 }
933
934 change_attribution(0);
935
936 // Define a GPX layer but don't add it yet
937
938 layerGPX={shortest: null, quickest: null};
939
940 gpx_style={shortest: new OpenLayers.Style({},{strokeWidth: 3, strokeColor: "#00FF00"}),
941 quickest: new OpenLayers.Style({},{strokeWidth: 3, strokeColor: "#0000FF"})};
942
943 // Add a markers vectors layer
944
945 layerVectors = new OpenLayers.Layer.Vector("Markers",{displayInLayerSwitcher: false});
946 map.addLayer(layerVectors);
947
948 // A set of markers
949
950 markers={};
951 markersmoved=false;
952 paramschanged=false;
953
954 for(var marker=1;marker<=mapprops.maxmarkers;marker++)
955 {
956 markers[marker] = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0),{},
957 new OpenLayers.Style({},{externalGraphic: "icons/marker-" + marker + "-red.png",
958 fillColor: "white",
959 graphicYOffset: -25,
960 graphicWidth: 21,
961 graphicHeight: 25,
962 display: "none"}));
963
964 layerVectors.addFeatures([markers[marker]]);
965 }
966
967 // A function to drag the markers
968
969 var drag = new OpenLayers.Control.DragFeature(layerVectors,
970 {onDrag: dragMarkerMove,
971 onComplete: dragMarkerComplete });
972 map.addControl(drag);
973 drag.activate();
974
975 // Markers to highlight a selected point
976
977 for(var highlight in highlights)
978 {
979 highlights[highlight] = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0),{},
980 new OpenLayers.Style({},{strokeColor: route_dark_colours[highlight],
981 fillColor: "white",
982 pointRadius: 10,
983 strokeWidth: 4,
984 fillOpacity: 0,
985 display: "none"}));
986
987 layerVectors.addFeatures([highlights[highlight]]);
988 }
989
990 // A popup for routing results
991
992 for(var popup in popups)
993 popups[popup] = createPopup(popup);
994
995 // Move the map
996
997 map.events.register("moveend", map, updateURLs);
998
999 var lon =args["lon"];
1000 var lat =args["lat"];
1001 var zoom=args["zoom"];
1002
1003 if(lon !== undefined && lat !== undefined && zoom !== undefined)
1004 {
1005 if(lon<mapprops.westedge) lon=mapprops.westedge;
1006 if(lon>mapprops.eastedge) lon=mapprops.eastedge;
1007
1008 if(lat<mapprops.southedge) lat=mapprops.southedge;
1009 if(lat>mapprops.northedge) lat=mapprops.northedge;
1010
1011 if(zoom<mapprops.zoomout) zoom=mapprops.zoomout;
1012 if(zoom>mapprops.zoomin) zoom=mapprops.zoomin;
1013
1014 var lonlat = new OpenLayers.LonLat(Number(lon),Number(lat));
1015 lonlat.transform(epsg4326,epsg900913);
1016
1017 map.moveTo(lonlat,zoom-map.minZoomLevel);
1018 }
1019 else
1020 {
1021 map.setCenter(map.restrictedExtent.getCenterLonLat(), map.getZoomForExtent(map.restrictedExtent,false));
1022 map.maxResolution = map.getResolution();
1023 }
1024
1025 // Unhide editing URL if variable set
1026
1027 if(mapprops.editurl !== undefined && mapprops.editurl !== "")
1028 {
1029 var edit_url=document.getElementById("edit_url");
1030
1031 edit_url.style.display="";
1032 edit_url.href=mapprops.editurl;
1033 }
1034
1035 updateURLs();
1036 }
1037
1038
1039 //
1040 // Callback for a marker drag occuring on the map.
1041 //
1042
1043 function dragMarkerMove(feature,pixel)
1044 {
1045 for(var marker=1;marker<=mapprops.maxmarkers;marker++)
1046 if(feature==markers[marker])
1047 dragMarkerSetForm(marker);
1048 }
1049
1050
1051 //
1052 // Callback for completing a marker drag on the map.
1053 //
1054
1055 function dragMarkerComplete(feature,pixel)
1056 {
1057 for(var marker=1;marker<=mapprops.maxmarkers;marker++)
1058 if(feature==markers[marker])
1059 dragMarkerSetForm(marker);
1060
1061 updateURLs();
1062 }
1063
1064
1065 //
1066 // Set the feature coordinates in the form after dragging it on the map.
1067 //
1068
1069 function dragMarkerSetForm(marker)
1070 {
1071 var lonlat = new OpenLayers.LonLat(markers[marker].geometry.x, markers[marker].geometry.y);
1072 lonlat.transform(epsg900913,epsg4326);
1073
1074 formSetCoords(marker,lonlat.lon,lonlat.lat);
1075 }
1076
1077
1078 ////////////////////////////////////////////////////////////////////////////////
1079 /////////////////////////////// Marker dragging ////////////////////////////////
1080 ////////////////////////////////////////////////////////////////////////////////
1081
1082 var dragged_waypoint=null,dragged_marker=null;
1083 var dragged_waypoint_over=null,dragged_marker_over=null;
1084 var dragged_icon_x,dragged_icon_y;
1085
1086 //
1087 // Drag a waypoint up or down the list.
1088 //
1089
1090 function dragWaypointStart(e)
1091 {
1092 var w=e.target;
1093
1094 while(w!=null && w.className != "waypoint")
1095 w=w.parentElement;
1096
1097 if(w===null)
1098 return;
1099
1100 w.style.opacity = "0.5";
1101
1102 dragged_waypoint=w;
1103 dragged_marker=Number.parseInt(dragged_waypoint.id.substring(8));
1104
1105 dragged_icon_x=e.clientX-e.target.offsetLeft;
1106 dragged_icon_y=e.clientY-e.target.offsetTop;
1107 }
1108
1109 function dragWaypointEnd(e)
1110 {
1111 e.preventDefault();
1112
1113 if(dragged_waypoint===null)
1114 return;
1115
1116 dragged_waypoint.style.opacity = "";
1117
1118 dragged_waypoint=null;
1119 dragged_marker=null;
1120
1121 if(dragged_waypoint_over===null)
1122 return;
1123
1124 dragged_waypoint_over.style.border = "";
1125
1126 dragged_waypoint_over=null;
1127 dragged_marker_over=null;
1128 }
1129
1130
1131 //
1132 // Drag a waypoint over another one up or down the list.
1133 //
1134
1135 function dragWaypointEnter(e)
1136 {
1137 var w=e.target;
1138
1139 while(w!=null && w.className != "waypoint")
1140 w=w.parentElement;
1141
1142 if(w===null)
1143 return;
1144
1145 if(dragged_waypoint_over!==null)
1146 dragged_waypoint_over.style.border = "";
1147
1148 if(w==dragged_waypoint)
1149 return;
1150
1151 dragged_waypoint_over=w;
1152 dragged_marker_over=Number.parseInt(dragged_waypoint_over.id.substring(8));
1153
1154 if(dragged_marker>dragged_marker_over)
1155 w.style.borderTop = "3px solid black";
1156 else
1157 w.style.borderBottom = "3px solid black";
1158 }
1159
1160 function dragWaypointOver(e)
1161 {
1162 e.preventDefault();
1163 }
1164
1165 function dragWaypointLeave(e)
1166 {
1167 var w=e.target;
1168
1169 while(w!=null && w.className != "waypoint")
1170 w=w.parentElement;
1171
1172 if(w===null)
1173 return;
1174
1175 if(w==dragged_waypoint_over)
1176 return;
1177
1178 w.style.border = "";
1179 }
1180
1181
1182 //
1183 // Drop the waypoint after dragging up or down the list.
1184 //
1185
1186 function dragWaypointDrop(e)
1187 {
1188 e.preventDefault();
1189
1190 if(dragged_marker_over===null)
1191 return;
1192
1193 if(dragged_marker_over>dragged_marker)
1194 for(var m=dragged_marker;m<dragged_marker_over;m++)
1195 markerSwap(m,m+1);
1196
1197 if(dragged_marker_over<dragged_marker)
1198 for(var m=dragged_marker;m>dragged_marker_over;m--)
1199 markerSwap(m,m-1);
1200 }
1201
1202
1203 //
1204 // Drag a waypoint over the map.
1205 //
1206
1207 function dragWaypointMapEnter(e)
1208 {
1209 e.preventDefault();
1210
1211 if(dragged_waypoint_over!==null)
1212 dragged_waypoint_over.style.border = "";
1213 }
1214
1215 function dragWaypointMapOver(e)
1216 {
1217 e.preventDefault();
1218 }
1219
1220 function dragWaypointMapLeave(e)
1221 {
1222 e.preventDefault();
1223 }
1224
1225
1226 //
1227 // Drop the waypoint after dragging it over the map.
1228 //
1229
1230 function dragWaypointMapDrop(e)
1231 {
1232 e.preventDefault();
1233
1234 var rect = document.getElementById("map").getBoundingClientRect();
1235
1236 var lonlat = map.getLonLatFromViewPortPx(new OpenLayers.Pixel(e.clientX-rect.left-window.scrollX-dragged_icon_x+8,
1237 e.clientY-rect.top -window.scrollY-dragged_icon_y+21));
1238 lonlat.transform(epsg900913,epsg4326);
1239
1240 formSetCoords(dragged_marker,lonlat.lon,lonlat.lat);
1241
1242 if(!routino.point[dragged_marker].active)
1243 markerToggleMap(dragged_marker);
1244
1245 if(routino.point[dragged_marker].search=="")
1246 markerCoords(dragged_marker);
1247 }
1248
1249
1250 ////////////////////////////////////////////////////////////////////////////////
1251 /////////////////////////////// Marker handling ////////////////////////////////
1252 ////////////////////////////////////////////////////////////////////////////////
1253
1254 //
1255 // Toggle a marker on the map.
1256 //
1257
1258 function markerToggleMap(marker) // called from router.html
1259 {
1260 if(!routino.point[marker].used)
1261 {
1262 routino.point[marker].used=true;
1263 markerCentre(marker);
1264 markerCoords(marker);
1265 }
1266
1267 markerAddRemoveMap(marker,!routino.point[marker].active);
1268 }
1269
1270
1271 //
1272 // Show or hide a marker on the map.
1273 //
1274
1275 function markerAddRemoveMap(marker,active)
1276 {
1277 if(active)
1278 markerAddMap(marker);
1279 else
1280 markerRemoveMap(marker);
1281 }
1282
1283
1284 //
1285 // Show a marker on the map.
1286 //
1287
1288 function markerAddMap(marker)
1289 {
1290 clearSearchResult(marker);
1291
1292 markers[marker].style.display = "";
1293 routino.point[marker].active=true;
1294 routino.point[marker].used=true;
1295
1296 updateIcon(marker);
1297
1298 markersmoved=true;
1299
1300 updateURLs();
1301
1302 updateSearchButtons();
1303 }
1304
1305
1306 //
1307 // Remove a marker from the map.
1308 //
1309
1310 function markerRemoveMap(marker)
1311 {
1312 clearSearchResult(marker);
1313
1314 markers[marker].style.display = "none";
1315 routino.point[marker].active=false;
1316
1317 updateIcon(marker);
1318
1319 markersmoved=true;
1320
1321 updateURLs();
1322
1323 updateSearchButtons();
1324 }
1325
1326
1327 //
1328 // Display search string for the marker
1329 //
1330
1331 function markerSearch(marker) // called from router.html
1332 {
1333 clearSearchResult(marker);
1334
1335 document.getElementById("coords" + marker).style.display="none";
1336 document.getElementById("search" + marker).style.display="";
1337 }
1338
1339
1340 //
1341 // Display coordinates for the marker
1342 //
1343
1344 function markerCoords(marker) // called from router.html
1345 {
1346 clearSearchResult(marker);
1347
1348 document.getElementById("search" + marker).style.display="none";
1349 document.getElementById("coords" + marker).style.display="";
1350 }
1351
1352
1353 //
1354 // Centre the marker on the map
1355 //
1356
1357 function markerCentre(marker) // called from router.html
1358 {
1359 if(!routino.point[marker].used)
1360 return;
1361
1362 clearSearchResult(marker);
1363
1364 var lonlat=map.getCenter().clone();
1365 lonlat.transform(epsg900913,epsg4326);
1366
1367 formSetCoords(marker,lonlat.lon,lonlat.lat);
1368 }
1369
1370
1371 //
1372 // Centre the map on the marker
1373 //
1374
1375 function markerRecentre(marker) // called from router.html
1376 {
1377 if(!routino.point[marker].used)
1378 return;
1379
1380 clearSearchResult(marker);
1381
1382 var lon=Number(routino.point[marker].lon);
1383 var lat=Number(routino.point[marker].lat);
1384
1385 var lonlat = new OpenLayers.LonLat(lon,lat);
1386 lonlat.transform(epsg4326,epsg900913);
1387
1388 map.panTo(lonlat);
1389 }
1390
1391
1392 //
1393 // Clear the current marker.
1394 //
1395
1396 function markerRemove(marker) // called from router.html
1397 {
1398 clearSearchResult(marker);
1399
1400 for(var m=marker;m<vismarkers;m++)
1401 markerCopy(m,m+1);
1402
1403 markerRemoveForm(vismarkers--);
1404
1405 if(vismarkers==1)
1406 markerAddAfter(1);
1407
1408 updateSearchButtons();
1409 }
1410
1411
1412 //
1413 // Add a marker before the current one.
1414 //
1415
1416 function markerAddBefore(marker)
1417 {
1418 if(vismarkers==mapprops.maxmarkers || marker==1)
1419 return false;
1420
1421 clearSearchResult(marker);
1422
1423 markerAddForm(++vismarkers);
1424
1425 for(var m=vismarkers;m>marker;m--)
1426 markerCopy(m,m-1);
1427
1428 markerClearForm(marker-1);
1429 }
1430
1431
1432 //
1433 // Add a marker after the current one.
1434 //
1435
1436 function markerAddAfter(marker) // called from router.html
1437 {
1438 if(vismarkers==mapprops.maxmarkers)
1439 return false;
1440
1441 clearSearchResult(marker);
1442
1443 markerAddForm(++vismarkers);
1444
1445 for(var m=vismarkers;m>(marker+1);m--)
1446 markerCopy(m,m-1);
1447
1448 markerClearForm(marker+1);
1449 }
1450
1451
1452 //
1453 // Set this marker as the home location.
1454 //
1455
1456 function markerHome(marker) // called from router.html
1457 {
1458 if(!routino.point[marker].used)
1459 {
1460 markerMoveHome(marker);
1461 }
1462 else
1463 {
1464 clearSearchResult(marker);
1465
1466 markerSetClearHome(marker,!routino.point[marker].home);
1467 }
1468 }
1469
1470
1471 //
1472 // Set this marker as the current location.
1473 //
1474
1475 function markerLocate(marker) // called from router.html
1476 {
1477 clearSearchResult(marker);
1478
1479 function success(position)
1480 {
1481 formSetCoords(marker,position.coords.longitude,position.coords.latitude);
1482 markerAddMap(marker);
1483 }
1484
1485 function failure(error)
1486 {
1487 alert("Error: " + error.message);
1488 }
1489
1490 if(navigator.geolocation)
1491 navigator.geolocation.getCurrentPosition(success,failure);
1492 else
1493 alert("Error: Geolocation unavailable");
1494 }
1495
1496
1497 //
1498 // Update the search buttons enable/disable.
1499 //
1500
1501 function updateSearchButtons()
1502 {
1503 var markersactive=0;
1504
1505 for(var m=1;m<=vismarkers;m++)
1506 if(routino.point[m].active)
1507 markersactive++;
1508
1509 if(markersactive<2)
1510 {
1511 document.getElementById("shortest1").disabled="disabled";
1512 document.getElementById("quickest1").disabled="disabled";
1513 document.getElementById("shortest2").disabled="disabled";
1514 document.getElementById("quickest2").disabled="disabled";
1515 }
1516 else
1517 {
1518 document.getElementById("shortest1").disabled="";
1519 document.getElementById("quickest1").disabled="";
1520 document.getElementById("shortest2").disabled="";
1521 document.getElementById("quickest2").disabled="";
1522 }
1523 }
1524
1525
1526 //
1527 // Update an icon to set colours and home or normal marker.
1528 //
1529
1530 function updateIcon(marker)
1531 {
1532 if(routino.point[marker].home)
1533 {
1534 if(routino.point[marker].active)
1535 document.getElementById("icon" + marker).src="icons/marker-home-red.png";
1536 else
1537 document.getElementById("icon" + marker).src="icons/marker-home-grey.png";
1538
1539 markers[marker].style.externalGraphic="icons/marker-home-red.png";
1540 }
1541 else
1542 {
1543 if(routino.point[marker].active)
1544 document.getElementById("icon" + marker).src="icons/marker-" + marker + "-red.png";
1545 else
1546 document.getElementById("icon" + marker).src="icons/marker-" + marker + "-grey.png";
1547
1548 markers[marker].style.externalGraphic="icons/marker-" + marker + "-red.png";
1549 }
1550
1551 layerVectors.drawFeature(markers[marker]);
1552 }
1553
1554
1555 //
1556 // Move the marker to the home location
1557 //
1558
1559 function markerMoveHome(marker)
1560 {
1561 if(homelon===null || homelat===null)
1562 return;
1563
1564 routino.point[marker].home=true;
1565 routino.point[marker].used=true;
1566
1567 formSetCoords(marker,homelon,homelat);
1568 markerAddMap(marker);
1569 }
1570
1571
1572 //
1573 // Set or clear the home marker icon
1574 //
1575
1576 function markerSetClearHome(marker,home)
1577 {
1578 var cookie;
1579 var date = new Date();
1580
1581 if(home)
1582 {
1583 homelat=format5f(routino.point[marker].lat);
1584 homelon=format5f(routino.point[marker].lon);
1585
1586 cookie="Routino-home=lon:" + homelon + ":lat:" + homelat;
1587
1588 date.setUTCFullYear(date.getUTCFullYear()+5);
1589
1590 routino.point[marker].home=true;
1591 }
1592 else
1593 {
1594 homelat=null;
1595 homelon=null;
1596
1597 cookie="Routino-home=";
1598
1599 date.setUTCFullYear(date.getUTCFullYear()-1);
1600
1601 routino.point[marker].home=false;
1602 }
1603
1604 document.cookie=cookie + ";Expires=" + date.toGMTString() + ";SameSite=Strict";
1605
1606 updateIcon(marker);
1607
1608 for(var m=1;m<=mapprops.maxmarkers;m++)
1609 markerCheckHome(m);
1610 }
1611
1612
1613 //
1614 // Check if a marker is the home marker
1615 //
1616
1617 function markerCheckHome(marker)
1618 {
1619 var home=routino.point[marker].home;
1620
1621 if(routino.point[marker].lon==homelon && routino.point[marker].lat==homelat)
1622 routino.point[marker].home=true;
1623 else
1624 routino.point[marker].home=false;
1625
1626 if(home!=routino.point[marker].home)
1627 updateIcon(marker);
1628 }
1629
1630
1631 //
1632 // Move this marker up.
1633 //
1634
1635 function markerMoveUp(marker) // called from router.html
1636 {
1637 if(marker==1)
1638 {
1639 for(var m=1;m<vismarkers;m++)
1640 markerSwap(m,m+1);
1641 }
1642 else
1643 markerSwap(marker,marker-1);
1644 }
1645
1646
1647 //
1648 // Move this marker down.
1649 //
1650
1651 function markerMoveDown(marker) // called from router.html
1652 {
1653 if(marker==vismarkers)
1654 {
1655 for(var m=vismarkers;m>1;m--)
1656 markerSwap(m,m-1);
1657 }
1658 else
1659 markerSwap(marker,marker+1);
1660 }
1661
1662
1663 //
1664 // Copy a marker from one place to another.
1665 //
1666
1667 function markerCopy(marker1,marker2)
1668 {
1669 for(var element in routino.point[marker2])
1670 routino.point[marker1][element]=routino.point[marker2][element];
1671
1672 document.getElementById("search" + marker1).style.display=document.getElementById("search" + marker2).style.display;
1673
1674 document.getElementById("coords" + marker1).style.display=document.getElementById("coords" + marker2).style.display;
1675
1676 document.forms["form"].elements["search" + marker1].value=document.forms["form"].elements["search" + marker2].value;
1677
1678 formSetCoords(marker1,routino.point[marker1].lon,routino.point[marker1].lat);
1679
1680 markerAddRemoveMap(marker1,routino.point[marker1].active);
1681 }
1682
1683
1684 //
1685 // Swap a pair of markers.
1686 //
1687
1688 function markerSwap(marker1,marker2)
1689 {
1690 for(var element in routino.point[marker2])
1691 {
1692 var temp=routino.point[marker1][element];
1693 routino.point[marker1][element]=routino.point[marker2][element];
1694 routino.point[marker2][element]=temp;
1695 }
1696
1697 var search_display=document.getElementById("search" + marker1).style.display;
1698 document.getElementById("search" + marker1).style.display=document.getElementById("search" + marker2).style.display;
1699 document.getElementById("search" + marker2).style.display=search_display;
1700
1701 var coords_display=document.getElementById("coords" + marker1).style.display;
1702 document.getElementById("coords" + marker1).style.display=document.getElementById("coords" + marker2).style.display;
1703 document.getElementById("coords" + marker2).style.display=coords_display;
1704
1705 var search_value=document.forms["form"].elements["search" + marker1].value;
1706 document.forms["form"].elements["search" + marker1].value=document.forms["form"].elements["search" + marker2].value;
1707 document.forms["form"].elements["search" + marker2].value=search_value;
1708
1709 formSetCoords(marker1,routino.point[marker1].lon,routino.point[marker1].lat);
1710 formSetCoords(marker2,routino.point[marker2].lon,routino.point[marker2].lat);
1711
1712 markerAddRemoveMap(marker1,routino.point[marker1].active);
1713 markerAddRemoveMap(marker2,routino.point[marker2].active);
1714 }
1715
1716
1717 //
1718 // Reverse the markers.
1719 //
1720
1721 function markersReverse() // called from router.html
1722 {
1723 for(var marker=1;marker<=vismarkers/2;marker++)
1724 markerSwap(marker,vismarkers+1-marker);
1725
1726 markersmoved=true;
1727
1728 updateURLs();
1729 }
1730
1731
1732 //
1733 // Close the loop.
1734 //
1735
1736 function markersLoop() // called from router.html
1737 {
1738 if(vismarkers==mapprops.maxmarkers)
1739 return false;
1740
1741 if(routino.point[vismarkers].lon==routino.point[1].lon && routino.point[vismarkers].lat==routino.point[1].lat)
1742 {
1743 if(routino.point[vismarkers].active)
1744 return false;
1745 else
1746 {
1747 markerToggleMap(vismarkers);
1748 return true;
1749 }
1750 }
1751
1752 if(routino.point[vismarkers].used)
1753 markerAddForm(++vismarkers);
1754
1755 markerCopy(vismarkers,1);
1756
1757 markersmoved=true;
1758
1759 updateURLs();
1760
1761 updateSearchButtons();
1762 }
1763
1764
1765 //
1766 // Display the form for a marker
1767 //
1768
1769 function markerAddForm(marker)
1770 {
1771 document.getElementById("waypoint" + marker).style.display="";
1772 }
1773
1774
1775 //
1776 // Hide the form for a marker
1777 //
1778
1779 function markerRemoveForm(marker)
1780 {
1781 document.getElementById("waypoint" + marker).style.display="none";
1782
1783 markerClearForm(marker);
1784 }
1785
1786
1787 //
1788 // Clear the form for a marker
1789 //
1790
1791 function markerClearForm(marker)
1792 {
1793 markerRemoveMap(marker);
1794 markerSearch(marker);
1795
1796 formSetCoords(marker,"","");
1797 formSetSearch(marker,"");
1798
1799 updateIcon(marker);
1800
1801 routino.point[marker].used=false;
1802 routino.point[marker].home=false;
1803 routino.point[marker].active=false;
1804 }
1805
1806
1807 ////////////////////////////////////////////////////////////////////////////////
1808 //////////////////////////// Route results handling ////////////////////////////
1809 ////////////////////////////////////////////////////////////////////////////////
1810
1811 var route_light_colours={shortest: "#60C060", quickest: "#6060C0"};
1812 var route_dark_colours ={shortest: "#408040", quickest: "#404080"};
1813
1814 var highlights={shortest: null, quickest: null};
1815 var popups={shortest: null, quickest: null};
1816 var routepoints={shortest: {}, quickest: {}};
1817 var gpx_style={shortest: null, quickest: null};
1818
1819
1820 //
1821 // Highlight a specific item in the route
1822 //
1823
1824 function highlight(type,line,action)
1825 {
1826 if(action == "clear")
1827 {
1828 highlights[type].style.display = "none";
1829
1830 drawPopup(type,null);
1831 }
1832 else if(action == "zoom")
1833 {
1834 var lonlat = new OpenLayers.LonLat(routepoints[type][line].lon,routepoints[type][line].lat);
1835 lonlat.transform(epsg4326,epsg900913);
1836
1837 map.moveTo(lonlat,map.numZoomLevels-3);
1838 }
1839 else
1840 {
1841 // Marker
1842
1843 var lonlat = new OpenLayers.LonLat(routepoints[type][line].lon,routepoints[type][line].lat);
1844 lonlat.transform(epsg4326,epsg900913);
1845
1846 highlights[type].move(lonlat);
1847
1848 if(highlights[type].style.display == "none")
1849 highlights[type].style.display = "";
1850
1851 // Popup
1852
1853 drawPopup(type,"<table>" + routepoints[type][line].html + "</table>");
1854 }
1855
1856 layerVectors.drawFeature(highlights[type]);
1857 }
1858
1859
1860 //
1861 // Create a popup - independent of map because want it fixed on screen not fixed on map.
1862 //
1863
1864 function createPopup(type)
1865 {
1866 var popup=document.createElement("div");
1867
1868 popup.className = "popup";
1869
1870 popup.innerHTML = "<span></span>";
1871
1872 popup.style.display = "none";
1873
1874 popup.style.position = "fixed";
1875 popup.style.top = "-4000px";
1876 popup.style.left = "-4000px";
1877 popup.style.zIndex = "100";
1878
1879 popup.style.padding = "5px";
1880
1881 popup.style.opacity=0.85;
1882 popup.style.backgroundColor=route_light_colours[type];
1883 popup.style.border="4px solid " + route_dark_colours[type];
1884
1885 document.body.appendChild(popup);
1886
1887 return(popup);
1888 }
1889
1890
1891 //
1892 // Draw a popup - independent of map because want it fixed on screen not fixed on map.
1893 //
1894
1895 function drawPopup(type,html)
1896 {
1897 var popup=popups[type];
1898
1899 if(html===null)
1900 {
1901 popup.style.display="none";
1902 return;
1903 }
1904
1905 if(popup.style.display=="none")
1906 {
1907 var map_div=document.getElementById("map");
1908
1909 popup.style.left =map_div.offsetParent.offsetLeft+map_div.offsetLeft+60 + "px";
1910 popup.style.top = map_div.offsetTop +30 + "px";
1911 popup.style.width =map_div.clientWidth-120 + "px";
1912
1913 popup.style.display="";
1914 }
1915
1916 var close="<span style='float: right; cursor: pointer;' onclick='highlight(\""+type+"\",-1,\"clear\")'>X</span>";
1917
1918 popup.innerHTML=close+html;
1919 }
1920
1921
1922 //
1923 // Remove a GPX trace
1924 //
1925
1926 function removeGPXTrace(type)
1927 {
1928 map.removeLayer(layerGPX[type]);
1929 layerGPX[type].destroy();
1930 layerGPX[type]=null;
1931
1932 displayStatus(type,"no_info");
1933
1934 document.getElementById(type + "_links").style.display = "none";
1935
1936 document.getElementById(type + "_route").innerHTML = "";
1937
1938 hideshow_hide(type);
1939 }
1940
1941
1942 ////////////////////////////////////////////////////////////////////////////////
1943 /////////////////////////////// Server handling ////////////////////////////////
1944 ////////////////////////////////////////////////////////////////////////////////
1945
1946 //
1947 // Define an AJAX request object
1948 //
1949
1950 function ajaxGET(url,success,failure,state)
1951 {
1952 var ajaxRequest=new XMLHttpRequest();
1953
1954 function ajaxGOT(options) {
1955 if(this.readyState==4)
1956 if(this.status==200)
1957 { if(typeof(options.success)=="function") options.success(this,options.state); }
1958 else
1959 { if(typeof(options.failure)=="function") options.failure(this,options.state); }
1960 }
1961
1962 ajaxRequest.onreadystatechange = function(){ ajaxGOT.call(ajaxRequest,{success: success, failure: failure, state: state}); };
1963 ajaxRequest.open("GET", url, true);
1964 ajaxRequest.send(null);
1965 }
1966
1967
1968 //
1969 // Display data statistics
1970 //
1971
1972 function displayStatistics() // called from router.html
1973 {
1974 // Use AJAX to get the statistics
1975
1976 ajaxGET("statistics.cgi", runStatisticsSuccess);
1977 }
1978
1979
1980 //
1981 // Success in running data statistics generation.
1982 //
1983
1984 function runStatisticsSuccess(response)
1985 {
1986 document.getElementById("statistics_data").innerHTML="<pre>" + response.responseText + "</pre>";
1987 document.getElementById("statistics_link").style.display="none";
1988 }
1989
1990
1991 //
1992 // Submit form - perform the routing
1993 //
1994
1995 function findRoute(type) // called from router.html
1996 {
1997 tab_select("results");
1998
1999 hideshow_hide("help_options");
2000 hideshow_hide("shortest");
2001 hideshow_hide("quickest");
2002
2003 displayStatus("result","running");
2004
2005 var url="router.cgi" + "?" + buildURLArguments(true) + ";type=" + type;
2006
2007 // Destroy the existing layer(s)
2008
2009 highlight("shortest",-1,"clear");
2010 highlight("quickest",-1,"clear");
2011
2012 if(markersmoved || paramschanged)
2013 {
2014 if(layerGPX.shortest!==null)
2015 removeGPXTrace("shortest");
2016 if(layerGPX.quickest!==null)
2017 removeGPXTrace("quickest");
2018 markersmoved=false;
2019 paramschanged=false;
2020 }
2021 else if(layerGPX[type]!==null)
2022 removeGPXTrace(type);
2023
2024 // Use AJAX to run the router
2025
2026 routing_type=type;
2027
2028 ajaxGET(url, runRouterSuccess, runRouterFailure);
2029 }
2030
2031
2032 //
2033 // Success in running router.
2034 //
2035
2036 function runRouterSuccess(response)
2037 {
2038 var lines=response.responseText.split("\n");
2039
2040 var uuid=lines[0];
2041 var success=lines[1];
2042
2043 var link;
2044
2045 // Update the status message
2046
2047 if(success=="ERROR")
2048 {
2049 displayStatus("result","error");
2050 hideshow_show("help_route");
2051
2052 link=document.getElementById("router_log_error");
2053 link.href="results.cgi?uuid=" + uuid + ";type=router;format=log";
2054
2055 return;
2056 }
2057 else
2058 {
2059 displayStatus("result","complete");
2060 hideshow_hide("help_route");
2061
2062 link=document.getElementById("router_log_complete");
2063 link.href="results.cgi?uuid=" + uuid + ";type=router;format=log";
2064 }
2065
2066 // Update the routing result message
2067
2068 link=document.getElementById(routing_type + "_html");
2069 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=html";
2070
2071 link=document.getElementById(routing_type + "_gpx_track");
2072 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-track";
2073
2074 link=document.getElementById(routing_type + "_gpx_route");
2075 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-route";
2076
2077 link=document.getElementById(routing_type + "_text_all");
2078 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=text-all";
2079
2080 link=document.getElementById(routing_type + "_text");
2081 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=text";
2082
2083 document.getElementById(routing_type + "_links").style.display = "";
2084
2085 // Add a GPX layer
2086
2087 var url="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-track";
2088
2089 layerGPX[routing_type] = new OpenLayers.Layer.Vector("GPX (" + routing_type + ")",
2090 {
2091 displayInLayerSwitcher: false,
2092 protocol: new OpenLayers.Protocol.HTTP({url: url, format: new OpenLayers.Format.GPX()}),
2093 strategies: [new OpenLayers.Strategy.Fixed()],
2094 style: gpx_style[routing_type],
2095 projection: map.displayProjection
2096 });
2097
2098 map.addLayer(layerGPX[routing_type]);
2099
2100 hideshow_show(routing_type);
2101
2102 displayResult(routing_type,uuid);
2103 }
2104
2105
2106 //
2107 // Failure in running router.
2108 //
2109
2110 function runRouterFailure(response)
2111 {
2112 displayStatus("result","failed");
2113 }
2114
2115
2116 //
2117 // Display the status
2118 //
2119
2120 function displayStatus(type,subtype,content)
2121 {
2122 var child=document.getElementById(type + "_status").firstChild;
2123
2124 do
2125 {
2126 if(child.id !== undefined)
2127 child.style.display="none";
2128
2129 child=child.nextSibling;
2130 }
2131 while(child !== null);
2132
2133 var chosen_status=document.getElementById(type + "_status_" + subtype);
2134
2135 chosen_status.style.display="";
2136
2137 if(content !== undefined)
2138 chosen_status.innerHTML=content;
2139 }
2140
2141
2142 //
2143 // Display the route
2144 //
2145
2146 function displayResult(type,uuid)
2147 {
2148 routing_type = type;
2149
2150 // Add the route
2151
2152 var url="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=html";
2153
2154 // Use AJAX to get the route
2155
2156 ajaxGET(url, getRouteSuccess, getRouteFailure);
2157 }
2158
2159
2160 //
2161 // Success in getting route.
2162 //
2163
2164 function getRouteSuccess(response)
2165 {
2166 var lines=response.responseText.split("\n");
2167
2168 routepoints[routing_type]=[];
2169
2170 var points=routepoints[routing_type];
2171
2172 var table=0;
2173 var point=0;
2174 var total_table,total_word;
2175
2176 for(var line=0;line<lines.length;line++)
2177 {
2178 var thisline=lines[line];
2179
2180 if(table===0)
2181 {
2182 if(thisline.match("<table>"))
2183 table=1;
2184 else
2185 continue;
2186 }
2187
2188 if(thisline.match("</table>"))
2189 break;
2190
2191 if(thisline.match("<tr class='([a-z])'>"))
2192 {
2193 var rowtype=RegExp.$1;
2194
2195 if(rowtype=="c")
2196 {
2197 thisline.match(": *([-0-9.]+) *([-0-9.]+)");
2198 points[point]={lat: Number(RegExp.$1), lon: Number(RegExp.$2), html: "", highway: "", distance: "", total: ""};
2199
2200 point++;
2201 }
2202 else if(rowtype=="n")
2203 {
2204 points[point-1].html += thisline;
2205 }
2206 else if(rowtype=="s")
2207 {
2208 thisline.match("<span class='h'>([^<]+)</span>");
2209 points[point-1].highway = RegExp.$1;
2210
2211 thisline.match("<span class='d'>([^<]+)</span>");
2212 points[point-1].distance = RegExp.$1;
2213
2214 thisline.match("(<span class='j'>[^<]+</span>)");
2215 points[point-1].total = RegExp.$1;
2216
2217 thisline.match("^(.*).<span class='j'>");
2218
2219 points[point-1].html += RegExp.$1;
2220 }
2221 else if(rowtype=="t")
2222 {
2223 points[point-1].html += thisline;
2224
2225 thisline.match("<span class='j'>([^<]+)</span>");
2226 points[point-1].total = RegExp.$1;
2227
2228 thisline.match("<td>(.*)");
2229 points[point-1].highway = RegExp.$1;
2230 }
2231 }
2232 }
2233
2234 displayStatus(routing_type,"info",points[point-1].total.bold());
2235
2236 var result="<table onmouseout='highlight(\"" + routing_type + "\",-1,\"clear\")'>";
2237
2238 for(var p=0;p<point;p++)
2239 {
2240 if(p!=point-1)
2241 points[p].html += "<tr><td>" + points[p].total;
2242
2243 result=result + "<tr onmouseover='highlight(\"" + routing_type + "\"," + p + ",\"show\")' " +
2244 "onclick='highlight(\"" + routing_type + "\"," + p + ",\"zoom\")'>" +
2245 "<td class='distance' title='" + points[p].distance + "'>#" + (p+1) +
2246 "<td class='highway'>" + points[p].highway;
2247 }
2248
2249 result=result + "</table>";
2250
2251 document.getElementById(routing_type + "_route").innerHTML=result;
2252 }
2253
2254
2255 //
2256 // Failure in getting route.
2257 //
2258
2259 function getRouteFailure(response)
2260 {
2261 document.getElementById(routing_type + "_route").innerHTML = "";
2262 }
2263
2264
2265 //
2266 // Perform a search
2267 //
2268
2269 function DoSearch(marker)
2270 {
2271 // Use AJAX to get the search result
2272
2273 var search=routino.point[marker].search;
2274
2275 var mapbounds=map.getExtent().clone();
2276 mapbounds.transform(epsg900913,epsg4326);
2277
2278 var url="search.cgi";
2279
2280 url=url + "?marker=" + marker;
2281 url=url + ";lonmin=" + format5f(mapbounds.left);
2282 url=url + ";latmin=" + format5f(mapbounds.bottom);
2283 url=url + ";lonmax=" + format5f(mapbounds.right);
2284 url=url + ";latmax=" + format5f(mapbounds.top);
2285 url=url + ";search=" + encodeURIComponent(search);
2286
2287 ajaxGET(url,runSearchSuccess);
2288 }
2289
2290
2291 var searchresults=[];
2292
2293 //
2294 // Success in running search.
2295 //
2296
2297 function runSearchSuccess(response)
2298 {
2299 var lines=response.responseText.split("\n");
2300
2301 var marker=lines[0];
2302 var cpuinfo=lines[1]; // not used
2303 var message=lines[2];
2304
2305 if(message !== "")
2306 {
2307 alert(message);
2308 return;
2309 }
2310
2311 searchresults[marker]=[];
2312
2313 for(var line=3;line<lines.length;line++)
2314 {
2315 var thisline=lines[line];
2316
2317 if(thisline==="")
2318 break;
2319
2320 thisline.match("([-.0-9]+) ([-.0-9]+) (.*)");
2321
2322 searchresults[marker][searchresults[marker].length]={lat: Number(RegExp.$1), lon: Number(RegExp.$2), name: RegExp.$3};
2323 }
2324
2325 if(searchresults[marker].length==1)
2326 {
2327 formSetSearch(marker,searchresults[marker][0].name);
2328 formSetCoords(marker,searchresults[marker][0].lon,searchresults[marker][0].lat);
2329 markerAddMap(marker);
2330 }
2331 else
2332 {
2333 var results=document.getElementById("searchresults" + marker);
2334
2335 var innerHTML="<td colspan=\"3\">";
2336
2337 for(var n=0;n<searchresults[marker].length;n++)
2338 {
2339 if(n>0)
2340 innerHTML+="<br>";
2341
2342 innerHTML+="<a href=\"#\" onclick=\"choseSearchResult(" + marker + "," + n + ")\">" +
2343 searchresults[marker][n].name +
2344 "</a>";
2345 }
2346
2347 results.innerHTML=innerHTML;
2348
2349 results.style.display="";
2350 }
2351 }
2352
2353
2354 //
2355 // Display search results.
2356 //
2357
2358 function choseSearchResult(marker,n)
2359 {
2360 if(n>=0)
2361 {
2362 formSetSearch(marker,searchresults[marker][n].name);
2363 formSetCoords(marker,searchresults[marker][n].lon,searchresults[marker][n].lat);
2364 markerAddMap(marker);
2365 }
2366 }
2367
2368
2369 //
2370 // Clear search results.
2371 //
2372
2373 function clearSearchResult(marker)
2374 {
2375 document.getElementById("searchresults" + marker).style.display="none";
2376 }