Routino SVN Repository Browser

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

ViewVC logotype

Contents of /branches/destination-access/extras/find-fixme/web/www/fixme.openlayers2.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2085 - (show annotations) (download) (as text)
Sat Nov 21 16:10:04 2020 UTC (4 years, 3 months ago) by amb
File MIME type: application/javascript
File size: 15696 byte(s)
Merge from trunk [update leaflet and openlayers versions].

1 //
2 // Routino (extras) fixme web page Javascript
3 //
4 // Part of the Routino routing software.
5 //
6 // This file Copyright 2008-2014, 2019, 2020 Andrew M. Bishop
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as published by
10 // the Free Software Foundation, either version 3 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
17 //
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 //
21
22
23 ////////////////////////////////////////////////////////////////////////////////
24 /////////////////////////////// Initialisation /////////////////////////////////
25 ////////////////////////////////////////////////////////////////////////////////
26
27 // Process the URL query string and extract the arguments
28
29 var legal={"^lon" : "^[-0-9.]+$",
30 "^lat" : "^[-0-9.]+$",
31 "^zoom" : "^[-0-9.]+$"};
32
33 var args={};
34
35 if(location.search.length>1)
36 {
37 var query,queries;
38
39 query=location.search.replace(/^\?/,"");
40 query=query.replace(/;/g,"&");
41 queries=query.split("&");
42
43 for(var i=0;i<queries.length;i++)
44 {
45 queries[i].match(/^([^=]+)(=(.*))?$/);
46
47 var k=RegExp.$1;
48 var v=decodeURIComponent(RegExp.$3);
49
50 for(var l in legal)
51 {
52 if(k.match(RegExp(l)) && v.match(RegExp(legal[l])))
53 args[k]=v;
54 }
55 }
56 }
57
58
59 ////////////////////////////////////////////////////////////////////////////////
60 ///////////////////////////////// Map handling /////////////////////////////////
61 ////////////////////////////////////////////////////////////////////////////////
62
63 var map;
64 var layerMap=[], layerHighlights, layerVectors;
65 var vectorData=[];
66 var epsg4326, epsg900913;
67 var select;
68
69 //
70 // Initialise the 'map' object
71 //
72
73 function map_init() // called from fixme.html
74 {
75 // Create the map (Map URLs and limits are in mapprops.js)
76
77 epsg4326=new OpenLayers.Projection("EPSG:4326");
78 epsg900913=new OpenLayers.Projection("EPSG:900913");
79
80 map = new OpenLayers.Map ("map",
81 {
82 controls:[
83 new OpenLayers.Control.Navigation(),
84 new OpenLayers.Control.PanZoomBar(),
85 new OpenLayers.Control.ScaleLine(),
86 new OpenLayers.Control.LayerSwitcher()
87 ],
88
89 projection: epsg900913,
90 displayProjection: epsg4326,
91
92 minZoomLevel: mapprops.zoomout,
93 numZoomLevels: mapprops.zoomin-mapprops.zoomout+1,
94 maxResolution: 156543.03390625 / Math.pow(2,mapprops.zoomout),
95
96 restrictedExtent: new OpenLayers.Bounds(mapprops.westedge,mapprops.southedge,mapprops.eastedge,mapprops.northedge).transform(epsg4326,epsg900913)
97 });
98
99 // Get a URL for the tile (mostly copied from OpenLayers/Layer/XYZ.js).
100
101 function limitedUrl(bounds)
102 {
103 var res = this.map.getResolution();
104
105 var x = Math.round((bounds.left - this.maxExtent.left) / (res * this.tileSize.w));
106 var y = Math.round((this.maxExtent.top - bounds.top) / (res * this.tileSize.h));
107 var z = this.map.getZoom() + this.map.minZoomLevel;
108
109 var limit = Math.pow(2, z);
110 x = ((x % limit) + limit) % limit;
111
112 var xyz = {"x": x, "y": y, "z": z};
113 var url = this.url;
114
115 if (OpenLayers.Util.isArray(url))
116 {
117 var s = "" + xyz.x + xyz.y + xyz.z;
118 url = this.selectUrl(s, url);
119 }
120
121 return OpenLayers.String.format(url, xyz);
122 }
123
124 // Add map tile layers
125
126 for(var l=0; l<mapprops.mapdata.length; l++)
127 {
128 var urls;
129
130 if(OpenLayers.Util.isArray(mapprops.mapdata[l].tiles.subdomains))
131 {
132 urls=[];
133
134 for(var s=0; s<mapprops.mapdata[l].tiles.subdomains.length; s++)
135 urls.push(mapprops.mapdata[l].tiles.url.replace(/\${s}/,mapprops.mapdata[l].tiles.subdomains[s]));
136 }
137 else
138 urls=mapprops.mapdata[l].tiles.url;
139
140 layerMap[l] = new OpenLayers.Layer.TMS(mapprops.mapdata[l].label,
141 urls,
142 {
143 getURL: limitedUrl,
144 displayOutsideMaxExtent: true,
145 buffer: 1
146 });
147 map.addLayer(layerMap[l]);
148 }
149
150 // Update the attribution if the layer changes
151
152 function change_attribution_event(event)
153 {
154 for(var l=0; l<mapprops.mapdata.length; l++)
155 if(layerMap[l] == event.layer)
156 change_attribution(l);
157 }
158
159 map.events.register("changelayer",layerMap,change_attribution_event);
160
161 function change_attribution(l)
162 {
163 var data_url =mapprops.mapdata[l].attribution.data_url;
164 var data_text=mapprops.mapdata[l].attribution.data_text;
165 var tile_url =mapprops.mapdata[l].attribution.tile_url;
166 var tile_text=mapprops.mapdata[l].attribution.tile_text;
167
168 document.getElementById("attribution_data").innerHTML="<a href=\"" + data_url + "\" target=\"data_attribution\">" + data_text + "</a>";
169 document.getElementById("attribution_tile").innerHTML="<a href=\"" + tile_url + "\" target=\"tile_attribution\">" + tile_text + "</a>";
170 }
171
172 change_attribution(0);
173
174 // Add two vectors layers (one for highlights that display behind the vectors)
175
176 layerHighlights = new OpenLayers.Layer.Vector("Highlights",{displayInLayerSwitcher: false});
177 map.addLayer(layerHighlights);
178
179 layerVectors = new OpenLayers.Layer.Vector("Markers",{displayInLayerSwitcher: false});
180 map.addLayer(layerVectors);
181
182 // Handle feature selection and popup
183
184 select = new OpenLayers.Control.SelectFeature(layerVectors,
185 {onSelect: selectFeature, onUnselect: unselectFeature});
186
187 map.addControl(select);
188 select.activate();
189
190 createPopup();
191
192 // Move the map
193
194 map.events.register("moveend", map, (function() { displayMoreData();}));
195
196 var lon =args["lon"];
197 var lat =args["lat"];
198 var zoom=args["zoom"];
199
200 if(lon !== undefined && lat !== undefined && zoom !== undefined)
201 {
202 lat = Number(lat);
203 lon = Number(lon);
204 zoom = Number.parseInt(Number(zoom)+0.5);
205
206 if(lon<mapprops.westedge) lon=mapprops.westedge;
207 if(lon>mapprops.eastedge) lon=mapprops.eastedge;
208
209 if(lat<mapprops.southedge) lat=mapprops.southedge;
210 if(lat>mapprops.northedge) lat=mapprops.northedge;
211
212 if(zoom<mapprops.zoomout) zoom=mapprops.zoomout;
213 if(zoom>mapprops.zoomin) zoom=mapprops.zoomin;
214
215 var lonlat = new OpenLayers.LonLat(lon,lat);
216 lonlat.transform(epsg4326,epsg900913);
217
218 map.moveTo(lonlat,zoom-map.minZoomLevel);
219 }
220 else
221 {
222 map.setCenter(map.restrictedExtent.getCenterLonLat(), map.getZoomForExtent(map.restrictedExtent,false));
223 map.maxResolution = map.getResolution();
224 }
225
226 // Unhide editing URL if variable set
227
228 if(mapprops.editurl !== undefined && mapprops.editurl !== "")
229 {
230 var edit_url=document.getElementById("edit_url");
231
232 edit_url.style.display="";
233 edit_url.href=mapprops.editurl;
234 }
235
236 updateURLs(false);
237 }
238
239
240 //
241 // Format a number in printf("%.5f") format.
242 //
243
244 function format5f(number)
245 {
246 var newnumber=Math.floor(number*100000+0.5);
247 var delta=0;
248
249 if(newnumber>=0 && newnumber<100000) delta= 100000;
250 if(newnumber<0 && newnumber>-100000) delta=-100000;
251
252 var string=String(newnumber+delta);
253
254 var intpart =string.substring(0,string.length-5);
255 var fracpart=string.substring(string.length-5,string.length);
256
257 if(delta>0) intpart="0";
258 if(delta<0) intpart="-0";
259
260 return(intpart + "." + fracpart);
261 }
262
263
264 //
265 // Build a set of URL arguments for the map location
266 //
267
268 function buildMapArguments()
269 {
270 var lonlat = map.getCenter().clone();
271 lonlat.transform(epsg900913,epsg4326);
272
273 var zoom = map.getZoom() + map.minZoomLevel;
274
275 return "lat=" + format5f(lonlat.lat) + ";lon=" + format5f(lonlat.lon) + ";zoom=" + zoom;
276 }
277
278
279 //
280 // Update the URLs
281 //
282
283 function updateURLs(addhistory)
284 {
285 var mapargs=buildMapArguments();
286 var libargs=";library=" + mapprops.library;
287
288 if(!mapprops.libraries)
289 libargs="";
290
291 var links=document.getElementsByTagName("a");
292
293 for(var i=0; i<links.length; i++)
294 {
295 var element=links[i];
296
297 if(element.id == "permalink_url")
298 element.href=location.pathname + "?" + mapargs + libargs;
299
300 if(element.id == "edit_url")
301 element.href=mapprops.editurl + "?" + mapargs;
302 }
303
304 if(addhistory)
305 history.replaceState(null, null, location.pathname + "?" + mapargs + libargs);
306 }
307
308
309 ////////////////////////////////////////////////////////////////////////////////
310 ///////////////////////// Popup and selection handling /////////////////////////
311 ////////////////////////////////////////////////////////////////////////////////
312
313 var popup=null;
314
315 //
316 // Create a popup - independent of map because want it fixed on screen not fixed on map.
317 //
318
319 function createPopup()
320 {
321 popup=document.createElement("div");
322
323 popup.className = "popup";
324
325 popup.innerHTML = "<span></span>";
326
327 popup.style.display = "none";
328
329 popup.style.position = "fixed";
330 popup.style.top = "-4000px";
331 popup.style.left = "-4000px";
332 popup.style.zIndex = "100";
333
334 popup.style.padding = "5px";
335
336 popup.style.opacity=0.85;
337 popup.style.backgroundColor="#C0C0C0";
338 popup.style.border="4px solid #404040";
339
340 document.body.appendChild(popup);
341 }
342
343
344 //
345 // Draw a popup - independent of map because want it fixed on screen not fixed on map.
346 //
347
348 function drawPopup(html)
349 {
350 if(html===null)
351 {
352 popup.style.display="none";
353 return;
354 }
355
356 if(popup.style.display=="none")
357 {
358 var map_div=document.getElementById("map");
359
360 popup.style.left =map_div.offsetParent.offsetLeft+map_div.offsetLeft+60 + "px";
361 popup.style.top = map_div.offsetTop +30 + "px";
362 popup.style.width =map_div.clientWidth-120 + "px";
363
364 popup.style.display="";
365 }
366
367 var close="<span style='float: right; cursor: pointer;' onclick='drawPopup(null)'>X</span>";
368
369 popup.innerHTML=close+html;
370 }
371
372
373 //
374 // Select a feature
375 //
376
377 function selectFeature(feature)
378 {
379 if(feature.attributes.dump)
380 ajaxGET("fixme.cgi?dump=" + feature.attributes.dump, runDumpSuccess);
381
382 layerHighlights.destroyFeatures();
383
384 var highlight_style = new OpenLayers.Style({},{strokeColor: "#F0F000",strokeWidth: 8,
385 fillColor: "#F0F000",pointRadius: 4});
386
387 var highlight = new OpenLayers.Feature.Vector(feature.geometry.clone(),{},highlight_style);
388
389 layerHighlights.addFeatures([highlight]);
390 }
391
392
393 //
394 // Un-select a feature
395 //
396
397 function unselectFeature(feature)
398 {
399 layerHighlights.destroyFeatures();
400
401 drawPopup(null);
402 }
403
404
405 //
406 // Display the dump data
407 //
408
409 function runDumpSuccess(response)
410 {
411 var string=response.responseText;
412
413 if(mapprops.browseurl !== undefined && mapprops.browseurl !== "")
414 {
415 var types=["node", "way", "relation"];
416
417 for(var t in types)
418 {
419 var type=types[t];
420
421 var regexp=RegExp(type + " id=&#39;([0-9]+)&#39;");
422
423 var match=string.match(regexp);
424
425 if(match !== null)
426 {
427 var id=match[1];
428
429 string=string.replace(regexp,type + " id=&#39;<a href='" + mapprops.browseurl + "/" + type + "/" + id + "' target='" + type + id + "'>" + id + "</a>&#39;");
430 }
431 }
432 }
433
434 drawPopup(string.split("&gt;&lt;").join("&gt;<br>&lt;").split("<br>&lt;tag").join("<br>&nbsp;&nbsp;&lt;tag"));
435 }
436
437
438 ////////////////////////////////////////////////////////////////////////////////
439 /////////////////////////////// Server handling ////////////////////////////////
440 ////////////////////////////////////////////////////////////////////////////////
441
442 //
443 // Define an AJAX request object
444 //
445
446 function ajaxGET(url,success,failure,state)
447 {
448 var ajaxRequest=new XMLHttpRequest();
449
450 function ajaxGOT(options) {
451 if(this.readyState==4)
452 if(this.status==200)
453 { if(typeof(options.success)=="function") options.success(this,options.state); }
454 else
455 { if(typeof(options.failure)=="function") options.failure(this,options.state); }
456 }
457
458 ajaxRequest.onreadystatechange = function(){ ajaxGOT.call(ajaxRequest,{success: success, failure: failure, state: state}); };
459 ajaxRequest.open("GET", url, true);
460 ajaxRequest.send(null);
461 }
462
463
464 //
465 // Display the status
466 //
467
468 function displayStatus(type,subtype,content)
469 {
470 var child=document.getElementById("result_status").firstChild;
471
472 do
473 {
474 if(child.id !== undefined)
475 child.style.display="none";
476
477 child=child.nextSibling;
478 }
479 while(child !== null);
480
481 var chosen_status=document.getElementById("result_status_" + type);
482
483 chosen_status.style.display="";
484
485 if(subtype !== undefined)
486 {
487 var format_status=document.getElementById("result_status_" + subtype).innerHTML;
488
489 chosen_status.innerHTML=format_status.replace("#",String(content));
490 }
491 }
492
493
494 //
495 // Display data statistics
496 //
497
498 function displayStatistics()
499 {
500 // Use AJAX to get the statistics
501
502 ajaxGET("fixme.cgi?statistics=yes", runStatisticsSuccess);
503 }
504
505
506 //
507 // Success in running data statistics generation.
508 //
509
510 function runStatisticsSuccess(response)
511 {
512 document.getElementById("statistics_data").innerHTML="<pre>" + response.responseText + "</pre>";
513 document.getElementById("statistics_link").style.display="none";
514 }
515
516
517 //
518 // Get the requested data
519 //
520
521 function displayData(datatype) // called from fixme.html
522 {
523 // Delete the old data
524
525 vectorData=[];
526
527 unselectFeature();
528
529 select.deactivate();
530
531 layerVectors.destroyFeatures();
532
533 // Print the status
534
535 displayStatus("no_data");
536
537 // Return if just here to clear the data
538
539 if(datatype === "")
540 return;
541
542 displayMoreData();
543 }
544
545
546 function displayMoreData()
547 {
548 // Get the new data
549
550 var mapbounds=map.getExtent().clone();
551 mapbounds.transform(epsg900913,epsg4326);
552
553 var url="fixme.cgi";
554
555 url=url + "?lonmin=" + format5f(mapbounds.left);
556 url=url + ";latmin=" + format5f(mapbounds.bottom);
557 url=url + ";lonmax=" + format5f(mapbounds.right);
558 url=url + ";latmax=" + format5f(mapbounds.top);
559 url=url + ";data=fixmes";
560
561 // Use AJAX to get the data
562
563 ajaxGET(url, runFixmeSuccess, runFailure);
564
565 updateURLs(true);
566 }
567
568
569 //
570 // Success in getting the error log data
571 //
572
573 function runFixmeSuccess(response)
574 {
575 var lines=response.responseText.split("\n");
576
577 var style = new OpenLayers.Style({},{stroke: false,
578 pointRadius: 3,fillColor: "#FF0000",
579 cursor: "pointer"});
580
581 var features=[];
582
583 for(var line=0;line<lines.length;line++)
584 {
585 var words=lines[line].split(" ");
586
587 if(line === 0)
588 continue;
589 else if(words[0] !== "")
590 {
591 var dump=words[0];
592
593 if(vectorData[dump])
594 continue;
595 else
596 vectorData[dump]=1;
597
598 var lat=Number(words[1]);
599 var lon=Number(words[2]);
600
601 var lonlat = new OpenLayers.LonLat(lon,lat).transform(epsg4326,epsg900913);
602
603 var point = new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);
604
605 features.push(new OpenLayers.Feature.Vector(point,{dump: dump},style));
606 }
607 }
608
609 select.activate();
610
611 layerVectors.addFeatures(features);
612
613 displayStatus("data","fixme",Object.keys(vectorData).length);
614 }
615
616
617 //
618 // Failure in getting data.
619 //
620
621 function runFailure(response)
622 {
623 displayStatus("failed");
624 }