Routino SVN Repository Browser

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

ViewVC logotype

Annotation of /trunk/extras/find-fixme/web/www/fixme.leaflet.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1994 - (hide annotations) (download) (as text)
Thu Apr 25 18:02:22 2019 UTC (5 years, 10 months ago) by amb
File MIME type: application/javascript
File size: 13106 byte(s)
Fix bug with regexp generating link to node/way/relation on openstreetmap.org.

1 amb 1491 //
2     // Routino (extras) fixme web page Javascript
3     //
4     // Part of the Routino routing software.
5     //
6 amb 1994 // This file Copyright 2008-2014, 2019 Andrew M. Bishop
7 amb 1491 //
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, layerBoxes;
65    
66     var box;
67    
68     //
69     // Initialise the 'map' object
70     //
71    
72     function map_init() // called from fixme.html
73     {
74     // Create the map (Map URLs and limits are in mapprops.js)
75    
76     map = L.map("map",
77     {
78     attributionControl: false,
79     zoomControl: false,
80    
81     minZoom: mapprops.zoomout,
82     maxZoom: mapprops.zoomin,
83    
84     maxBounds: L.latLngBounds(L.latLng(mapprops.southedge,mapprops.westedge),L.latLng(mapprops.northedge,mapprops.eastedge))
85     });
86    
87     // Add map tile layers
88    
89     var baselayers={};
90    
91     for(var l=0; l<mapprops.mapdata.length; l++)
92     {
93     var urls=mapprops.mapdata[l].tiles.url.replace(/\${/g,"{");
94    
95     if(mapprops.mapdata[l].tiles.subdomains===undefined)
96     layerMap[l] = L.tileLayer(urls);
97     else
98     layerMap[l] = L.tileLayer(urls, {subdomains: mapprops.mapdata[l].tiles.subdomains});
99    
100     baselayers[mapprops.mapdata[l].label]=layerMap[l];
101    
102     if(l===0)
103     map.addLayer(layerMap[l]);
104     }
105    
106     // Add the controls
107    
108     map.addControl(L.control.zoom());
109     map.addControl(L.control.scale());
110     map.addControl(L.control.layers(baselayers));
111    
112     // Update the attribution if the layer changes
113    
114     function change_attribution_event(event)
115     {
116     for(var l=0; l<mapprops.mapdata.length; l++)
117     if(layerMap[l] == event.layer)
118     change_attribution(l);
119     }
120    
121     map.on("baselayerchange",change_attribution_event);
122    
123     function change_attribution(l)
124     {
125     var data_url =mapprops.mapdata[l].attribution.data_url;
126     var data_text=mapprops.mapdata[l].attribution.data_text;
127     var tile_url =mapprops.mapdata[l].attribution.tile_url;
128     var tile_text=mapprops.mapdata[l].attribution.tile_text;
129    
130     document.getElementById("attribution_data").innerHTML="<a href=\"" + data_url + "\" target=\"data_attribution\">" + data_text + "</a>";
131     document.getElementById("attribution_tile").innerHTML="<a href=\"" + tile_url + "\" target=\"tile_attribution\">" + tile_text + "</a>";
132     }
133    
134     change_attribution(0);
135    
136     // Add two vectors layers (one for highlights that display behind the vectors)
137    
138     layerVectors = L.layerGroup();
139     map.addLayer(layerVectors);
140    
141     layerHighlights = L.layerGroup();
142     map.addLayer(layerHighlights);
143    
144     // Handle popup
145    
146     createPopup();
147    
148     // Add a boxes layer
149    
150     layerBoxes = L.rectangle(map.options.maxBounds,{stroke: false, color: "#f00", weight: 1, opacity: 1.0,
151     fill: false});
152    
153     map.addLayer(layerBoxes);
154    
155     box=false;
156    
157     // Move the map
158    
159     map.on("moveend", updateURLs);
160    
161     var lon =args["lon"];
162     var lat =args["lat"];
163     var zoom=args["zoom"];
164    
165 amb 1493 if(lon !== undefined && lat !== undefined && zoom !== undefined)
166 amb 1491 {
167     if(lon<mapprops.westedge) lon=mapprops.westedge;
168     if(lon>mapprops.eastedge) lon=mapprops.eastedge;
169    
170     if(lat<mapprops.southedge) lat=mapprops.southedge;
171     if(lat>mapprops.northedge) lat=mapprops.northedge;
172    
173     if(zoom<mapprops.zoomout) zoom=mapprops.zoomout;
174     if(zoom>mapprops.zoomin) zoom=mapprops.zoomin;
175    
176     map.setView(L.latLng(lat,lon),zoom);
177     }
178     else
179     map.fitBounds(map.options.maxBounds);
180    
181     // Unhide editing URL if variable set
182    
183 amb 1493 if(mapprops.editurl !== undefined && mapprops.editurl !== "")
184 amb 1491 {
185     var edit_url=document.getElementById("edit_url");
186    
187     edit_url.style.display="";
188     edit_url.href=mapprops.editurl;
189     }
190    
191     updateURLs();
192     }
193    
194    
195     //
196     // Format a number in printf("%.5f") format.
197     //
198    
199     function format5f(number)
200     {
201     var newnumber=Math.floor(number*100000+0.5);
202     var delta=0;
203    
204     if(newnumber>=0 && newnumber<100000) delta= 100000;
205     if(newnumber<0 && newnumber>-100000) delta=-100000;
206    
207     var string=String(newnumber+delta);
208    
209     var intpart =string.substring(0,string.length-5);
210     var fracpart=string.substring(string.length-5,string.length);
211    
212     if(delta>0) intpart="0";
213     if(delta<0) intpart="-0";
214    
215     return(intpart + "." + fracpart);
216     }
217    
218    
219     //
220     // Build a set of URL arguments for the map location
221     //
222    
223     function buildMapArguments()
224     {
225     var lonlat = map.getCenter();
226    
227     var zoom = map.getZoom();
228    
229     return "lat=" + format5f(lonlat.lat) + ";lon=" + format5f(lonlat.lng) + ";zoom=" + zoom;
230     }
231    
232    
233     //
234     // Update the URLs
235     //
236    
237     function updateURLs()
238     {
239     var mapargs=buildMapArguments();
240    
241     var links=document.getElementsByTagName("a");
242    
243     for(var i=0; i<links.length; i++)
244     {
245     var element=links[i];
246    
247     if(element.id == "permalink_url")
248     element.href=location.pathname + "?" + mapargs;
249    
250     if(element.id == "edit_url")
251     element.href=mapprops.editurl + "?" + mapargs;
252     }
253     }
254    
255    
256     ////////////////////////////////////////////////////////////////////////////////
257     ///////////////////////// Popup and selection handling /////////////////////////
258     ////////////////////////////////////////////////////////////////////////////////
259    
260     var popup=null;
261    
262     //
263     // Create a popup - independent of map because want it fixed on screen not fixed on map.
264     //
265    
266     function createPopup()
267     {
268     popup=document.createElement("div");
269    
270     popup.className = "popup";
271    
272     popup.innerHTML = "<span></span>";
273    
274     popup.style.display = "none";
275    
276     popup.style.position = "fixed";
277     popup.style.top = "-4000px";
278     popup.style.left = "-4000px";
279     popup.style.zIndex = "100";
280    
281     popup.style.padding = "5px";
282    
283     popup.style.opacity=0.85;
284     popup.style.backgroundColor="#C0C0C0";
285     popup.style.border="4px solid #404040";
286    
287     document.body.appendChild(popup);
288     }
289    
290    
291     //
292     // Draw a popup - independent of map because want it fixed on screen not fixed on map.
293     //
294    
295     function drawPopup(html)
296     {
297 amb 1493 if(html===null)
298 amb 1491 {
299     popup.style.display="none";
300     return;
301     }
302    
303     if(popup.style.display=="none")
304     {
305     var map_div=document.getElementById("map");
306    
307     popup.style.left =map_div.offsetParent.offsetLeft+map_div.offsetLeft+60 + "px";
308     popup.style.top = map_div.offsetTop +30 + "px";
309 amb 1499 popup.style.width =map_div.clientWidth-120 + "px";
310 amb 1491
311     popup.style.display="";
312     }
313    
314 amb 1499 var close="<span style='float: right; cursor: pointer;' onclick='drawPopup(null)'>X</span>";
315    
316     popup.innerHTML=close+html;
317 amb 1491 }
318    
319    
320     //
321     // Select a feature
322     //
323    
324     function selectCircleMarkerFeature(feature,dump,event)
325     {
326     if(dump)
327     ajaxGET("fixme.cgi?dump=" + dump, runDumpSuccess);
328    
329     layerHighlights.clearLayers();
330    
331     var highlight = L.circleMarker(feature.getLatLng(),{radius: 2*feature.getRadius(), fill: true, fillColor: "#F0F000", fillOpacity: 1.0,
332     stroke: false});
333    
334     layerHighlights.addLayer(highlight);
335    
336     highlight.bringToBack();
337     }
338    
339    
340     //
341     // Un-select a feature
342     //
343    
344     function unselectFeature(feature)
345     {
346     layerHighlights.clearLayers();
347    
348     drawPopup(null);
349     }
350    
351    
352     //
353     // Display the dump data
354     //
355    
356     function runDumpSuccess(response)
357     {
358     var string=response.responseText;
359    
360 amb 1493 if(mapprops.editurl !== undefined && mapprops.editurl !== "")
361 amb 1491 {
362     var types=["node", "way", "relation"];
363    
364     for(var t in types)
365     {
366     var type=types[t];
367    
368 amb 1994 var regexp=RegExp(type + " id=&#39;([0-9]+)&#39;");
369 amb 1491
370     var match=string.match(regexp);
371    
372 amb 1493 if(match !== null)
373 amb 1491 {
374 amb 1994 var id=match[1];
375 amb 1491
376 amb 1506 string=string.replace(regexp,type + " id=&#39;<a href='" + mapprops.browseurl + "/" + type + "/" + id + "' target='" + type + id + "'>" + id + "</a>&#39;");
377 amb 1491 }
378     }
379     }
380    
381     drawPopup(string.split("&gt;&lt;").join("&gt;<br>&lt;").split("<br>&lt;tag").join("<br>&nbsp;&nbsp;&lt;tag"));
382     }
383    
384    
385     ////////////////////////////////////////////////////////////////////////////////
386     /////////////////////////////// Server handling ////////////////////////////////
387     ////////////////////////////////////////////////////////////////////////////////
388    
389     //
390     // Define an AJAX request object
391     //
392    
393     function ajaxGET(url,success,failure,state)
394     {
395     var ajaxRequest=new XMLHttpRequest();
396    
397     function ajaxGOT(options) {
398     if(this.readyState==4)
399     if(this.status==200)
400     { if(typeof(options.success)=="function") options.success(this,options.state); }
401     else
402     { if(typeof(options.failure)=="function") options.failure(this,options.state); }
403     }
404    
405     ajaxRequest.onreadystatechange = function(){ ajaxGOT.call(ajaxRequest,{success: success, failure: failure, state: state}); };
406     ajaxRequest.open("GET", url, true);
407     ajaxRequest.send(null);
408     }
409    
410    
411     //
412     // Display the status
413     //
414    
415     function displayStatus(type,subtype,content)
416     {
417     var child=document.getElementById("result_status").firstChild;
418    
419     do
420     {
421 amb 1493 if(child.id !== undefined)
422 amb 1491 child.style.display="none";
423    
424     child=child.nextSibling;
425     }
426 amb 1496 while(child !== null);
427 amb 1491
428     var chosen_status=document.getElementById("result_status_" + type);
429    
430     chosen_status.style.display="";
431    
432 amb 1496 if(subtype !== undefined)
433 amb 1491 {
434     var format_status=document.getElementById("result_status_" + subtype).innerHTML;
435    
436     chosen_status.innerHTML=format_status.replace("#",String(content));
437     }
438     }
439    
440    
441     //
442     // Display data statistics
443     //
444    
445     function displayStatistics()
446     {
447     // Use AJAX to get the statistics
448    
449     ajaxGET("fixme.cgi?statistics=yes", runStatisticsSuccess);
450     }
451    
452    
453     //
454     // Success in running data statistics generation.
455     //
456    
457     function runStatisticsSuccess(response)
458     {
459     document.getElementById("statistics_data").innerHTML="<pre>" + response.responseText + "</pre>";
460     document.getElementById("statistics_link").style.display="none";
461     }
462    
463    
464     //
465     // Get the requested data
466     //
467    
468     function displayData(datatype) // called from fixme.html
469     {
470     // Delete the old data
471    
472     unselectFeature();
473    
474     layerVectors.clearLayers();
475     layerHighlights.clearLayers();
476    
477     layerBoxes.setStyle({stroke:false});
478     box=false;
479    
480     // Print the status
481    
482     displayStatus("no_data");
483    
484     // Return if just here to clear the data
485    
486 amb 1493 if(datatype === "")
487 amb 1491 return;
488    
489     // Get the new data
490    
491     var mapbounds=map.getBounds();
492    
493     var url="fixme.cgi";
494    
495     url=url + "?lonmin=" + format5f(mapbounds.getWest());
496     url=url + ";latmin=" + format5f(mapbounds.getSouth());
497     url=url + ";lonmax=" + format5f(mapbounds.getEast());
498     url=url + ";latmax=" + format5f(mapbounds.getNorth());
499     url=url + ";data=" + datatype;
500    
501     // Use AJAX to get the data
502    
503     ajaxGET(url, runFixmeSuccess, runFailure);
504     }
505    
506    
507     //
508     // Success in getting the error log data
509     //
510    
511     function runFixmeSuccess(response)
512     {
513     var lines=response.responseText.split("\n");
514    
515     for(var line=0;line<lines.length;line++)
516     {
517     var words=lines[line].split(" ");
518    
519 amb 1493 if(line === 0)
520 amb 1491 {
521     var lat1=words[0];
522     var lon1=words[1];
523     var lat2=words[2];
524     var lon2=words[3];
525    
526     var bounds = L.latLngBounds(L.latLng(lat1,lon1),L.latLng(lat2,lon2));
527    
528     layerBoxes.setBounds(bounds);
529    
530     layerBoxes.setStyle({stroke: true});
531     box=true;
532     }
533 amb 1493 else if(words[0] !== "")
534 amb 1491 {
535     var dump=words[0];
536     var lat=words[1];
537     var lon=words[2];
538    
539     var lonlat = L.latLng(lat,lon);
540    
541     var feature = L.circleMarker(lonlat,{radius: 3, fill: true, fillColor: "#FF0000", fillOpacity: 1.0,
542     stroke: false});
543    
544     feature.on("click", (function(f,d) { return function(evt) { selectCircleMarkerFeature(f,d,evt); }; }(feature,dump)));
545    
546     layerVectors.addLayer(feature);
547     }
548     }
549    
550     displayStatus("data","fixme",lines.length-2);
551     }
552    
553    
554     //
555     // Failure in getting data.
556     //
557    
558     function runFailure(response)
559     {
560     displayStatus("failed");
561     }