Routino SVN Repository Browser

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

ViewVC logotype

Annotation of /trunk/web/www/routino/router.openlayers.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2064 - (hide 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: 55375 byte(s)
Fix errors when zooming to the markers from the URL for openlayers.

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