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.openlayers.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: 55375 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=ol.extent.boundingExtent([ol.proj.fromLonLat([minlon,minlat]),
274 ol.proj.fromLonLat([maxlon,maxlat])]);
275
276 map.getView().fit(markerextent);
277 }
278 }
279
280 // 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 if(cookies[cookie].startsWith("Routino-home"))
328 {
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 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
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 // Add a markers vectors layer
908
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 cookie="Routino-home=";
1558
1559 date.setUTCFullYear(date.getUTCFullYear()-1);
1560
1561 routino.point[marker].home=false;
1562 }
1563
1564 document.cookie=cookie + ";Expires=" + date.toGMTString() + ";SameSite=Strict";
1565
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 }