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 1877 - (show annotations) (download) (as text)
Thu Apr 7 18:40:48 2016 UTC (8 years, 11 months ago) by amb
File MIME type: application/javascript
File size: 56461 byte(s)
Move the two route buttons to be just below the waypoints so they are
less likely to scroll off the screen.  Add another pair of route
buttons on the results tab to make it quicker to re-calculate a route
after moving the waypoints.

1 //
2 // Routino router web page Javascript
3 //
4 // Part of the Routino routing software.
5 //
6 // This file Copyright 2008-2016 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("shortest1").disabled="disabled";
1456 document.getElementById("quickest1").disabled="disabled";
1457 document.getElementById("shortest2").disabled="disabled";
1458 document.getElementById("quickest2").disabled="disabled";
1459 }
1460 else
1461 {
1462 document.getElementById("shortest1").disabled="";
1463 document.getElementById("quickest1").disabled="";
1464 document.getElementById("shortest2").disabled="";
1465 document.getElementById("quickest2").disabled="";
1466 }
1467 }
1468
1469
1470 //
1471 // Update an icon to set colours and home or normal marker.
1472 //
1473
1474 function updateIcon(marker)
1475 {
1476 if(routino.point[marker].home)
1477 {
1478 if(routino.point[marker].active)
1479 document.getElementById("icon" + marker).src="icons/marker-home-red.png";
1480 else
1481 document.getElementById("icon" + marker).src="icons/marker-home-grey.png";
1482
1483 markers[marker].style.externalGraphic="icons/marker-home-red.png";
1484 }
1485 else
1486 {
1487 if(routino.point[marker].active)
1488 document.getElementById("icon" + marker).src="icons/marker-" + marker + "-red.png";
1489 else
1490 document.getElementById("icon" + marker).src="icons/marker-" + marker + "-grey.png";
1491
1492 markers[marker].style.externalGraphic="icons/marker-" + marker + "-red.png";
1493 }
1494
1495 layerVectors.drawFeature(markers[marker]);
1496 }
1497
1498
1499 //
1500 // Move the marker to the home location
1501 //
1502
1503 function markerMoveHome(marker)
1504 {
1505 if(homelon===null || homelat===null)
1506 return;
1507
1508 routino.point[marker].home=true;
1509 routino.point[marker].used=true;
1510
1511 formSetCoords(marker,homelon,homelat);
1512 markerAddMap(marker);
1513 }
1514
1515
1516 //
1517 // Set or clear the home marker icon
1518 //
1519
1520 function markerSetClearHome(marker,home)
1521 {
1522 var cookie;
1523 var date = new Date();
1524
1525 if(home)
1526 {
1527 homelat=format5f(routino.point[marker].lat);
1528 homelon=format5f(routino.point[marker].lon);
1529
1530 cookie="Routino-home=lon:" + homelon + ":lat:" + homelat;
1531
1532 date.setUTCFullYear(date.getUTCFullYear()+5);
1533
1534 routino.point[marker].home=true;
1535 }
1536 else
1537 {
1538 homelat=null;
1539 homelon=null;
1540
1541 cookie="Routino-home=unset";
1542
1543 date.setUTCFullYear(date.getUTCFullYear()-1);
1544
1545 routino.point[marker].home=false;
1546 }
1547
1548 document.cookie=cookie + ";expires=" + date.toGMTString();
1549
1550 updateIcon(marker);
1551
1552 for(var m=1;m<=mapprops.maxmarkers;m++)
1553 markerCheckHome(m);
1554 }
1555
1556
1557 //
1558 // Check if a marker is the home marker
1559 //
1560
1561 function markerCheckHome(marker)
1562 {
1563 var home=routino.point[marker].home;
1564
1565 if(routino.point[marker].lon==homelon && routino.point[marker].lat==homelat)
1566 routino.point[marker].home=true;
1567 else
1568 routino.point[marker].home=false;
1569
1570 if(home!=routino.point[marker].home)
1571 updateIcon(marker);
1572 }
1573
1574
1575 //
1576 // Move this marker up.
1577 //
1578
1579 function markerMoveUp(marker) // called from router.html
1580 {
1581 if(marker==1)
1582 {
1583 for(var m=1;m<vismarkers;m++)
1584 markerSwap(m,m+1);
1585 }
1586 else
1587 markerSwap(marker,marker-1);
1588 }
1589
1590
1591 //
1592 // Move this marker down.
1593 //
1594
1595 function markerMoveDown(marker) // called from router.html
1596 {
1597 if(marker==vismarkers)
1598 {
1599 for(var m=vismarkers;m>1;m--)
1600 markerSwap(m,m-1);
1601 }
1602 else
1603 markerSwap(marker,marker+1);
1604 }
1605
1606
1607 //
1608 // Copy a marker from one place to another.
1609 //
1610
1611 function markerCopy(marker1,marker2)
1612 {
1613 for(var element in routino.point[marker2])
1614 routino.point[marker1][element]=routino.point[marker2][element];
1615
1616 document.getElementById("search" + marker1).style.display=document.getElementById("search" + marker2).style.display;
1617
1618 document.getElementById("coords" + marker1).style.display=document.getElementById("coords" + marker2).style.display;
1619
1620 document.forms["form"].elements["search" + marker1].value=document.forms["form"].elements["search" + marker2].value;
1621
1622 formSetCoords(marker1,routino.point[marker1].lon,routino.point[marker1].lat);
1623
1624 markerAddRemoveMap(marker1,routino.point[marker1].active);
1625 }
1626
1627
1628 //
1629 // Swap a pair of markers.
1630 //
1631
1632 function markerSwap(marker1,marker2)
1633 {
1634 for(var element in routino.point[marker2])
1635 {
1636 var temp=routino.point[marker1][element];
1637 routino.point[marker1][element]=routino.point[marker2][element];
1638 routino.point[marker2][element]=temp;
1639 }
1640
1641 var search_display=document.getElementById("search" + marker1).style.display;
1642 document.getElementById("search" + marker1).style.display=document.getElementById("search" + marker2).style.display;
1643 document.getElementById("search" + marker2).style.display=search_display;
1644
1645 var coords_display=document.getElementById("coords" + marker1).style.display;
1646 document.getElementById("coords" + marker1).style.display=document.getElementById("coords" + marker2).style.display;
1647 document.getElementById("coords" + marker2).style.display=coords_display;
1648
1649 var search_value=document.forms["form"].elements["search" + marker1].value;
1650 document.forms["form"].elements["search" + marker1].value=document.forms["form"].elements["search" + marker2].value;
1651 document.forms["form"].elements["search" + marker2].value=search_value;
1652
1653 formSetCoords(marker1,routino.point[marker1].lon,routino.point[marker1].lat);
1654 formSetCoords(marker2,routino.point[marker2].lon,routino.point[marker2].lat);
1655
1656 markerAddRemoveMap(marker1,routino.point[marker1].active);
1657 markerAddRemoveMap(marker2,routino.point[marker2].active);
1658 }
1659
1660
1661 //
1662 // Reverse the markers.
1663 //
1664
1665 function markersReverse() // called from router.html
1666 {
1667 for(var marker=1;marker<=vismarkers/2;marker++)
1668 markerSwap(marker,vismarkers+1-marker);
1669
1670 markersmoved=true;
1671
1672 updateURLs();
1673 }
1674
1675
1676 //
1677 // Close the loop.
1678 //
1679
1680 function markersLoop() // called from router.html
1681 {
1682 if(vismarkers==mapprops.maxmarkers)
1683 return false;
1684
1685 if(routino.point[vismarkers].lon==routino.point[1].lon && routino.point[vismarkers].lat==routino.point[1].lat)
1686 {
1687 if(routino.point[vismarkers].active)
1688 return false;
1689 else
1690 {
1691 markerToggleMap(vismarkers);
1692 return true;
1693 }
1694 }
1695
1696 if(routino.point[vismarkers].used)
1697 markerAddForm(++vismarkers);
1698
1699 markerCopy(vismarkers,1);
1700
1701 markersmoved=true;
1702
1703 updateURLs();
1704
1705 updateSearchButtons();
1706 }
1707
1708
1709 //
1710 // Display the form for a marker
1711 //
1712
1713 function markerAddForm(marker)
1714 {
1715 document.getElementById("waypoint" + marker).style.display="";
1716 }
1717
1718
1719 //
1720 // Hide the form for a marker
1721 //
1722
1723 function markerRemoveForm(marker)
1724 {
1725 document.getElementById("waypoint" + marker).style.display="none";
1726
1727 markerClearForm(marker);
1728 }
1729
1730
1731 //
1732 // Clear the form for a marker
1733 //
1734
1735 function markerClearForm(marker)
1736 {
1737 markerRemoveMap(marker);
1738 markerCoords(marker);
1739
1740 formSetCoords(marker,"","");
1741 formSetSearch(marker,"");
1742
1743 updateIcon(marker);
1744
1745 routino.point[marker].used=false;
1746 routino.point[marker].home=false;
1747 routino.point[marker].active=false;
1748 }
1749
1750
1751 ////////////////////////////////////////////////////////////////////////////////
1752 //////////////////////////// Route results handling ////////////////////////////
1753 ////////////////////////////////////////////////////////////////////////////////
1754
1755 var route_light_colours={shortest: "#60C060", quickest: "#6060C0"};
1756 var route_dark_colours ={shortest: "#408040", quickest: "#404080"};
1757
1758 var highlights={shortest: null, quickest: null};
1759 var popups={shortest: null, quickest: null};
1760 var routepoints={shortest: {}, quickest: {}};
1761 var gpx_style={shortest: null, quickest: null};
1762
1763
1764 //
1765 // Highlight a specific item in the route
1766 //
1767
1768 function highlight(type,line,action)
1769 {
1770 if(action == "clear")
1771 {
1772 highlights[type].style.display = "none";
1773
1774 drawPopup(type,null);
1775 }
1776 else if(action == "zoom")
1777 {
1778 var lonlat = new OpenLayers.LonLat(routepoints[type][line].lon,routepoints[type][line].lat);
1779 lonlat.transform(epsg4326,epsg900913);
1780
1781 map.moveTo(lonlat,map.numZoomLevels-2);
1782 }
1783 else
1784 {
1785 // Marker
1786
1787 var lonlat = new OpenLayers.LonLat(routepoints[type][line].lon,routepoints[type][line].lat);
1788 lonlat.transform(epsg4326,epsg900913);
1789
1790 highlights[type].move(lonlat);
1791
1792 if(highlights[type].style.display == "none")
1793 highlights[type].style.display = "";
1794
1795 // Popup
1796
1797 drawPopup(type,"<table>" + routepoints[type][line].html + "</table>");
1798 }
1799
1800 layerVectors.drawFeature(highlights[type]);
1801 }
1802
1803
1804 //
1805 // Create a popup - independent of map because want it fixed on screen not fixed on map.
1806 //
1807
1808 function createPopup(type)
1809 {
1810 var popup=document.createElement("div");
1811
1812 popup.className = "popup";
1813
1814 popup.innerHTML = "<span></span>";
1815
1816 popup.style.display = "none";
1817
1818 popup.style.position = "fixed";
1819 popup.style.top = "-4000px";
1820 popup.style.left = "-4000px";
1821 popup.style.zIndex = "100";
1822
1823 popup.style.padding = "5px";
1824
1825 popup.style.opacity=0.85;
1826 popup.style.backgroundColor=route_light_colours[type];
1827 popup.style.border="4px solid " + route_dark_colours[type];
1828
1829 document.body.appendChild(popup);
1830
1831 return(popup);
1832 }
1833
1834
1835 //
1836 // Draw a popup - independent of map because want it fixed on screen not fixed on map.
1837 //
1838
1839 function drawPopup(type,html)
1840 {
1841 var popup=popups[type];
1842
1843 if(html===null)
1844 {
1845 popup.style.display="none";
1846 return;
1847 }
1848
1849 if(popup.style.display=="none")
1850 {
1851 var map_div=document.getElementById("map");
1852
1853 popup.style.left =map_div.offsetParent.offsetLeft+map_div.offsetLeft+60 + "px";
1854 popup.style.top = map_div.offsetTop +30 + "px";
1855 popup.style.width =map_div.clientWidth-120 + "px";
1856
1857 popup.style.display="";
1858 }
1859
1860 var close="<span style='float: right; cursor: pointer;' onclick='highlight(\""+type+"\",-1,\"clear\")'>X</span>";
1861
1862 popup.innerHTML=close+html;
1863 }
1864
1865
1866 //
1867 // Remove a GPX trace
1868 //
1869
1870 function removeGPXTrace(type)
1871 {
1872 map.removeLayer(layerGPX[type]);
1873 layerGPX[type].destroy();
1874 layerGPX[type]=null;
1875
1876 displayStatus(type,"no_info");
1877
1878 document.getElementById(type + "_links").style.display = "none";
1879
1880 document.getElementById(type + "_route").innerHTML = "";
1881
1882 hideshow_hide(type);
1883 }
1884
1885
1886 ////////////////////////////////////////////////////////////////////////////////
1887 /////////////////////////////// Server handling ////////////////////////////////
1888 ////////////////////////////////////////////////////////////////////////////////
1889
1890 //
1891 // Define an AJAX request object
1892 //
1893
1894 function ajaxGET(url,success,failure,state)
1895 {
1896 var ajaxRequest=new XMLHttpRequest();
1897
1898 function ajaxGOT(options) {
1899 if(this.readyState==4)
1900 if(this.status==200)
1901 { if(typeof(options.success)=="function") options.success(this,options.state); }
1902 else
1903 { if(typeof(options.failure)=="function") options.failure(this,options.state); }
1904 }
1905
1906 ajaxRequest.onreadystatechange = function(){ ajaxGOT.call(ajaxRequest,{success: success, failure: failure, state: state}); };
1907 ajaxRequest.open("GET", url, true);
1908 ajaxRequest.send(null);
1909 }
1910
1911
1912 //
1913 // Display data statistics
1914 //
1915
1916 function displayStatistics() // called from router.html
1917 {
1918 // Use AJAX to get the statistics
1919
1920 ajaxGET("statistics.cgi", runStatisticsSuccess);
1921 }
1922
1923
1924 //
1925 // Success in running data statistics generation.
1926 //
1927
1928 function runStatisticsSuccess(response)
1929 {
1930 document.getElementById("statistics_data").innerHTML="<pre>" + response.responseText + "</pre>";
1931 document.getElementById("statistics_link").style.display="none";
1932 }
1933
1934
1935 //
1936 // Submit form - perform the routing
1937 //
1938
1939 function findRoute(type) // called from router.html
1940 {
1941 tab_select("results");
1942
1943 hideshow_hide("help_options");
1944 hideshow_hide("shortest");
1945 hideshow_hide("quickest");
1946
1947 displayStatus("result","running");
1948
1949 var url="router.cgi" + "?" + buildURLArguments(true) + ";type=" + type;
1950
1951 // Destroy the existing layer(s)
1952
1953 highlight("shortest",-1,"clear");
1954 highlight("quickest",-1,"clear");
1955
1956 if(markersmoved || paramschanged)
1957 {
1958 if(layerGPX.shortest!==null)
1959 removeGPXTrace("shortest");
1960 if(layerGPX.quickest!==null)
1961 removeGPXTrace("quickest");
1962 markersmoved=false;
1963 paramschanged=false;
1964 }
1965 else if(layerGPX[type]!==null)
1966 removeGPXTrace(type);
1967
1968 // Use AJAX to run the router
1969
1970 routing_type=type;
1971
1972 ajaxGET(url, runRouterSuccess, runRouterFailure);
1973 }
1974
1975
1976 //
1977 // Success in running router.
1978 //
1979
1980 function runRouterSuccess(response)
1981 {
1982 var lines=response.responseText.split("\n");
1983
1984 var uuid=lines[0];
1985 var success=lines[1];
1986
1987 var link;
1988
1989 // Update the status message
1990
1991 if(success=="ERROR")
1992 {
1993 displayStatus("result","error");
1994 hideshow_show("help_route");
1995
1996 link=document.getElementById("router_log_error");
1997 link.href="results.cgi?uuid=" + uuid + ";type=router;format=log";
1998
1999 return;
2000 }
2001 else
2002 {
2003 displayStatus("result","complete");
2004 hideshow_hide("help_route");
2005
2006 link=document.getElementById("router_log_complete");
2007 link.href="results.cgi?uuid=" + uuid + ";type=router;format=log";
2008 }
2009
2010 // Update the routing result message
2011
2012 link=document.getElementById(routing_type + "_html");
2013 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=html";
2014
2015 link=document.getElementById(routing_type + "_gpx_track");
2016 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-track";
2017
2018 link=document.getElementById(routing_type + "_gpx_route");
2019 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-route";
2020
2021 link=document.getElementById(routing_type + "_text_all");
2022 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=text-all";
2023
2024 link=document.getElementById(routing_type + "_text");
2025 link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=text";
2026
2027 document.getElementById(routing_type + "_links").style.display = "";
2028
2029 // Add a GPX layer
2030
2031 var url="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-track";
2032
2033 layerGPX[routing_type] = new OpenLayers.Layer.Vector("GPX (" + routing_type + ")",
2034 {
2035 displayInLayerSwitcher: false,
2036 protocol: new OpenLayers.Protocol.HTTP({url: url, format: new OpenLayers.Format.GPX()}),
2037 strategies: [new OpenLayers.Strategy.Fixed()],
2038 style: gpx_style[routing_type],
2039 projection: map.displayProjection
2040 });
2041
2042 map.addLayer(layerGPX[routing_type]);
2043
2044 hideshow_show(routing_type);
2045
2046 displayResult(routing_type,uuid);
2047 }
2048
2049
2050 //
2051 // Failure in running router.
2052 //
2053
2054 function runRouterFailure(response)
2055 {
2056 displayStatus("result","failed");
2057 }
2058
2059
2060 //
2061 // Display the status
2062 //
2063
2064 function displayStatus(type,subtype,content)
2065 {
2066 var child=document.getElementById(type + "_status").firstChild;
2067
2068 do
2069 {
2070 if(child.id !== undefined)
2071 child.style.display="none";
2072
2073 child=child.nextSibling;
2074 }
2075 while(child !== null);
2076
2077 var chosen_status=document.getElementById(type + "_status_" + subtype);
2078
2079 chosen_status.style.display="";
2080
2081 if(content !== undefined)
2082 chosen_status.innerHTML=content;
2083 }
2084
2085
2086 //
2087 // Display the route
2088 //
2089
2090 function displayResult(type,uuid)
2091 {
2092 routing_type = type;
2093
2094 // Add the route
2095
2096 var url="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=html";
2097
2098 // Use AJAX to get the route
2099
2100 ajaxGET(url, getRouteSuccess, getRouteFailure);
2101 }
2102
2103
2104 //
2105 // Success in getting route.
2106 //
2107
2108 function getRouteSuccess(response)
2109 {
2110 var lines=response.responseText.split("\n");
2111
2112 routepoints[routing_type]=[];
2113
2114 var points=routepoints[routing_type];
2115
2116 var table=0;
2117 var point=0;
2118 var total_table,total_word;
2119
2120 for(var line=0;line<lines.length;line++)
2121 {
2122 var thisline=lines[line];
2123
2124 if(table===0)
2125 {
2126 if(thisline.match("<table>"))
2127 table=1;
2128 else
2129 continue;
2130 }
2131
2132 if(thisline.match("</table>"))
2133 break;
2134
2135 if(thisline.match("<tr class='([a-z])'>"))
2136 {
2137 var rowtype=RegExp.$1;
2138
2139 if(rowtype=="c")
2140 {
2141 thisline.match(": *([-0-9.]+) *([-0-9.]+)");
2142 points[point]={lat: Number(RegExp.$1), lon: Number(RegExp.$2), html: "", highway: "", distance: "", total: ""};
2143
2144 point++;
2145 }
2146 else if(rowtype=="n")
2147 {
2148 points[point-1].html += thisline;
2149 }
2150 else if(rowtype=="s")
2151 {
2152 thisline.match("<span class='h'>([^<]+)</span>");
2153 points[point-1].highway = RegExp.$1;
2154
2155 thisline.match("<span class='d'>([^<]+)</span>");
2156 points[point-1].distance = RegExp.$1;
2157
2158 thisline.match("(<span class='j'>[^<]+</span>)");
2159 points[point-1].total = RegExp.$1;
2160
2161 thisline.match("^(.*).<span class='j'>");
2162
2163 points[point-1].html += RegExp.$1;
2164 }
2165 else if(rowtype=="t")
2166 {
2167 points[point-1].html += thisline;
2168
2169 thisline.match("<span class='j'>([^<]+)</span>");
2170 points[point-1].total = RegExp.$1;
2171
2172 thisline.match("<td>(.*)");
2173 points[point-1].highway = RegExp.$1;
2174 }
2175 }
2176 }
2177
2178 displayStatus(routing_type,"info",points[point-1].total.bold());
2179
2180 var result="<table onmouseout='highlight(\"" + routing_type + "\",-1,\"clear\")'>";
2181
2182 for(var p=0;p<point;p++)
2183 {
2184 if(p!=point-1)
2185 points[p].html += "<tr><td>" + points[p].total;
2186
2187 result=result + "<tr onmouseover='highlight(\"" + routing_type + "\"," + p + ",\"show\")' " +
2188 "onclick='highlight(\"" + routing_type + "\"," + p + ",\"zoom\")'>" +
2189 "<td class='distance' title='" + points[p].distance + "'>#" + (p+1) +
2190 "<td class='highway'>" + points[p].highway;
2191 }
2192
2193 result=result + "</table>";
2194
2195 document.getElementById(routing_type + "_route").innerHTML=result;
2196 }
2197
2198
2199 //
2200 // Failure in getting route.
2201 //
2202
2203 function getRouteFailure(response)
2204 {
2205 document.getElementById(routing_type + "_route").innerHTML = "";
2206 }
2207
2208
2209 //
2210 // Perform a search
2211 //
2212
2213 function DoSearch(marker)
2214 {
2215 // Use AJAX to get the search result
2216
2217 var search=routino.point[marker].search;
2218
2219 var mapbounds=map.getExtent().clone();
2220 mapbounds.transform(epsg900913,epsg4326);
2221
2222 var url="search.cgi";
2223
2224 url=url + "?marker=" + marker;
2225 url=url + ";lonmin=" + format5f(mapbounds.left);
2226 url=url + ";latmin=" + format5f(mapbounds.bottom);
2227 url=url + ";lonmax=" + format5f(mapbounds.right);
2228 url=url + ";latmax=" + format5f(mapbounds.top);
2229 url=url + ";search=" + encodeURIComponent(search);
2230
2231 ajaxGET(url,runSearchSuccess);
2232 }
2233
2234
2235 var searchresults=[];
2236
2237 //
2238 // Success in running search.
2239 //
2240
2241 function runSearchSuccess(response)
2242 {
2243 var lines=response.responseText.split("\n");
2244
2245 var marker=lines[0];
2246 var cpuinfo=lines[1]; // not used
2247 var message=lines[2];
2248
2249 if(message !== "")
2250 {
2251 alert(message);
2252 return;
2253 }
2254
2255 searchresults[marker]=[];
2256
2257 for(var line=3;line<lines.length;line++)
2258 {
2259 var thisline=lines[line];
2260
2261 if(thisline==="")
2262 break;
2263
2264 thisline.match("([-.0-9]+) ([-.0-9]+) (.*)");
2265
2266 searchresults[marker][searchresults[marker].length]={lat: Number(RegExp.$1), lon: Number(RegExp.$2), name: RegExp.$3};
2267 }
2268
2269 if(searchresults[marker].length==1)
2270 {
2271 formSetSearch(marker,searchresults[marker][0].name);
2272 formSetCoords(marker,searchresults[marker][0].lon,searchresults[marker][0].lat);
2273 markerAddMap(marker);
2274 }
2275 else
2276 {
2277 var results=document.getElementById("searchresults" + marker);
2278
2279 var innerHTML="<td colspan=\"3\">";
2280
2281 for(var n=0;n<searchresults[marker].length;n++)
2282 {
2283 if(n>0)
2284 innerHTML+="<br>";
2285
2286 innerHTML+="<a href=\"#\" onclick=\"choseSearchResult(" + marker + "," + n + ")\">" +
2287 searchresults[marker][n].name +
2288 "</a>";
2289 }
2290
2291 results.innerHTML=innerHTML;
2292
2293 results.style.display="";
2294 }
2295 }
2296
2297
2298 //
2299 // Display search results.
2300 //
2301
2302 function choseSearchResult(marker,n)
2303 {
2304 if(n>=0)
2305 {
2306 formSetSearch(marker,searchresults[marker][n].name);
2307 formSetCoords(marker,searchresults[marker][n].lon,searchresults[marker][n].lat);
2308 markerAddMap(marker);
2309 }
2310 }
2311
2312
2313 //
2314 // Clear search results.
2315 //
2316
2317 function clearSearchResult(marker)
2318 {
2319 document.getElementById("searchresults" + marker).style.display="none";
2320 }