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 1830 - (show annotations) (download) (as text)
Sat Oct 24 15:04:31 2015 UTC (9 years, 5 months ago) by amb
File MIME type: application/javascript
File size: 56205 byte(s)
Print an error message if the geolocation function fails or is
unavailable.

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