Imported Upstream version 1.4.1
[routino] / web / www / routino / visualiser.js
1 //
2 // Routino data visualiser web page Javascript
3 //
4 // Part of the Routino routing software.
5 //
6 // This file Copyright 2008-2010 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 //
24 // Data types
25 //
26
27 var data_types=[
28                 "junctions",
29                 "super",
30                 "oneway",
31                 "speed",
32                 "weight",
33                 "height",
34                 "width",
35                 "length"
36                ];
37
38
39 //
40 // Junction styles
41 //
42
43 var junction_colours={
44                       0: "#FFFFFF",
45                       1: "#FF0000",
46                       2: "#FFFF00",
47                       3: "#00FF00",
48                       4: "#8B4513",
49                       5: "#00BFFF",
50                       6: "#FF69B4",
51                       7: "#000000",
52                       8: "#000000",
53                       9: "#000000"
54                      };
55
56 var junction_styles={};
57
58
59 //
60 // Super styles
61 //
62
63 var super_node_style,super_segment_style;
64
65
66 //
67 // Oneway styles
68 //
69
70 var hex={0: "00", 1: "11",  2: "22",  3: "33",  4: "44",  5: "55",  6: "66",  7: "77",
71          8: "88", 9: "99", 10: "AA", 11: "BB", 12: "CC", 13: "DD", 14: "EE", 15: "FF"};
72
73
74 ////////////////////////////////////////////////////////////////////////////////
75 ///////////////////////////////// Map handling /////////////////////////////////
76 ////////////////////////////////////////////////////////////////////////////////
77
78 var map;
79 var layerMapOSM, layerVectors, layerBoxes;
80 var epsg4326, epsg900913;
81 var map_args;
82
83 var box;
84
85 // 
86 // Initialise the 'map' object
87 //
88
89 function map_init(lat,lon,zoom)
90 {
91  // Default configuration:
92  // UK coordinate range
93  // West -11.0, South 49.5, East 2.0, North 61.0
94  // Zoom level 4 to 15
95
96  // EDIT THIS below to change the visible map limits
97
98  var westedge  = -11.0;          // Minimum longitude (degrees)
99  var eastedge  =   2.0;          // Maximum longitude (degrees)
100  var southedge =  49.5;          // Minimum latitude (degrees)
101  var northedge =  61.0;          // Maximum latitude (degrees)
102  var zoomout   =     4;          // Minimum zoom
103  var zoomin    =    15;          // Maximum zoom
104
105  // EDIT THIS above to change the visible map limits
106
107  //
108  // Create the map
109  //
110
111  epsg4326=new OpenLayers.Projection("EPSG:4326");
112  epsg900913=new OpenLayers.Projection("EPSG:900913");
113
114  map = new OpenLayers.Map ("map",
115                            {
116                             controls:[
117                                       new OpenLayers.Control.Navigation(),
118                                       new OpenLayers.Control.PanZoomBar(),
119                                       new OpenLayers.Control.ScaleLine(),
120                                       new OpenLayers.Control.LayerSwitcher()
121                                       ],
122
123                             projection: epsg900913,
124                             displayProjection: epsg4326,
125
126                             minZoomLevel: zoomout,
127                             numZoomLevels: zoomin-zoomout+1,
128                             maxResolution: 156543.0339 / Math.pow(2,zoomout),
129
130                             maxExtent:        new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
131                             restrictedExtent: new OpenLayers.Bounds(westedge,southedge,eastedge,northedge).transform(epsg4326,epsg900913),
132
133                             units: "m"
134                            });
135
136  map.events.register("moveend", map, mapMoved);
137
138  // Add a map tile layer (OpenStreetMap tiles, direct access)
139
140  layerMapOSM = new OpenLayers.Layer.TMS("Original OSM map",
141                                         "http://tile.openstreetmap.org/",
142                                         {
143                                          emptyUrl: "http://openstreetmap.org/openlayers/img/404.png",
144                                          type: 'png',
145                                          getURL: limitedUrl,
146                                          displayOutsideMaxExtent: true,
147                                          buffer: 1
148                                         });
149  map.addLayer(layerMapOSM);
150
151  // Get a URL for the tile; limited to map restricted extent.
152
153  function limitedUrl(bounds)
154  {
155   var z = map.getZoom() + map.minZoomLevel;
156
157   if (z>=7 && (bounds.right  < map.restrictedExtent.left ||
158                bounds.left   > map.restrictedExtent.right ||
159                bounds.top    < map.restrictedExtent.bottom ||
160                bounds.bottom > map.restrictedExtent.top))
161      return this.emptyUrl;
162
163   var res = map.getResolution();
164   var y = Math.round((this.maxExtent.top - bounds.top) / (res * this.tileSize.h));
165   var limit = Math.pow(2, z);
166
167   if (y < 0 || y >= limit)
168     return this.emptyUrl;
169
170   var x = Math.round((bounds.left - this.maxExtent.left) / (res * this.tileSize.w));
171
172   x = ((x % limit) + limit) % limit;
173   return this.url + z + "/" + x + "/" + y + "." + this.type;
174  }
175
176  // Add a vectors layer
177  
178  layerVectors = new OpenLayers.Layer.Vector("Markers");
179  map.addLayer(layerVectors);
180
181  for(var colour in junction_colours)
182     junction_styles[colour]=new OpenLayers.Style({},{stroke: false, pointRadius: 2,fillColor: junction_colours[colour]});
183
184  super_node_style   =new OpenLayers.Style({},{stroke: false, pointRadius: 3,fillColor  : "#FF0000"});
185  super_segment_style=new OpenLayers.Style({},{fill: false  , strokeWidth: 2,strokeColor: "#FF0000"});
186
187  // Add a boxes layer
188
189  layerBoxes = new OpenLayers.Layer.Boxes("Boundary");
190  map.addLayer(layerBoxes);
191
192  box=null;
193
194  // Set the map centre to the limited range specified
195
196  map.setCenter(map.restrictedExtent.getCenterLonLat(), map.getZoomForExtent(map.restrictedExtent,true));
197  map.maxResolution = map.getResolution();
198
199  // Move the map
200
201  if(lon != 'lon' && lat != 'lat' && zoom != 'zoom')
202    {
203     var lonlat = new OpenLayers.LonLat(lon,lat).transform(epsg4326,map.getProjectionObject());
204
205     map.moveTo(lonlat,zoom-map.minZoomLevel);
206    }
207 }
208
209
210 //
211 // Map has moved
212 //
213
214 function mapMoved()
215 {
216  var centre = map.getCenter().clone();
217
218  var lonlat = centre.transform(map.getProjectionObject(),epsg4326);
219
220  var zoom = this.getZoom() + map.minZoomLevel;
221
222  map_args="lat=" + lonlat.lat + ";lon=" + lonlat.lon + ";zoom=" + zoom;
223
224  updateCustomURL();
225 }
226
227
228 //
229 // Update custom URL
230 //
231
232 function updateCustomURL()
233 {
234  var router_url=document.getElementById("router_url");
235  var link_url  =document.getElementById("link_url");
236  var edit_url  =document.getElementById("edit_url");
237
238  router_url.href="customrouter.cgi?" + map_args;
239  link_url.href="customvisualiser.cgi?" + map_args;
240  edit_url.href="http://www.openstreetmap.org/edit?" + map_args;
241 }
242
243
244 ////////////////////////////////////////////////////////////////////////////////
245 /////////////////////////////// Server handling ////////////////////////////////
246 ////////////////////////////////////////////////////////////////////////////////
247
248 //
249 // Display data statistics
250 //
251
252 function displayStatistics()
253 {
254  // Use AJAX to get the statistics
255
256  OpenLayers.loadURL("statistics.cgi",null,null,runStatisticsSuccess);
257 }
258
259
260 //
261 // Success in running data statistics generation.
262 //
263
264 function runStatisticsSuccess(response)
265 {
266  var statistics_data=document.getElementById("statistics_data");
267  var statistics_link=document.getElementById("statistics_link");
268
269  statistics_data.innerHTML="<pre>" + response.responseText + "</pre>";
270
271  statistics_link.style.display="none";
272 }
273
274
275 //
276 // Get the requested data
277 //
278
279 function displayData(datatype)
280 {
281  for(var data in data_types)
282     hideshow_hide(data_types[data]);
283
284  if(datatype != "")
285     hideshow_show(datatype);
286
287  // Delete the old data
288
289  layerVectors.destroyFeatures();
290
291  if(box != null)
292     layerBoxes.removeMarker(box);
293  box=null;
294
295  // Print the status
296
297  var div_status=document.getElementById("result_status");
298  div_status.innerHTML = "No data displayed";
299
300  // Return if just here to clear the data
301
302  if(datatype == "")
303     return;
304
305  // Get the new data
306
307  var mapbounds=map.getExtent().clone();
308  mapbounds.transform(epsg900913,epsg4326);
309
310  var url="visualiser.cgi";
311
312  url=url + "?lonmin=" + mapbounds.left;
313  url=url + ";latmin=" + mapbounds.bottom;
314  url=url + ";lonmax=" + mapbounds.right;
315  url=url + ";latmax=" + mapbounds.top;
316  url=url + ";data=" + datatype;
317
318  // Print the status
319
320  div_status.innerHTML = "Fetching " + datatype + " data ...";
321
322  // Use AJAX to get the data
323
324  switch(datatype)
325    {
326    case 'junctions':
327     OpenLayers.loadURL(url,null,null,runJunctionsSuccess,runFailure);
328     break;
329    case 'super':
330     OpenLayers.loadURL(url,null,null,runSuperSuccess,runFailure);
331     break;
332    case 'oneway':
333     OpenLayers.loadURL(url,null,null,runOnewaySuccess,runFailure);
334     break;
335    case 'speed':
336    case 'weight':
337    case 'height':
338    case 'width':
339    case 'length':
340     OpenLayers.loadURL(url,null,null,runLimitSuccess,runFailure);
341     break;
342    }
343 }
344
345
346 //
347 // Success in getting the junctions.
348 //
349
350 function runJunctionsSuccess(response)
351 {
352  var lines=response.responseText.split('\n');
353
354 // This won't update the browser window
355 // var div_status=document.getElementById("result_status");
356 // div_status.innerHTML = "Processing " + (lines.length-2) + " junctions ...";
357
358  var features=[];
359
360  for(var line=0;line<lines.length;line++)
361    {
362     var words=lines[line].split(' ');
363
364     if(line == 0)
365       {
366        var lat1=words[0];
367        var lon1=words[1];
368        var lat2=words[2];
369        var lon2=words[3];
370
371        var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,map.getProjectionObject());
372
373        box = new OpenLayers.Marker.Box(bounds);
374
375        layerBoxes.addMarker(box);
376       }
377     else if(words[0] != "")
378       {
379        var lat=words[0];
380        var lon=words[1];
381        var count=words[2];
382
383        var lonlat= new OpenLayers.LonLat(lon,lat).transform(epsg4326,epsg900913);
384
385        var point = new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);
386
387        features.push(new OpenLayers.Feature.Vector(point,{},junction_styles[count]));
388       }
389    }
390
391  layerVectors.addFeatures(features);
392
393  var div_status=document.getElementById("result_status");
394  div_status.innerHTML = "Processed " + (lines.length-2) + " junctions";
395 }
396
397
398 //
399 // Success in getting the super-node and super-segments
400 //
401
402 function runSuperSuccess(response)
403 {
404  var lines=response.responseText.split('\n');
405
406 // This won't update the browser window
407 // var div_status=document.getElementById("result_status");
408 // div_status.innerHTML = "Processing " + (lines.length-2) + " super-nodes/segments ...";
409
410  var features=[];
411
412  var nodepoint;
413
414  for(var line=0;line<lines.length;line++)
415    {
416     var words=lines[line].split(' ');
417
418     if(line == 0)
419       {
420        var lat1=words[0];
421        var lon1=words[1];
422        var lat2=words[2];
423        var lon2=words[3];
424
425        var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,map.getProjectionObject());
426
427        box = new OpenLayers.Marker.Box(bounds);
428
429        layerBoxes.addMarker(box);
430       }
431     else if(words[0] != "")
432       {
433        var lat=words[0];
434        var lon=words[1];
435        var type=words[2];
436
437        var lonlat= new OpenLayers.LonLat(lon,lat).transform(epsg4326,epsg900913);
438
439        var point = new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);
440
441        if(type == "n")
442          {
443           nodepoint=point;
444
445           features.push(new OpenLayers.Feature.Vector(point,{},super_node_style));
446          }
447        else
448          {
449           var segment = new OpenLayers.Geometry.LineString([nodepoint,point]);
450
451           features.push(new OpenLayers.Feature.Vector(segment,{},super_segment_style));
452          }
453       }
454    }
455
456  layerVectors.addFeatures(features);
457
458  var div_status=document.getElementById("result_status");
459  div_status.innerHTML = "Processed " + (lines.length-2) + " super-nodes/segments";
460 }
461
462
463 //
464 // Success in getting the oneway data
465 //
466
467 function runOnewaySuccess(response)
468 {
469  var lines=response.responseText.split('\n');
470
471 // This won't update the browser window
472 // var div_status=document.getElementById("result_status");
473 // div_status.innerHTML = "Processing " + (lines.length-2) + " oneway segments ...";
474
475  var features=[];
476
477  for(var line=0;line<lines.length;line++)
478    {
479     var words=lines[line].split(' ');
480
481     if(line == 0)
482       {
483        var lat1=words[0];
484        var lon1=words[1];
485        var lat2=words[2];
486        var lon2=words[3];
487
488        var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,map.getProjectionObject());
489
490        box = new OpenLayers.Marker.Box(bounds);
491
492        layerBoxes.addMarker(box);
493       }
494     else if(words[0] != "")
495       {
496        var lat1=words[0];
497        var lon1=words[1];
498        var lat2=words[2];
499        var lon2=words[3];
500
501        var lonlat1= new OpenLayers.LonLat(lon1,lat1).transform(epsg4326,epsg900913);
502        var lonlat2= new OpenLayers.LonLat(lon2,lat2).transform(epsg4326,epsg900913);
503
504      //var point1 = new OpenLayers.Geometry.Point(lonlat1.lon,lonlat1.lat);
505        var point2 = new OpenLayers.Geometry.Point(lonlat2.lon,lonlat2.lat);
506
507        var dlat = lonlat2.lat-lonlat1.lat;
508        var dlon = lonlat2.lon-lonlat1.lon;
509        var dist = Math.sqrt(dlat*dlat+dlon*dlon)/10;
510        var ang  = Math.atan2(dlat,dlon);
511
512        var point3 = new OpenLayers.Geometry.Point(lonlat1.lon+dlat/dist,lonlat1.lat-dlon/dist);
513        var point4 = new OpenLayers.Geometry.Point(lonlat1.lon-dlat/dist,lonlat1.lat+dlon/dist);
514
515        var segment = new OpenLayers.Geometry.LineString([point2,point3,point4,point2]);
516
517        var r=Math.round(7.5+7.9*Math.cos(ang));
518        var g=Math.round(7.5+7.9*Math.cos(ang+2.0943951));
519        var b=Math.round(7.5+7.9*Math.cos(ang-2.0943951));
520        var colour = "#" + hex[r] + hex[g] + hex[b];
521
522        var style=new OpenLayers.Style({},{strokeWidth: 2,strokeColor: colour});
523
524        features.push(new OpenLayers.Feature.Vector(segment,{},style));
525       }
526    }
527
528  layerVectors.addFeatures(features);
529
530  var div_status=document.getElementById("result_status");
531  div_status.innerHTML = "Processed " + (lines.length-2) + " oneway segments";
532 }
533
534
535 //
536 // Success in getting the speed/weight/height/width/length limits
537 //
538
539 function runLimitSuccess(response)
540 {
541  var lines=response.responseText.split('\n');
542
543 // This won't update the browser window
544 // var div_status=document.getElementById("result_status");
545 // div_status.innerHTML = "Processing " + (lines.length-2) + " limits ...";
546
547  var features=[];
548
549  var nodelonlat;
550
551  for(var line=0;line<lines.length;line++)
552    {
553     var words=lines[line].split(' ');
554
555     if(line == 0)
556       {
557        var lat1=words[0];
558        var lon1=words[1];
559        var lat2=words[2];
560        var lon2=words[3];
561
562        var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,map.getProjectionObject());
563
564        box = new OpenLayers.Marker.Box(bounds);
565
566        layerBoxes.addMarker(box);
567       }
568     else if(words[0] != "")
569       {
570        var lat=words[0];
571        var lon=words[1];
572        var number=words[2];
573
574        var lonlat= new OpenLayers.LonLat(lon,lat).transform(epsg4326,epsg900913);
575
576        if(number == undefined)
577          {
578           var point = new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);
579
580           nodelonlat=lonlat;
581
582           features.push(new OpenLayers.Feature.Vector(point,{},junction_styles[1]));
583          }
584        else
585          {
586           var dlat = lonlat.lat-nodelonlat.lat;
587           var dlon = lonlat.lon-nodelonlat.lon;
588           var dist = Math.sqrt(dlat*dlat+dlon*dlon)/60;
589
590           var point = new OpenLayers.Geometry.Point(nodelonlat.lon+dlon/dist,nodelonlat.lat+dlat/dist);
591
592           features.push(new OpenLayers.Feature.Vector(point,{},
593                                                       new OpenLayers.Style({},{externalGraphic: 'icons/limit-' + number + '.png',
594                                                                                graphicYOffset: -9,
595                                                                                graphicWidth: 19,
596                                                                                graphicHeight: 19})));
597          }
598       }
599    }
600
601  layerVectors.addFeatures(features);
602
603  var div_status=document.getElementById("result_status");
604  div_status.innerHTML = "Processed " + (lines.length-2) + " limits";
605 }
606
607
608 //
609 // Failure in getting data.
610 //
611
612 function runFailure(response)
613 {
614  var div_status=document.getElementById("result_status");
615  div_status.innerHTML = "Failed to get visualiser data!";
616
617  window.alert("Failed to get visualiser data!\n" + response.statusText);
618 }