Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino
Contents of /branches/destination-access/extras/find-fixme/web/www/fixme.openlayers2.js
Parent Directory
|
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)
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='([0-9]+)'"); |
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='<a href='" + mapprops.browseurl + "/" + type + "/" + id + "' target='" + type + id + "'>" + id + "</a>'"); |
430 | } |
431 | } |
432 | } |
433 | |
434 | drawPopup(string.split("><").join("><br><").split("<br><tag").join("<br> <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 | } |