1if(!window.console) // for very old browser 2 var console = { log : function(i){}} 3 4var language = window.navigator.languages ? window.navigator.languages[0] : (window.navigator.language || window.navigator.userLanguage); 5 6if(typeof language === 'string') 7 language = [ language ]; 8 9// we need to have the following languages: 10// browserlang 11// a short one (de instead of de-AT) if not present 12// en as fallback if not present 13 14if(language.indexOf("en") == -1) 15 language.push("en"); 16 17for(var i = 0; i < language.length; i++) { 18 if(language[i].match(/-/)) { 19 var short_lang = language[i].match(/^([a-zA-Z]*)-/)[1]; 20 if(language.indexOf(short_lang) == -1) { 21 language.push(short_lang); 22 continue; 23 } 24 } 25} 26 27console.log(language); 28 29// global texts 30var attr = { 31 osm : 'Map data © <a href="https://openstreetmap.org/">OpenStreetMap</a> contributors - <a href="http://opendatacommons.org/licenses/odbl/">ODbL</a>', 32 osm_tiles : 'Tiles © OSM - <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC BY-SA</a>', 33 search : 'Search by OSM - <a href="http://wiki.openstreetmap.org/wiki/Nominatim">Nominatim</a>', 34 mapbox : 'Tiles © <a href="http://mapbox.com/about/maps/">MapBox</a>', 35 mapquest : 'Tiles courtesy of <a href="http://www.mapquest.com/">MapQuest</a>', 36 greenmap : 'Green Map Icons used by permission © <a href="http://www.greenmap.org">Green Map System 2015</a>', 37 overpass : 'POI via <a href="http://www.overpass-api.de/">Overpass API</a>' 38} 39 40if(!window.assethost) 41 var assethost = "http://demo.transformap.co/"; 42 43/* 44 * takes a two args: osm datatype and osm id 45 * if marker in field of view, toggle popup. 46 * zooms in if marker is hidden in cluster to get leafletMarker 47 */ 48function MytogglePopup(osm_type,osm_id) { 49 disableLoadPOI = true; 50 var leaflet_marker = getVisibleMarker(osm_type,osm_id) 51 if(leaflet_marker) { 52 leaflet_marker.togglePopup(); 53 setTimeout(function () { 54 disableLoadPOI = false; 55 }, 200); 56 return; 57 } //else 58 59 var target_marker; 60 var marker_array = markers.GetMarkers(); 61 for(var i = 0; i < marker_array.length; i++) { 62 var prunecluster_marker = marker_array[i]; 63 if(prunecluster_marker.data.type == osm_type && prunecluster_marker.data.id == osm_id) { 64 target_marker = prunecluster_marker; 65 break; 66 } 67 } 68 if(target_marker) { 69 if(map.getZoom() == map.getMaxZoom()) { 70 var possible_clusters = []; 71 map.eachLayer(function (layer) { 72 if(layer._population > 0) 73 possible_clusters.push(layer); 74 }); 75 var distance = 123456789; 76 var nearest_cluster = null; 77 for(i = 0; i < possible_clusters.length; i++) { 78 var new_distance = calculateDistance(target_marker.position.lat, possible_clusters[i]._latlng.lat, target_marker.position.lng, possible_clusters[i]._latlng.lng); 79 if( new_distance < distance ) { 80 distance = new_distance; 81 nearest_cluster = possible_clusters[i]; 82 } 83 } 84 if(!nearest_cluster) { 85 console.log("Error in MytogglePopup: no nearest cluster found"); 86 disableLoadPOI = false; 87 return; 88 } 89 nearest_cluster.fireEvent('click'); 90 } 91 else 92 map.setZoomAround( new L.LatLng(target_marker.position.lat, target_marker.position.lng), map.getZoom() + 1); 93 94 setTimeout(function () { 95 MytogglePopup(osm_type,osm_id); 96 }, 200); 97 } else { 98 disableLoadPOI = false; 99 console.log("Error in MytogglePopup: marker " + osm_type + " " + osm_id + " not found in markers.GetMarkers()"); 100 } 101} 102 103 104//source: http://jsfiddle.net/vg01q7xw/ 105Number.prototype.toRad = function() { 106 return this * Math.PI / 180; 107} 108function calculateDistance(lat1, lat2, lon1, lon2) { 109 var R = 6371000; // meter 110 var Phi1 = lat1.toRad(); 111 var Phi2 = lat2.toRad(); 112 var DeltaPhi = (lat2 - lat1).toRad(); 113 var DeltaLambda = (lon2 - lon1).toRad(); 114 115 var a = Math.sin(DeltaPhi / 2) * Math.sin(DeltaPhi / 2) 116 + Math.cos(Phi1) * Math.cos(Phi2) * Math.sin(DeltaLambda / 2) 117 * Math.sin(DeltaLambda / 2); 118 var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); 119 var d = R * c; 120 121 return d; 122} 123 124function getVisibleMarker(osm_type,osm_id) { 125 var my_layer = null; 126 map.eachLayer(function (layer) { 127 if(! layer._popup || ! layer.options.alt) 128 return; 129 if(layer.options.alt != (osm_type + " " + osm_id)) 130 return; 131 132 my_layer = layer; 133 }); 134 return my_layer; 135} 136 137/* this part must be in global namespace */ 138// fetch taxonomy, containing all translations, and implicit affiliations 139// taken from Wikipedia:JSON 140var taxonomy, turbolink; 141var url = assethost+"taxonomy.json"; 142var http_request = new XMLHttpRequest(); 143http_request.open("GET", url, true); 144http_request.onreadystatechange = function () { 145 var done = 4, ok = 200; 146 if (http_request.readyState === done && http_request.status === ok) { 147 if(!window.JSON) { 148// document.getElementById('map').inn("Error:cannot handle JSON"); 149 return; 150 } 151 taxonomy = JSON.parse(http_request.responseText); 152 153 if(taxonomy) { 154 // add map key derived from it 155 for(var osmkey_counter = 0; osmkey_counter < overpass_config.icon_tags.length; osmkey_counter++) { 156 var osmkey = overpass_config.icon_tags[osmkey_counter]; 157 158 var taxonomy_block = taxonomy[osmkey]; 159 if (!taxonomy_block) { 160 console.log("no entry in taxonomy for " + osmkey); 161 break; 162 } 163 164 var entry_array = taxonomy_block['items']; 165 for (var i = 0; i < entry_array.length; i++ ) { 166 var item = entry_array[i]; 167 for ( var osmvalue_counter = 0; osmvalue_counter < item['osm:values'].length; osmvalue_counter++ ) { 168 var li = $("<li>"); 169 var new_id = item['osm:key'] + item['osm:values'][osmvalue_counter]; 170 li.attr("onClick", "toggleInfoBox('" + new_id + "');"); 171 li.append('<img src="'+assethost+'assets/transformap/pngs/identities/24/' + item['osm:key'] + '=' + item['osm:values'][osmvalue_counter] + '.png" /> ' 172 + item['label']['en'] 173 + '<div class=InfoBox ' 174 + 'id="' + new_id + '">' 175 + item['description']['en'] + '</div>'); 176 $('#mapkey').append(li); 177 } 178 } 179 } 180 181 if(window.filters) 182 createFiltersOfTaxonomy(); 183 184 } 185 else 186 console.log("taxonomy not here"); 187 188 } 189 }; 190http_request.send(null); 191 192var overpass_ql_text, 193 overpass_query, 194 overpass_query_nodes, 195 overpass_query_ways, 196 overpass_query_rels, 197 object_type_keys = [ "amenity", "shop", "tourism", "craft", "garden:type", "leisure", "office", "man_made", "landuse", "club", "farm_boxes" ] ; 198 199/* 200 * sets global the vars above 201 * MUST be called before first loadPOI 202 */ 203function buildOverpassQuery() { 204 if(! window.overpass_config ) 205 window.overpass_config = {}; 206 207 var op_server1 = "//overpass-api.de/api/", 208 op_server2 = (window.parent.document.location.protocol == "https:") ? op_server1 : "http://api.openstreetmap.fr/oapi/", //fr does'n have https, ru too 209 op_server3 = (window.parent.document.location.protocol == "https:") ? op_server1 : "http://overpass.osm.rambler.ru/cgi/"; 210 211 if(! overpass_config.timeout) overpass_config.timeout = 180; 212 if(! overpass_config.minzoom) overpass_config.minzoom = 12; 213 if(! overpass_config.servers) overpass_config.servers = [ op_server1, op_server2, op_server3 ]; 214 if(! overpass_config.q_array) overpass_config.q_array = [ [ '"identity"' ] ]; 215 if(! overpass_config.icon_folder) overpass_config.icon_folder = "identities"; 216 if(! overpass_config.icon_tags) overpass_config.icon_tags = [ "identity" ]; 217 if(! overpass_config.icon_size) overpass_config.icon_size = 24;
218 if(! overpass_config.class_selector_key) overpass_config.class_selector_key = { key: "" }; 219 220 var overpass_urlstart = 'interpreter?data='; 221 var overpass_start = '[out:json][timeout:' + overpass_config.timeout + '][bbox:BBOX];'; 222 223 var overpass_query_string = ""; 224 var overpass_query_string_nodes = ""; 225 var overpass_query_string_ways = ""; 226 var overpass_query_string_rels = ""; 227 228 for (var i = 0; i < overpass_config.q_array.length; i++) { 229 var anded_tags = overpass_config.q_array[i]; 230 var anded_querystring = ""; 231 var nr_of_and_clauses = anded_tags.length; 232 for (var j=0; j < nr_of_and_clauses; j++) { 233 anded_querystring += "[" + anded_tags[j] + "]"; 234 } 235 236 overpass_query_string += "node" + anded_querystring + ";out;"; 237 overpass_query_string += "(way" + anded_querystring + ";node(w));out;"; 238 overpass_query_string += "rel" + anded_querystring + ";out;>;out;"; 239 240 overpass_query_string_nodes += "node" + anded_querystring + ";out;"; 241 overpass_query_string_ways += "(way" + anded_querystring + ";node(w));out;"; 242 overpass_query_string_rels += "rel" + anded_querystring + ";out;>;out;"; 243 } 244 245 overpass_ql_text = overpass_start + overpass_query_string; 246 overpass_query = overpass_config.servers[0] + overpass_urlstart + overpass_ql_text; 247 overpass_query_nodes = overpass_config.servers[0] + overpass_urlstart + overpass_start + overpass_query_string_nodes; 248 overpass_query_ways = overpass_config.servers[1] + overpass_urlstart + overpass_start + overpass_query_string_ways; 249 overpass_query_rels = overpass_config.servers[2] + overpass_urlstart + overpass_start + overpass_query_string_rels; 250 console.log(overpass_query_nodes); 251 console.log(overpass_query_ways); 252 console.log(overpass_query_rels); 253} 254 255var debugLayer, 256 map, 257 markers = new PruneClusterForLeaflet(60,20), 258 lc = {}, 259 default_overlay = { 260 "POIs" : markers 261 }; 262 263function initMap(defaultlayer,base_maps,overlay_maps,lat,lon,zoom) { 264 var center = new L.LatLng(lat ? lat : 0, lon ? lon : 0); 265 266 var overriddenId = new L.Control.EditInOSM.Editors.Id({ url: "http://editor.transformap.co/#background=Bing&map=" }); 267 268/* var MapQuestOpen_OSM = new L.tileLayer('http://otile{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.jpeg', { 269 subdomains: '1234', 270 attribution: [attr.osm, attr.mapquest, attr.overpass, attr.greenmap].join(', '), 271 maxZoom : 19, 272 maxNativeZoom: 18 , 273 noWrap: true 274 }); MQ open no longer here */ 275 var osm = new L.TileLayer('//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { 276 attribution: [attr.osm, attr.osm_tiles, attr.overpass, attr.greenmap].join(', '), 277 maxZoom : 19, 278 noWrap: true 279 }); 280 281 terrain = new L.tileLayer('https://stamen-tiles-{s}.a.ssl.fastly.net/terrain/{z}/{x}/{y}.png', { 282 attribution: 'Map tiles by <a href="http://stamen.com/">Stamen Design</a>, '+ 283 'under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. '+ 284 'Data by <a href="https://openstreetmap.org">OpenStreetMap</a> contributors, under <a href="https://www.openstreetmap.org/copyright">ODbL</a>.' 285 }); 286 terrain_bg = new L.tileLayer('https://stamen-tiles-{s}.a.ssl.fastly.net/terrain-background/{z}/{x}/{y}.png', { 287 attribution: 'Map tiles by <a href="http://stamen.com/">Stamen Design</a>, '+ 288 'under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. '+ 289 'Data by <a href="https://openstreetmap.org">OpenStreetMap</a> contributors, under <a href="https://www.openstreetmap.org/copyright">ODbL</a>.' 290 }); 291 hot = new L.tileLayer('http://tile-{s}.openstreetmap.fr/hot/{z}/{x}/{y}.png', { 292 attribution: 'Tiles courtesy of <a href="http://hot.openstreetmap.org/">Humanitarian OpenStreetMap Team</a>. '+ 293 'Data by <a href="https://openstreetmap.org">OpenStreetMap</a> contributors, under <a href="https://www.openstreetmap.org/copyright">ODbL</a>.' 294 }); 295 296 /*if(!defaultlayer) 297 defaultlayer = (window.parent.document.location.protocol == "https:") ? osm : MapQuestOpen_OSM;*/ 298 defaultlayer = terrain_bg; 299 300 if(!overlay_maps) 301 overlay_maps = default_overlay; 302 303 map = new L.Map('map', { 304 center: center, 305 zoom: zoom ? zoom : 3, 306 layers: defaultlayer, 307 editInOSMControlOptions: { 308 position: 'topright', 309 zoomThreshold: 18, 310 widget: 'multiButton', 311 editors: [overriddenId] 312 } 313 }); 314 315 if(!base_maps) { 316 317 base_maps = { 318// 'MapQuestOpen': MapQuestOpen_OSM,
319 'Stamen - Terrain Background': terrain_bg, 320 'Stamen - Terrain': terrain, 321 'Humanitarian OpenSteetMap ': hot, 322 'OpenSteetMap - Mapnik': osm, 323 324 }; 325 } 326 327 map.addLayer(markers); 328 329 var ctrl = new L.Control.Layers(base_maps,overlay_maps) 330 map.addControl(ctrl); 331 332 L.LatLngBounds.prototype.toOverpassBBoxString = function (){ 333 var a = this._southWest, 334 b = this._northEast; 335 return [a.lat, a.lng, b.lat, b.lng].join(","); 336 } 337 338 var path_style = L.Path.prototype._updateStyle; 339 L.Path.prototype._updateStyle = function () { 340 path_style.apply(this); 341 for (k in this.options.svg) { 342 this._path.setAttribute(k, this.options.svg[k]); 343 } 344 } 345 346 if(window.createSideBar) { 347 createSideBar(); 348 setTimeout(toggleSideBarOnLoad,200); 349 map.on('moveend', updatePOIlist); 350 if(window.filters) 351 map.on('moveend',updateFilterCount); // here because it is called on every map move 352 } 353 354 $('#map').append('<a href="https://github.com/TransforMap/transfor-map" title="Fork me on GitHub" id=forkme></a>'); 355 $('#forkme').append('<img src="'+assethost+'assets/forkme-on-github.png" alt="Fork me on GitHub" />'); 356 357 $('#map').append('<img src="'+assethost+'assets/ajax-loader.gif" id="loading_node" class="loading" />'); 358 $('#map').append('<img src="'+assethost+'assets/ajax-loader.gif" id="loading_way" class="loading" />'); 359 $('#map').append('<img src="'+assethost+'assets/ajax-loader.gif" id="loading_relation" class="loading" />'); 360 $('#map').append('<div id="notificationbar">Please zoom in to update POIs!</div>'); 361 362 map.on('moveend', updateLinks); 363 map.on('popupopen', setImageInPopup); 364 map.on('popupopen', setTranslationsInPopup); 365 366 var popup_param = getUrlVars()["popup"]; 367 if(popup_param) { 368 open_popup_on_load.type = popup_param.match(/^(node|way|relation)/)[1]; 369 open_popup_on_load.id = popup_param.replace(/^(node|way|relation)/,'' ); 370 } 371 372 debugLayer = L.layerGroup(); 373 debugLayer.addTo(map); 374 375 return map; 376} 377 378var open_popup_on_load = { type : "", id: "", already_shown: false }; 379 380/* 381 var href = location.href; 382 var hasQuery = href.indexOf("?") + 1; 383 var hasHash = href.indexOf("#") + 1; 384 var appendix = (hasQuery ? "&" : "?") + "ts=true"; 385 location.href = hasHash ? href.replace("#", appendix + "#") : href + appendix; 386 */ 387 388function getUrlVars() { 389 var vars = {}; 390 var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) { 391 vars[key] = value.replace(/#.*$/,''); 392 }); 393 return vars; 394} 395 396function setImageInPopup(obj) { 397// console.log("setImageInPopup: called"); 398 if(!document.getElementById('wp-image')) { 399// console.log("setImageInPopup: no wp-image"); 400 return; 401 } 402 if ($('#wp-image img').attr('src')) { 403// console.log("setImageInPopup: src already set"); 404 return; 405 } 406 var img = $('#wp-image img'); 407 var source = wikipedia_images["wpimage_" + img.attr('title')]; 408 409 if(!source) { 410 $('#wp-image').css('display','none'); 411// console.log("setImageInPopup: no answer for item yet"); 412 return; 413 } 414 if ( source == "UNDEF") { 415 $('#wp-image').css('display','none'); 416// console.log("setImageInPopup: no image on wikipedia"); 417 return; 418 } 419// console.log("setImageInPopup: setting src " + source); 420 $('#wp-image').css('display','table-cell'); 421 img.attr('src', source); 422} 423 424function setTranslationsInPopup(obj) { 425 var elements = $('.leaflet-popup-content [translated]'); 426 if(!elements.length) 427 return; 428 429 //console.log(elements.length + " untranslated elements found."); 430 elements.each(function ( index ) { 431 var jqitem = $(this); 432 var tags_string = jqitem.attr("sourcetext"); 433 if(tags_string == "unknown feature") 434 return; 435 var tags = tags_string.split(","); 436 var new_strings = []; 437 var langs_used = []; 438 for(var i=0; i < tags.length; i++) { 439 var tag = tags[i].trim(); 440 if(!translations.tags[tag]) { 441 console.log("setTranslationsInPopup: no entry in translations foun
441d for '" + tag + "'"); 442 new_strings.push(tag); 443 continue; 444 } 445 446 var found_transl = 0; 447 for(var j=0; j < language.length; j++) { 448 var targetlang = language[j]; 449 if(translations.tags[tag][targetlang]) { 450 new_strings.push(translations.tags[tag][targetlang].value); 451 if(langs_used.indexOf(targetlang) == -1) 452 langs_used.push(targetlang); 453 found_transl = 1; 454 break; 455 } 456 } 457 if(!found_transl) { 458 console.log("no translation in your lang or en found for: '" + tag + "'"); 459 new_strings.push(tag); 460 } 461 462 } 463 var new_text = new_strings.join(", "); 464 if(jqitem.children().first().text() != new_text) { 465 jqitem.children().first().text(new_text); 466 jqitem.attr("translated",langs_used.join(",")); 467 } 468 }); 469} 470 471function addSearch() { 472 map.addControl( new L.Control.Search({ 473 url: '//nominatim.openstreetmap.org/search?format=json&q={s}', 474 jsonpParam: 'json_callback', 475 propertyName: 'display_name', 476 propertyLoc: ['lat','lon'], 477 circleLocation: false, 478 markerLocation: false, 479 autoType: false, 480 autoCollapse: false, 481 minLength: 2, 482 zoom:16 483 }) ); 484 485} 486function addLocate() { 487lc = L.control.locate({ 488 position: 'topleft', 489 showPopup: false, 490 strings: { 491 title: "Jump to my location!" 492 } 493 } 494 ).addTo(map); 495} 496 497var marker_table = {}; 498var old_zoom = 20; 499 500var pids = { 501 node : { 502 counter : 0, 503 active : {} 504 }, 505 way : { 506 counter : 0, 507 active : {} 508 }, 509 relation : { 510 counter : 0, 511 active : {} 512 } 513} 514 515var mutex_loading = { "loading_node" : 0, "loading_way" : 0, "loading_relation" : 0 }; 516 517var on_start_loaded = 0; 518 519/* 520 * type: "loading_node" / "loading_way" / "loading_relation" 521 * change: (+)1 or -1 522 */ 523function changeLoadingIndicator(type, change) { 524 525 var loading_indicator = document.getElementById(type); 526 if(mutex_loading[type] + change >= 0) //don't go into negative 527 mutex_loading[type] = mutex_loading[type] + change; 528 if(change == -1) { 529 if(mutex_loading[type] == 0) 530 loading_indicator.style.display = "none"; 531 } else // +1 532 loading_indicator.style.display = "block"; 533 loading_indicator.title = mutex_loading[type]; 534} 535 536function secHTML(input) { 537 return $("<div>").text( input ).html(); 538} 539 540function getIconTag(tags) { 541 for (var i = 0; i < overpass_config.icon_tags.length; i++) { 542 var key = overpass_config.icon_tags[i]; 543 if(tags[key] && ! ( key == "amenity" && tags[key] == "shop" ) ) { 544 return key; 545 } 546 } 547 return ""; 548} 549 550function chooseIconSrc(tags,iconsize) { 551 var icon_tag = getIconTag(tags); 552 553 var icon_url = ""; 554 if(!icon_tag) { 555 icon_url = assethost+"assets/transformap/pngs/" + overpass_config.icon_folder + "/" + iconsize + "/unknown.png"; 556 } else { 557 558 if (tags[icon_tag].indexOf(";") >= 0) // more than one item, take generic icon 559 icon_url = assethost+"assets/transformap/pngs/" + overpass_config.icon_folder + "/" + iconsize + "/generic.png"; 560 else 561 icon_url = assethost+"assets/transformap/pngs/" + overpass_config.icon_folder + "/" + iconsize + "/" + icon_tag + "=" + tags[icon_tag] + ".png"; 562 } 563 return icon_url; 564} 565 566var disableLoadPOI = false; 567 568var bboxes_requested = [ 569 /* e.g. { outer_bbox: L.LatLngBounds, inner_polyboxes: [ L.LatLngBounds, L.LatLngBounds, ... ] }, { ... } */ 570 ]; //VERY SIMPLE list of areas already requested, don't load if new one is inside 571 572/*contains(2) { 573 return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) && // south2 >= south && north2 <= north && 574 (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng); // west2 >= west && east2 <= east 575} 576intersects(2) { 577 latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat), 578 lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng); 579 580 return latIntersects && lngIntersects; 581}*/ 582 583/* 584 * returns true if it already was in BBOX, 585 * and false if it had to be added 586 */ 587function checkIfInRequestedBboxesAndIfNotaddTo(bounds) { 588 var north = bounds._northEast.lat, // for performance reasons, do this one time 589 east = bounds._northEast.lng, 590 south = bounds._southWest.lat, 591 west = bounds._southWest.lng; 592 var b_height = north - south, 593 b_width = east - west, 594 width_to_height = b_width/b_height; 595 596 var zoom_delta_to_max = map.getMaxZoom() - map.getZoom(), 597 min_height = b_height / (Math.pow(2,zoom_delta_to_max)); 598// console.log("checkIfInRequestedBboxesAndIfNotaddTo: viewbox_height = " + viewbox_height + "°, min_heigh = " + min_height); 599 var min_width = b_width / (Math.pow(2,zoom_delta_to_max)); 600 601 // console.log("checkIfInRequestedBboxesAndIfNotaddTo: called. bboxes_requested:" + JSON.stringify(bboxes_requested)); 602 for(var i=0; i < bboxes_requested.length; i++) { //for-loop over outer bboxes 603 var current_bound = bboxes_requested[i];
604 if(! current_bound.outer_bbox.intersects(bounds)) //neither crossing nor inside 605 continue; 606 console.log("checkIfInRequestedBboxesAndIfNotaddTo begin: " + current_bound.inner_polyboxes.length + " inner polyboxes"); 607 if(current_bound.outer_bbox.contains(bounds)) { // only if it doesn't cross outer bbox it is possible that it's already covered 608 for(var inner_bbox_i = 0; inner_bbox_i < current_bound.inner_polyboxes.length; inner_bbox_i++) { 609 current_inner_bbox = current_bound.inner_polyboxes[inner_bbox_i]; 610 if(!current_inner_bbox.hasOwnProperty("_southWest")) { 611 console.log("current_inner_bbox error:"); 612 console.log(current_inner_bbox); 613 console.log(current_bound); 614 } 615 //current_inner_bbox.contains(bounds): 616 if(south < current_inner_bbox._southWest.lat || 617 north > current_inner_bbox._northEast.lat || 618 west < current_inner_bbox._southWest.lng || 619 east > current_inner_bbox._northEast.lng) 620 continue; 621 return true; // all ¬ contains-checks failed, must be contained 622 623/* if(current_inner_bbox.contains(bounds)) { 624 // console.log("checkIfInRequestedBboxesAndIfNotaddTo: bbox already here"); 625 return true; 626 627 } //false == continue*/ 628 } 629 } 630 else //intersects one border 631 current_bound.outer_bbox.extend(bounds); 632 // either intersects with outer bbox or is not in any inner bbox 633 // add one horizontal and one vertical box that it intersects for EACH box! 634 var new_bboxes = [], 635 new_bounds_north_stretched = null, 636 new_bounds_south_stretched = null, 637 new_bounds_west_stretched = null, 638 new_bounds_east_stretched = null; 639 var nr_of_deletions = 0; 640 var addbounds = true; 641 for(var inner_bbox_i = 0; inner_bbox_i < current_bound.inner_polyboxes.length; inner_bbox_i++) { 642 current_inner_bbox = current_bound.inner_polyboxes[inner_bbox_i]; 643 644 //if ! current_inner_bbox.intersects(bounds) continue (both boxes completely disjunct) 645 if(south >= current_inner_bbox._northEast.lat || 646 north <= current_inner_bbox._southWest.lat || 647 east <= current_inner_bbox._southWest.lng || 648 west >= current_inner_bbox._northEast.lng) 649 continue; 650 651 /* 16 cases: 652 1.: bounds completely inside current_inner_bbox 653 -> is already covered by 1st for-loop with inner_polyboxes 654 2.: current_inner_bbox completely inside -> delete it; continue (empty array slots cleared afterwards) 655 -> use delete array[i], it does not reindex. reindex afterwards, remove all undefined... 656 3-10: 8 where one box is crosses only one side of the other 657 3-6: 4 where bounds is bigger 658 7-10: 4 where current_inner_bbox is bigger 659 11-14: 4 where they cross them on two sides (corner-crossing) 660 15,15: as stretching boxes can be longer, heigher it can happen that they form a "cross" -> simply add bounds, no special handling needed 661 =^= (bwb && beb && !bnb && !bsb) || (!bwb && !bwb && bnb && bsb) 662 663 * WHAT IF some bounds are equal? TODO 664 * FIXME a lot of dual boxes seem to be generated... -OK they were if a box hits one with same border 665 */ 666 667 /* TODO shrinking of bounds: 668 * stretching of inner_polyboxes is still needed, because: you don't know which side gets cut first, and if inner_polyboxes don't overlap, 669 * only a corner would get cutted out (which isn't possible on rectangles) 670 * 671 * with each run of the inner for-loop we can cut bounds smaller. if nothing left, it ... have to move first for-loop in! 672 */ 673 674 var boundsnorth_bigger = (north >= current_inner_bbox._northEast.lat), 675 boundssouth_bigger = (south <= current_inner_bbox._southWest.lat), 676 boundseast_bigger = (east >= current_inner_bbox._northEast.lng), 677 boundswest_bigger = (west <= current_inner_bbox._southWest.lng); 678 console.log("bnb:"+boundsnorth_bigger+" bsb:"+boundssouth_bigger+" beb:"+boundseast_bigger+" bwb:"+boundswest_bigger); 679 680 var bounds_bigger_on_howmany_sides = (boundsnorth_bigger ? 1 : 0) + (boundssouth_bigger ? 1 : 0) + (boundseast_bigger ? 1 : 0) + (boundswest_bigger); 681 console.log("bounds_bigger_on_howmany_sides: " + bounds_bigger_on_howmany_sides); 682 683 if(bounds_bigger_on_howmany_sides == 4) { // case 2 684 delete current_bound.inner_polyboxes[inner_bbox_i];
685 nr_of_deletions++; 686 continue; 687 } 688 689 //box is an autogenerated stretching box - these are always inside downloaded boxes, ignore for generating more. 690 if(current_inner_bbox.hasOwnProperty('stretch')) 691 continue; 692 693 if(bounds_bigger_on_howmany_sides == 3) { // cases 3-6 694 if(!boundsnorth_bigger) { // current_inner_bbox crosses bounds on north, stretch southward 695 console.log("3-6: !bnb"); 696 var inner_height = current_inner_bbox._northEast.lat - current_inner_bbox._southWest.lat; 697 var max_to_stretch = north - inner_height; 698 current_inner_bbox._southWest.lat = (max_to_stretch < south) ? south : max_to_stretch; 699 continue; 700 } 701 if(!boundssouth_bigger) { 702 console.log("3-6: !bsb"); 703 var inner_height = current_inner_bbox._northEast.lat - current_inner_bbox._southWest.lat; 704 var max_to_stretch = south + inner_height; 705 current_inner_bbox._northEast.lat = (max_to_stretch > north) ? north : max_to_stretch; 706 continue; 707 } 708 if(!boundseast_bigger) { 709 console.log("3-6: !beb"); 710 var inner_width = current_inner_bbox._northEast.lng - current_inner_bbox._southWest.lng; 711 var max_to_stretch = east - inner_width; 712 current_inner_bbox._southWest.lng = (max_to_stretch < west) ? west : max_to_stretch; 713 continue; 714 } 715 if(!boundswest_bigger) { 716 console.log("3-6: !bwb"); 717 var inner_width = current_inner_bbox._northEast.lng - current_inner_bbox._southWest.lng; 718 var max_to_stretch = west + inner_width; 719 current_inner_bbox._northEast.lng = (max_to_stretch > east) ? east : max_to_stretch; 720 continue; 721 } 722 console.log("shouldn't have reached bounds_bigger_on_howmany_sides == 3 after ????????????"); 723 } 724 if(bounds_bigger_on_howmany_sides == 1) { // cases 7-10 725 addbounds = false; // we add a bigger box instead 726 if(boundssouth_bigger) { // bounds crosses current_inner_bbox on south, stretch northwards 727 console.log("7-10: bsb"); 728 var max_to_stretch = current_inner_bbox._southWest.lat + b_height; 729 var new_north = (max_to_stretch > current_inner_bbox._northEast.lat) ? current_inner_bbox._northEast.lat : max_to_stretch; 730 if(!new_bounds_north_stretched) { 731 new_bounds_north_stretched = new L.latLngBounds( [ south, west ], [ new_north, east ] ); 732 } else { 733 if(new_bounds_north_stretched._northEast.lat < new_north) 734 new_bounds_north_stretched._northEast.lat = new_north; 735 } 736 //TODO shrink bounds! 737 continue; 738 } 739 if(boundsnorth_bigger) { // bounds crosses current_inner_bbox on north, stretch southwards 740 console.log("7-10: bnb"); 741 var max_to_stretch = current_inner_bbox._northEast.lat - b_height; 742 var new_south = (max_to_stretch < current_inner_bbox._southWest.lat) ? current_inner_bbox._southWest.lat : max_to_stretch; 743 if(!new_bounds_south_stretched) { 744 new_bounds_south_stretched = new L.latLngBounds( [ new_south, west ], [ north, east ] ); 745 } else { 746 if(new_bounds_south_stretched._southWest.lat > new_south) 747 new_bounds_south_stretched._southWest.lat = new_south; 748 } 749 //TODO shrink bounds! 750 continue; 751 } 752 if(boundseast_bigger) { // bounds crosses current_inner_bbox on east, stretch westwards 753 console.log("7-10: beb"); 754 var max_to_stretch = current_inner_bbox._northEast.lng - b_width; 755 var new_west = (max_to_stretch < current_inner_bbox._southWest.lng) ? current_inner_bbox._southWest.lng : max_to_stretch; 756 if(!new_bounds_west_stretched) { 757 new_bounds_west_stretched = new L.latLngBounds( [ south, new_west ], [ north, east ] ); 758 } else { 759 if(new_bounds_west_stretched._southWest.lng > new_west) 760 new_bounds_west_stretched._southWest.lng = new_west; 761 } 762 //TODO shrink bounds! 763 continue; 764 } 765 if(boundswest_bigger) { // bounds crosses current_inner_bbox on west, stretch eastwards 766 console.log("7-10: bwb"); 767 var max_to_stretch = current_inner_bbox._southWest.lng + b_width; 768 var new_east = (max_to_stretch > current_inner_bbox._northEast.lng) ? current_inner_bbox._northEast.lng : max_to_stretch; 769 if(!new_bounds_east_stretched) { 770 new_bounds_east_stretched = new L.latLngBounds( [ south, west ], [ north, new_east ] ); 771 } else { 772 if(new_bounds_east_stretched._northEast.lng < new_east) 773 new_bounds_east_stretched._northEast.lng = new_east; 774 } 775 //TODO shrink bounds! 776 continue; 777 }
778 console.log("shouldn't have reached bounds_bigger_on_howmany_sides == 1 after ????????????"); 779 } 780 if(bounds_bigger_on_howmany_sides == 2) { //cases 11-16 781 if( (boundswest_bigger && boundseast_bigger && !boundsnorth_bigger && !boundssouth_bigger) || 782 (!boundswest_bigger && !boundseast_bigger && boundsnorth_bigger && boundssouth_bigger) ) 783 continue; // case 15+16 784 785 /*we only need an stretching box if: 786 * xbox only if overlapping_x / width_to_height < overlap_y 787 * ybox only if overlapping_x < overlap_y * width_to_height 788 * -> either an x OR an y-box! 789 */ 790 if(boundsnorth_bigger && boundseast_bigger && !boundssouth_bigger && !boundswest_bigger) { 791 console.log("11-14: b topright, cib bottomleft "); 792 var overlap_x = current_inner_bbox._northEast.lng - west, 793 overlap_y = current_inner_bbox._northEast.lat - south; 794 if(overlap_x < overlap_y * width_to_height) { 795 //x stretching box 796 var b_N = current_inner_bbox._northEast.lat, 797 b_S = south, 798 xb_height = b_N - b_S; 799 if(xb_height <= min_height) continue; //console.log("no xb, to small"); 800 801 var x_stretch_value = xb_height * width_to_height; 802 803 var xb_E_max = west + x_stretch_value, 804 b_E = (xb_E_max > east) ? east : xb_E_max; 805 806 var xb_W_max = current_inner_bbox._northEast.lng - x_stretch_value, 807 b_W = (xb_W_max < current_inner_bbox._southWest.lng) ? current_inner_bbox._southWest.lng : xb_W_max; 808 console.log("new xb"); 809 } else { 810 //y stretching box 811 var b_E = current_inner_bbox._northEast.lng, 812 b_W = west, 813 yb_width = b_E - b_W; 814 if(yb_width <= min_width) continue; //console.log("no yb, to small"); 815 816 var y_stretch_value = yb_width / width_to_height; 817 818 var yb_N_max = south + y_stretch_value, 819 b_N = (yb_N_max > north) ? north : yb_N_max; 820 821 var yb_S_max = current_inner_bbox._northEast.lat - y_stretch_value, 822 b_S = (yb_S_max < current_inner_bbox._southWest.lat) ? current_inner_bbox._southWest.lat : yb_S_max; 823 console.log("new yb"); 824 } 825 } 826 if(boundsnorth_bigger && !boundseast_bigger && !boundssouth_bigger && boundswest_bigger) { 827 console.log("11-14: b topleft, cib bottomright ");
828 var overlap_x = east - current_inner_bbox._southWest.lng, 829 overlap_y = current_inner_bbox._northEast.lat - south; 830 if(overlap_x < overlap_y * width_to_height) {//x stretching box 831 var b_N = current_inner_bbox._northEast.lat, 832 b_S = south, 833 xb_height = b_N - b_S; 834 if(xb_height <= min_height) continue;//console.log("no xb, to small"); 835 836 var x_stretch_value = xb_height * width_to_height; 837 838 var xb_E_max = current_inner_bbox._southWest.lng + x_stretch_value, 839 b_E = (xb_E_max > current_inner_bbox._northEast.lng) ? current_inner_bbox._northEast.lng : xb_E_max; 840 841 var xb_W_max = east - x_stretch_value, 842 b_W = (xb_W_max < west) ? west : xb_W_max; 843 console.log("new xb"); 844 } else {//y stretching box 845 var b_E = east, 846 b_W = current_inner_bbox._southWest.lng, 847 yb_width = b_E - b_W; 848 if(yb_width <= min_width) continue; //console.log("no yb, to small"); 849 850 var y_stretch_value = yb_width / width_to_height; 851 852 var yb_N_max = south + y_stretch_value, 853 b_N = (yb_N_max > north) ? north : yb_N_max; 854 855 var yb_S_max = current_inner_bbox._northEast.lat - y_stretch_value, 856 b_S = (yb_S_max < current_inner_bbox._southWest.lat) ? current_inner_bbox._southWest.lat : yb_S_max; 857 console.log("new yb"); 858 } 859 } 860 if(!boundsnorth_bigger && !boundseast_bigger && boundssouth_bigger && boundswest_bigger) { 861 console.log("11-14: b bottomleft, cib topright ");
862 var overlap_x = east - current_inner_bbox._southWest.lng, 863 overlap_y = north - current_inner_bbox._southWest.lat; 864 if(overlap_x < overlap_y * width_to_height) {//x stretching box 865 var b_N = north, 866 b_S = current_inner_bbox._southWest.lat, 867 xb_height = b_N - b_S; 868 if(xb_height <= min_height) continue;//console.log("no xb, to small"); 869 870 var x_stretch_value = xb_height * width_to_height; 871 872 var xb_E_max = current_inner_bbox._southWest.lng + x_stretch_value, 873 b_E = (xb_E_max > current_inner_bbox._northEast.lng) ? current_inner_bbox._northEast.lng : xb_E_max; 874 875 var xb_W_max = east - x_stretch_value, 876 b_W = (xb_W_max < west) ? west : xb_W_max; 877 console.log("new xb"); 878 } else {//y stretching box 879 var b_E = east, 880 b_W = current_inner_bbox._southWest.lng, 881 yb_width = b_E - b_W; 882 if(yb_width <= min_width) continue; //console.log("no yb, to small"); 883 884 var y_stretch_value = yb_width / width_to_height; 885 886 var yb_N_max = current_inner_bbox._southWest.lat + y_stretch_value, 887 b_N = (yb_N_max > current_inner_bbox._northEast.lat) ? current_inner_bbox._northEast.lat : yb_N_max; 888 889 var yb_S_max = north - y_stretch_value, 890 b_S = (yb_S_max < south) ? south : yb_S_max; 891 console.log("new yb"); 892 } 893 } 894 if(!boundsnorth_bigger && boundseast_bigger && boundssouth_bigger && !boundswest_bigger) { 895 console.log("11-14: b bottomright, cib topleft ");
896 var overlap_x = current_inner_bbox._northEast.lng - west, 897 overlap_y = north - current_inner_bbox._southWest.lat; 898 if(overlap_x < overlap_y * width_to_height) {//x stretching box 899 var b_N = north, 900 b_S = current_inner_bbox._southWest.lat, 901 xb_height = b_N - b_S; 902 if(xb_height <= min_height) continue;//console.log("no xb, to small"); 903 904 var x_stretch_value = xb_height * width_to_height; 905 906 var xb_E_max = west + x_stretch_value, 907 b_E = (xb_E_max > east) ? east : xb_E_max; 908 909 var xb_W_max = current_inner_bbox._northEast.lng - x_stretch_value, 910 b_W = (xb_W_max < current_inner_bbox._southWest.lng) ? current_inner_bbox._southWest.lng : xb_W_max; 911 console.log("new xb"); 912 } else {//y stretching box 913 var b_E = current_inner_bbox._northEast.lng, 914 b_W = west, 915 yb_width = b_E - b_W; 916 if(yb_width <= min_width) continue; //console.log("no yb, to small"); 917 918 var y_stretch_value = yb_width / width_to_height; 919 920 var yb_N_max = current_inner_bbox._southWest.lat + y_stretch_value, 921 b_N = (yb_N_max > current_inner_bbox._northEast.lat) ? current_inner_bbox._northEast.lat : yb_N_max; 922 923 var yb_S_max = north - y_stretch_value, 924 b_S = (yb_S_max < south) ? south : yb_S_max; 925 console.log("new yb"); 926 } 927 } 928 stretching_box = new L.latLngBounds( [ b_S, b_W ], [ b_N, b_E ] ); 929 stretching_box.stretch = true; //add distinguishment from an orig box 930 new_bboxes.push( stretching_box ); 931 continue; 932 } 933 } 934 /* if(new_bboxes) { 935 console.log("checkIfInRequestedBboxesAndIfNotaddTo: new stretching bboxes to add:"); 936 console.log(new_bboxes); 937 } else 938 console.log("checkIfInRequestedBboxesAndIfNotaddTo: no net stretching bboxes to add.");*/ 939 940 //delete 941 if(nr_of_deletions) 942 console.log(nr_of_deletions + " to delete"); 943 for(var inner_bbox_i = 0; nr_of_deletions ; inner_bbox_i++) { 944 if(! current_bound.inner_polyboxes[inner_bbox_i]) { 945 current_bound.inner_polyboxes.splice(inner_bbox_i--,1); 946 nr_of_deletions--; 947 } 948 } 949 950 if(addbounds) 951 current_bound.inner_polyboxes.push(bounds); 952 953 for(var new_i=0; new_i < new_bboxes.length; new_i++) 954 current_bound.inner_polyboxes.push(new_bboxes[new_i]); 955 956 var stretchbounds = { 1: new_bounds_east_stretched, 2: new_bounds_west_stretched, 3: new_bounds_south_stretched, 4: new_bounds_north_stretched }; 957 for (i in stretchbounds) 958 if(stretchbounds[i]) 959 current_bound.inner_polyboxes.push(stretchbounds[i]); 960 961 console.log("checkIfInRequestedBboxesAndIfNotaddTo: " + current_bound.inner_polyboxes.length + " inner polyboxes now."); 962 return false; 963 } 964 //it is completely outside from every outer bbox, create a new one 965 var new_outer_box_deep_copy = new L.latLngBounds( [ south, west ], [ north, east ] ); 966 var bounds_deep_copy = new L.latLngBounds( [ south, west ], [ north, east ] ); 967 bboxes_requested.push( { outer_bbox: new_outer_box_deep_copy, inner_polyboxes: [ bounds_deep_copy ] } ); 968 // console.log("checkIfInRequestedBboxesAndIfNotaddTo: outside other bboxes, add a new"); 969 return false; 970} 971 972//https://stackoverflow.com/questions/1484506/random-color-generator-in-javascript 973function rainbow(numOfSteps, step) { 974 // This function generates vibrant, "evenly spaced" colours (i.e. no clustering). This is ideal for creating easily distinguishable vibrant markers in Google Maps and other apps. 975 // Adam Cole, 2011-Sept-14 976 // HSV to RBG adapted from: http://mjijackson.com/2008/02/rgb-to-hsl-
976and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript 977 var r, g, b; 978 var h = step / numOfSteps; 979 var i = ~~(h * 6); 980 var f = h * 6 - i; 981 var q = 1 - f; 982 switch(i % 6){ 983 case 0: r = 1; g = f; b = 0; break; 984 case 1: r = q; g = 1; b = 0; break; 985 case 2: r = 0; g = 1; b = f; break; 986 case 3: r = 0; g = q; b = 1; break; 987 case 4: r = f; g = 0; b = 1; break; 988 case 5: r = 1; g = 0; b = q; break; 989 } 990 var c = "#" + ("00" + (~ ~(r * 255)).toString(16)).slice(-2) + ("00" + (~ ~(g * 255)).toString(16)).slice(-2) + ("00" + (~ ~(b * 255)).toString(16)).slice(-2); 991 return (c); 992} 993 994var debugLayerShown = false; 995function toggleDebugLayer() { 996 debugLayerShown = !debugLayerShown; 997 disableLoadPOI = true; 998 if(!debugLayerShown) { 999 debugLayer.clearLayers(); 1000 disableLoadPOI = false; 1001 return; 1002 } 1003 1004 for(var i=0; i < bboxes_requested.length; i++) { 1005 var current_bound = bboxes_requested[i]; 1006 for(var inner_bbox_i = 0; inner_bbox_i < current_bound.inner_polyboxes.length; inner_bbox_i++) { 1007 current_inner_bbox = current_bound.inner_polyboxes[inner_bbox_i]; 1008 if(current_inner_bbox.stretch) 1009 console.log("stretch"); 1010 var rect = L.rectangle(current_inner_bbox, {color: rainbow(256, Math.floor(Math.random() * 256)), weight: (current_inner_bbox.stretch) ? 2 : 8, fill: false}).on('click',clickOnLayer); 1011 debugLayer.addLayer(rect); 1012 //debugLayer.addLayer(L.rectangle(current_inner_bbox, {color: rainbow(256, 128), weight: 1, fill: false})); 1013 } 1014 1015 } 1016 1017 var dup_dump = {}; 1018 var sum = 0; 1019 //find dups - there were a LOT of dups! 1020 for(var i=0; i < bboxes_requested.length; i++) { 1021 var current_bound = bboxes_requested[i]; 1022 for(var inner_bbox_i = 0; inner_bbox_i < current_bound.inner_polyboxes.length; inner_bbox_i++) { 1023 current_inner_bbox = current_bound.inner_polyboxes[inner_bbox_i]; 1024 var north = L.Util.formatNum(current_inner_bbox._northEast.lat,7), 1025 east = L.Util.formatNum(current_inner_bbox._northEast.lng,7), 1026 south = L.Util.formatNum(current_inner_bbox._southWest.lat,7), 1027 west = L.Util.formatNum(current_inner_bbox._southWest.lng,7); 1028 1029 //sort dup_dumps on north,east,south,west coordinate 1030 // dump[north][east][south][west] = true if bbox exists 1031 if(!dup_dump[north]) { 1032 var west_obj = 1; 1033 var south_obj = {}; 1034 south_obj[west] = west_obj; 1035 var east_obj = {}; 1036 east_obj[south] = south_obj; 1037 var north_obj = {}; 1038 north_obj[east] = east_obj; 1039 dup_dump[north] = north_obj; 1040 } else { 1041 if(!dup_dump[north][east]) { 1042 var west_obj = 1; 1043 var south_obj = {}; 1044 south_obj[west] = west_obj; 1045 var east_obj = {}; 1046 east_obj[south] = south_obj; 1047 dup_dump[north][east] = east_obj; 1048 } else { 1049 if(!dup_dump[north][east][south]) { 1050 var west_obj = 1; 1051 var south_obj = {}; 1052 south_obj[west] = west_obj; 1053 dup_dump[north][east][south] = south_obj; 1054 } else { 1055 if(!dup_dump[north][east][south][west]) { 1056 dup_dump[north][east][south][west] = 1; 1057 } else { 1058 dup_dump[north][east][south][west]++; 1059 } 1060 } 1061 } 1062 } 1063 } 1064 var different = 0; 1065 var dups = 0; 1066 for(n in dup_dump) { 1067 for(e in dup_dump[n]) { 1068 for(s in dup_dump[n][e]) { 1069 for(w in dup_dump[n][e][s]) { 1070 console.log("n"+n+" e"+e+" s"+s+" w"+w+" : "+ dup_dump[n][e][s][w]); 1071 dups = dups + dup_dump[n][e][s][w] -1; 1072 different++; 1073 } 1074 } 1075 } 1076 } 1077 console.log(dup_dump); 1078 console.log("unique: "+different+" of " + current_bound.inner_polyboxes.length + ", " + dups + " dups"); 1079 } 1080} 1081 1082function clickOnLayer(e) { 1083 console.log(e.target._parts); 1084// e.bringToFront(); 1085} 1086 1087var wikidata_mappings = { tags : {}, ids : {} }, 1088 translations = { tags: {} }; 1089 1090/* how to get object descriptions: 1091ask wikidata for an object that has osm property $object_tag 1092https://wdq.wmflabs.org/api?q=string[214:%2264192849%22] 1093osm tag property is P1282 1094 1095https://wdq.wmflabs.org/api?q=string[1282:"Tag:amenity=restaurant"] 1096* takes object_tag = "key=value" 1097*/ 1098function fetchTranslationsFromWikiData(object_tag) { 1099 if(object_tag.indexOf("=") == -1) { 1100 console.log("Error in fetchTranslationsFromWikiData: tag has to be in key=value format, not :'" + object_tag + "'"); 1101 return; 1102 } 1103 1104 var kv = object_tag.split("="), 1105 value = kv[1], 1106 osm_string = (value == "yes") ? "Key:" + kv[0] : "Tag:" + object_tag; 1107 1108 1109 if(!wikidata_mappings.tags[object_tag]) { 1110 var wikidata_query = 'https://wdq.wmflabs.org/api?q=string[1282:"' + osm_string + '"]'; //FIXME is it possible to retrieve page Q$id in one call? 1111 /* 1112 returns 1113 {"status":{ 1114 "error":"OK", 1115 "items":1, 1116 "querytime":"0ms", 1117 "parsed_query":"STRING[1282:'Tag:amenity=restaurant']"}, 1118 "items":[11707] 1119 } 1120 */ 1121 1122 $.getJSON(wikidata_query + "&callback=?", function(data) { 1123 if(data.status.error != "OK") { 1124 console.log("wikidata returned " + data.status.error + " for query '" + data.status.parsed_query + "'."); 1125 return; 1126 } 1127 var tag_array = data.status.parsed_query.match(/1282:'(Tag|Key):([a-z:_0-9-]+)[=]?(.*)']$/); 1128 var tag = (tag_array[1] == "Key" ) ? tag_array[2] + "=yes" : tag_array[2] + "=" + tag_array[3]; 1129 console.log("wdm: " + tag); 1130 if(data.items.length == 0) { 1131 console.log("nothing found in wikidata for query '" + data.status.parsed_query + "'."); 1132 console.log(data);
1133 wikidata_mappings.tags[tag] = -1; 1134 return; 1135 } 1136 var item; 1137 for(var i=0; i < data.items.length; i++) { //takes last one 1138 item = data.items[i]; 1139 //console.log("got answer from wikidata for query '" + data.status.parsed_query + "': '" + item + "'."); 1140 } 1141 1142 wikidata_mappings.tags[tag] = "Q" + item; 1143 wikidata_mappings.ids["Q" + item] = tag; 1144 1145 var wikidata_object_query = "https://www.wikidata.org/wiki/Special:EntityData/Q" + item + ".json"; //Note: throws CORS error if item == undefined 1146 $.getJSON(wikidata_object_query, function(data) { 1147 if(!data.entities) { 1148 console.log("wikidata returned no entities"); 1149 return; 1150 } 1151 for(q_number in data.entities) { 1152 var item = data.entities[q_number]; 1153 translations.tags[wikidata_mappings.ids[q_number]] = item.labels; 1154 } 1155 setTimeout(setTranslationsInPopup,100); 1156 }); 1157 }); 1158 wikidata_mappings.tags[object_tag] = "loading"; 1159 } 1160} 1161 1162/* out of given tags, looks up "main keys" out of global var object_type_keys, 1163 * and returns a nice array with each tag split up in a single entry 1164 * tags[ "amenity=cafe; fast_food", "shop=bakery", ... ] → [ "amenity=cafe", "amenity=fast_food", "shop=bakery" ] 1165 */ 1166function getMainTags(tags) { 1167 object_tags = []; 1168 for(var i=0; i < object_type_keys.length; i++) { 1169 var key = object_type_keys[i]; 1170 if(tags[key]) { 1171 var value = tags[key]; 1172 if(value.indexOf(";") >= 0) { 1173 var values = value.split(";"); 1174 for (var j=0; j < values.length; j++) { 1175 object_tags.push(key + "=" + values[j].trim()); 1176 } 1177 } 1178 else 1179 object_tags.push(key + "=" + value); 1180 } 1181 } 1182 console.log(object_tags); 1183 return object_tags; 1184} 1185 1186function loadPoi() { 1187 1188 var notificationbar = document.getElementById("notificationbar"); 1189 if (map.getZoom() < overpass_config.minzoom ) { 1190 notificationbar.style.display = "block"; 1191 if(on_start_loaded && window.createSideBar) { 1192 var json_date = new Date(pois_lz.osm3s.timestamp_osm_base); 1193 $('#tall').html("Lowzoom data: " + json_date.toLocaleString()); 1194 $('#tnode').css("display", "hidden"); 1195 $('#tway').css("display", "hidden"); 1196 $('#trel').css("display", "hidden"); 1197 return; 1198 } 1199 1200 if(pois_lz) { 1201 console.log(pois_lz); 1202 console.log("adding lz POIs"); 1203 1204 changeLoadingIndicator("loading_node",+1); 1205 handleNodes(pois_lz); 1206 1207 changeLoadingIndicator("loading_way",+1); 1208 handleWays(pois_lz); 1209 1210 changeLoadingIndicator("loading_relation",+1); 1211 handleRelations(pois_lz); 1212 1213 if(window.createSideBar) { 1214 var json_date = new Date(pois_lz.osm3s.timestamp_osm_base); 1215 $('#tall').html("Lowzoom data: " + json_date.toLocaleString()); 1216 $('#tnode').css("display", "hidden"); 1217 $('#tway').css("display", "hidden"); 1218 $('#trel').css("display", "hidden"); 1219 } 1220 1221 on_start_loaded = 1; 1222 } 1223 1224 return; 1225 } 1226 notificationbar.style.display = "none"; 1227 1228 var current_zoom = map.getZoom(); 1229 console.log("loadPOI called, z" + current_zoom); 1230 if(current_zoom > old_zoom && current_zoom != overpass_config.minzoom) { 1231 console.log("zooming in, POI already loaded, nothing to to"); 1232 old_zoom = current_zoom; 1233 return; 1234 } 1235 old_zoom = current_zoom; 1236 1237 if(disableLoadPOI) 1238 return; 1239 1240 // if Graz (start position, gets called once first) do nothing 1241 var centre = map.getCenter(); 1242 if (centre.lat == 47.07 && centre.lng == 15.43) { 1243 var splitstr = window.location.href.split('#'); 1244 if (splitstr[1]) { 1245 var coords_href = splitstr[1].split('/'); 1246 if ( coords_href[1] == 47.07 && coords_href[2] == 15.43 ) 1247 console.log("look, we are really in Graz"); 1248 else { 1249 console.log("1st call, return"); 1250 return; 1251 } 1252 } 1253 } 1254 1255 var bounds = map.getBounds(); 1256 if(checkIfInRequestedBboxesAndIfNotaddTo(bounds)) 1257 return; 1258 1259 function url_ify(link,linktext) { 1260 if (/@/.test(link)) { 1261 return '<a href="mailto:' + link + '">' + secHTML(linktext) + '</a>'; 1262 } else if (/^[0-9-+\s]*$/.test(link)) { 1263 return '<a href="tel:' + link + '">' + linktext.replace(/\s/g," ") + '</a>'; //FIXME how to prefix fax nrs? 1264 } else { 1265 if ( ! /^http/.test(link) ) //http[s] is implicit here 1266 link = "http://" + link; 1267 return $("<div>").append( $('<a>').attr('href', link).text(linktext) ).html(); 1268 } 1269 } 1270 1271 function fillPopup(tags,type,id,lat,lon) { 1272 1273 var tags_to_ignore = [ "name" , "ref", "addr:street", "addr:housenumber", "addr:postcode", "addr:city", "addr:suburb", "addr:country","website","url","contact:website","contact:url","email","contact:email","phone","contact:phone","fax","contact:fax","created_by","area","layer","room","indoor","twitter","contact:twitter","link:twitter", "contact:google_plus", "google_plus", "link:google_plus", "contact:facebook","facebook","link:facebook","facebook:page","website:facebook","url:facebook","contact:youtube","youtube","link:youtube","wheelchair","wheelchair:description","wikipedia","wikidata","image" ]; 1274 1275 var r = $('<table>'); 1276 1277 var href = location.href.replace(/#.*$/,'').replace(/[&?]popup=(node|way|relation)[0-9]+/,''); 1278 var hasQuery = href.indexOf("?") + 1; 1279 var appendix = (hasQuery ? "&" : "?") + "popup=" + type + id; 1280 1281 var popup_href = href + appendix + '#' + map.getZoom() + '/' + lat + '/' + lon; 1282 1283 r.append($('<tr>') 1284 .attr('class','header') 1285 .append($('<td>').append('<a href="' + popup_href + '" title="Link to this POI on this map">Permalink</a>')) 1286 .append($('<td>').append('<a href="http://editor.transformap.co/#background=Bing&id=' + type.substring(0,1) + id + '&map=19/' + lon + '/' + lat + '" title="Edit this object with iD for TransforMap" target=_blank>Edit</a>')) 1287 ); 1288 r.append($('<tr>') 1289 .attr('class','header') 1290 .append($('<td>').append('<a href="https://www.openstreetmap.org/' + type + "/"
1290+ id + '" title="Link to ' + type + ' ' + id + ' on OpenStreetMap" target=_blank><img src="'+assethost+'assets/20px-Mf_' + type + '.svg.png" />' + type.substring(0,1) + id + '</a>')) 1291 .append($('<td>').append('<a href="http://map.project-osrm.org/?dest=' + lat + ',' + lon + '&destname=' + tags['name'] + '" target=_blank title="Route here with OSRM">Route Here</a>')) 1292 ); 1293 var wikipedia_link = ""; 1294 1295 function addSocialMediaLinks(tags) { 1296 var string = ""; 1297 1298 for (key in tags) { 1299 var value = tags[key].replace(/^http[s]?:\/\//,""); //we add https later, regardless of link 1300 var valuestring = decodeURIComponent(value); 1301 var img = "<img src='"+assethost+"assets/"; 1302 1303 if(/twitter/.test(key)) { 1304 if(! /twitter.com\//.test(value)) valuestring = "twitter.com/" + valuestring; 1305 img += "twitter.16.png' title='on Twitter' />"; 1306 } else 1307 if(/facebook/.test(key) || (/facebook.com\/|fb.com\//.test(value) && /website/.test(key)) ) { 1308 if(! /facebook.com\/|fb.com\//.test(value)) valuestring = "facebook.com/" + valuestring; 1309 img += "facebook.16.png' title='Facebook-page' />"; 1310 } else 1311 if(/google_plus/.test(key)) { 1312 if(! /plus.google.com\//.test(value)) valuestring = "plus.google.com/" + valuestring; 1313 img += "g+.16.png' title='Google+ page' />"; 1314 } else 1315 if(/youtube/.test(key)) { 1316 if(! /youtube.com\//.test(value)) valuestring = "youtube.com/" + valuestring; 1317 img += "YouTube.16.png' title='YouTube channel' />"; 1318 } else 1319 if(/^wikipedia/.test(key)) { 1320 var lang = key.match(/^(?:wikipedia:)([a-z-]{2,7})$/) || ""; // if value starts with e.g. "de:ARTICLE", this works in WP anyway 1321 if(! /wikipedia\./.test(value)) valuestring = "wikipedia.org/wiki/" + valuestring; 1322 if(lang) valuestring = lang[1] + "." + valuestring; 1323 1324 img += "wikipedia.16.png' title='Wikipedia Article' />"; 1325 wikipedia_link = "https://" + valuestring; 1326 } else 1327 if(/wikidata/.test(key)) { 1328 if(! /wikidata.org\//.test(value)) valuestring = "wikidata.org/wiki/" + valuestring; 1329 img += "wikidata.16.png' title='Wikidata Entry' />"; 1330 } else 1331 continue; 1332 1333 valuestring = "https://" + valuestring; 1334 1335 string += "<a href='" + valuestring + "'>" + img + "</a> "; 1336 } 1337 1338 return string; 1339 } 1340 1341 var social_media_links = addSocialMediaLinks(tags); 1342 1343 if(tags["addr:street"] || tags["addr:housenumber"] || tags["addr:postcode"] || tags["addr:city"] || tags["addr:suburb"] || tags["addr:country"] 1344 || tags["website"] || tags["url"] || tags["contact:website"] || tags["contact:url"] || tags["email"] || tags["contact:email"] 1345 || tags["phone"] || tags["contact:phone"] || tags["fax"] || tags["contact:fax"] || tags["wheelchair"] || social_media_links) { 1346 r.append($('<tr>') 1347 .attr('class','header') 1348 .append($('<td>').append( 1349 (tags["addr:street"] ? tags["addr:street"] : "" ) + 1350 (tags["addr:housenumber"] ? (" " + tags["addr:housenumber"]) : "" ) + 1351 ( (tags["addr:housenumber"] || tags["addr:street"]) ? ",<br>" : "" ) + 1352 (tags["addr:postcode"] ? (tags["addr:postcode"] + " ") : "" ) + 1353 (tags["addr:city"] ? tags["addr:city"] : "" ) + 1354 (tags["addr:suburb"] ? "-" + tags["addr:suburb"] : "") + 1355 (tags["addr:country"] ? "<br>" + tags["addr:country"] : "") + 1356 (tags["wheelchair"] ? ("<br><img class='wheelchair " + tags["wheelchair"] + "' src='"+assethost+"assets/disability-18.png' title='wheelchair: " + 1357 ( (tags["wheelchair"] == "yes") ? "100% accessible" : 1358 ( (tags["wheelchair"] == "limited" ) ? "limited (assist needed)" : 1359 ( (tags["wheelchair"] == "no") ? "no" : tags["wheelchair"] ) ) ) + 1360 ( tags["wheelchair:description"] ? ("\n" + secHTML(tags["wheelchair:description"])) : "" ) 1361 + "'/>") : "") 1362 )) 1363 .append($('<td>').append( 1364 (tags["website"] ? (url_ify(tags["website"],"website") + "<br>") : "" ) + 1365 (tags["url"] ? (url_ify(tags["url"],"website") + "<br>") : "" ) + 1366 (tags["contact:website"] ? (url_ify(tags["contact:website"],"website") + "<br>") : "" ) + 1367 (tags["contact:url"] ? (url_ify(tags["contact:url"],"website") + "<br>") : "" ) + 1368 1369 (tags["email"] ? (url_ify(tags["email"],"email") + "<br>") : "" )+ 1370 (tags["contact:email"] ? (url_ify(tags["contact:email"],"email") + "<br>") : "" ) + 1371 1372 (tags["phone"] ? (url_ify(tags["phone"], "Tel: " + tags["phone"]) + "<br>") : "" ) + 1373 (tags["contact:phone"] ? (url_ify(tags["contact:phone"], "Tel: " + tags["contact:phone"]) + "<br>") : "" ) + 1374 1375 (tags["fax"] ? (url_ify(tags["fax"], "Fax: " + tags["fax"]) + "<br>") : "" ) + 1376 (tags["contact:fax"] ? (url_ify(tags["contact:fax"], "Fax: " + tags["contact:fax"]) + "<br>") : "" ) + 1377 1378 social_media_links 1379 1380 ))); 1381 } 1382 var wp_articlename = ""; 1383 for (key in tags) { 1384 if(/^wikipedia/.test(key)) { 1385 var value = tags[key];
1386 var lang = key.match(/^(?:wikipedia:)([a-z-]{2,7})$/) || value.match(/^([a-z-]{2,7}):/) || ""; 1387 lang = (lang) ? lang[1] : "en"; 1388 1389 if(! /wikipedia\./.test(value)) 1390 wp_articlename = value; 1391 else { 1392 wp_articlename = value.replace(/^http[s]?:\/\//,'') 1393 .replace(/^www\./,'') 1394 .replace(/^([a-z-]{2,7})\.wikipedia/,'') 1395 .replace(/^wikipedia\./,'') 1396 .replace(/^[a-z]{2,3}\/wiki\//,''); 1397 } 1398 wp_articlename = wp_articlename.replace(/^[a-z-]{2,7}:/,''); 1399 var article_id = "wpimage_" + wp_articlename; // we must omit LANG here, as we don't have a way to get lang in callback function run on wikipedia's answer FIXME breaks on 2 wp links, when the first one is non-english... 1400 1401 var req_string = "https://" + lang + ".wikipedia.org/w/api.php?action=query&titles=" + wp_articlename + "&prop=pageimages&format=json&pithumbsize=276"; 1402 1403 $.getJSON(req_string + "&callback=?", function(data) { 1404 for(obj_id in data.query.pages) { 1405 var item = data.query.pages[obj_id]; 1406 // console.log("got answer from wikipedia for " + item.title + "."); 1407 if(item.thumbnail) { 1408 wikipedia_images["wpimage_" + item.title] = item.thumbnail.source; 1409 } else { 1410 wikipedia_images["wpimage_" + item.title] = "UNDEF"; 1411 console.log("no WP image for " + item.title); 1412 } 1413 } 1414 setTimeout(setImageInPopup,100); //needed here too if site called with popup open 1415 }); 1416 1417 r.append($('<tr>') 1418 .attr('class','header') 1419 .append("<td colspan=2 id='wp-image'><img id='" +article_id + "' title='" + wp_articlename + "'/><a href='" + wikipedia_link +"'>© Wikipedia</a></td>" )//only one popup shall be open at a time for the id to be unique 1420 ); 1421 1422 } 1423 } 1424 if(tags['image']) { 1425 if(tags['image'].match(/^File:/)) { 1426 var imagename = tags['image'].replace(/ /,"_"); 1427 var req_string = "https://commons.wikimedia.org/w/api.php" 1428 + "?action=query" 1429 + "&format=json" 1430 + "&titles=" + imagename 1431 + "&prop=imageinfo" 1432 + "&iiprop=url" 1433 + "&iiurlwidth=276"; 1434 $.getJSON(req_string+ "&callback=?", function(data) { 1435 for(obj_id in data.query.pages) { 1436 var item = data.query.pages[obj_id]; 1437 console.log("got answer from wikimedia commons for " + item.title + "."); 1438 if(item.imageinfo[0]) { 1439 var item_name = decodeURIComponent(item.imageinfo[0].descriptionurl.replace(/.*\//,'')); //item.title is with spaces instead of underscores. 1440 wikipedia_images["wpimage_" + item_name] = item.imageinfo[0].thumburl; 1441 } else { 1442 wikipedia_images["wpimage_" + item.title.replace(/ /,"_") ] = "UNDEF"; 1443 console.log("no WP image for " + item.title); 1444 } 1445 } 1446 setTimeout(setImageInPopup,100); //needed here too if site called with popup open 1447 }); 1448 1449 r.append($('<tr>') 1450 .attr('class','header') 1451 .append("<td colspan=2 id='wp-image'><img id='" + imagename + "' title='" + imagename + "'/><a href='https://commons.wikimedia.org/wiki/" + imagename + "'>© Wikipedia</a></td>" ) 1452 // FIXME attribution/License must be set on return of c
1452all 1453 ); 1454 1455 1456 } 1457 else if( ! (wp_articlename && tags['image'].match(/wiki(pedia|media)/)) ) { 1458 r.append($('<tr>') 1459 .attr('class','header') 1460 .append("<td colspan=2 id='image'><img src='" + tags['image'] + "' style='width:276px;' /></td>" )//only one popup shall be open at a time for the id to be unique 1461 ); 1462 } 1463 } 1464 1465 1466 1467 for (key in tags) { 1468 var value = tags[key]; 1469 if ( tags_to_ignore.indexOf(key) >= 0) 1470 continue; 1471 1472 if ( key == 'website' || key == 'url' || key == 'contact:website' || key == 'contact:url') { 1473 var teststr=/^http/; //http[s] is implicit here 1474 if ( ! teststr.test(value) ) 1475 value = "http://" + value; 1476 1477 var htlink = '<a href="' + value + '">' + value + '</a>'; 1478 r.append($('<tr>').append($('<th>').text(key)).append($('<td>').append(htlink))); 1479 } else if ( /^wikipedia/.test(key)) { 1480 var lang = key.match(/^(?:wikipedia:)([a-z-]{2,7})$/) || ""; // if value starts with e.g. "de:ARTICLE", this works in WP anyway 1481 var begin = (! /^http/.test(value)) ? "https://" + ((lang) ? (lang[1] + ".") : "") + "wikipedia.org/wiki/" : ""; //http[s] is implicit here 1482 1483 var htlink = $('<a>').attr('href', begin + value).text(decodeURIComponent(value)); 1484 r.append($('<tr>').addClass('tag').append($('<th>').text(key)).append($('<td>').append(htlink))); 1485 } else if ( key == 'wikidata' ) { 1486 var begin = (! /^http/.test(value)) ? "https://www.wikidata.org/wiki/" : ""; //http[s] is implicit here 1487 1488 var htlink = $('<a>').attr('href', begin + value).text(decodeURIComponent(value)); 1489 r.append($('<tr>').addClass('tag').append($('<th>').text(key)).append($('<td>').append(htlink))); 1490 } else if (key == 'contact:email' || key == 'email') { 1491 if ( ! /^mailto:/.test(value) ) 1492 value = "mailto:" + value; 1493 1494 var htlink = $('<a>').attr('href', value).text(value); 1495 r.append($('<tr>').addClass('tag').append($('<th>').text(key)).append($('<td>').append(htlink))); 1496 } else { 1497 var key_escaped = secHTML(key); 1498 var value_escaped = secHTML(value); 1499 1500 var keytext = key_escaped.replace(/:/g,":<wbr />"); 1501 var valuetext = "<span>= </span>" + value_escaped.replace(/;/g,"; "); 1502 1503 /* display label:* instead of key */ 1504 /* 1505 var found = 0; // use for break outer loops 1506 1507 for ( groupname in taxonomy ) { // e.g. "fulfils_needs" : {}=group 1508 group = taxonomy[groupname]; 1509 1510 var count_items = group["items"].length; 1511 for (var i = 0; i < count_items; i++) { // loop over each item in group["items"] 1512 item = group["items"][i]; 1513 if(item["osm:key"] == keytext) { 1514 keytext = "<em>" + item.label["en"] + "</em>"; //<em> for displaying a translated value 1515 found = 1; 1516 break; 1517 } 1518 } 1519 if(found == 1) 1520 break; // for ( groupname in taxonomy ) 1521 } 1522 */ 1523 1524 r.append($('<tr>').addClass('tag') 1525 .append($('<th>').append(keytext)) 1526 .append($('<td>').append(valuetext)) 1527 ); 1528 } 1529 1530 } // end for (key in tags) 1531 1532 var s = $('<div>'); 1533 s.append(r); 1534 var retval = $('<div>').append(s); 1535 1536 var object_tags = getMainTags(tags), 1537 object_text = "unknown feature"; 1538 1539 if(object_tags.length) {
1540 object_tags.forEach(function (currentValue) { 1541 fetchTranslationsFromWikiData(currentValue); 1542 }); 1543 1544 object_text = object_tags.join(", "); 1545 } 1546 1547 retval.prepend($('<h3>') 1548 .attr("translated","untranslated") 1549 .attr("title", (object_text == "unknown feature") ? "This Object has no known OSM tag set" : object_text ) 1550 .attr("sourcetext", object_text ) 1551 .append($("<span>") 1552 .text(object_text)) 1553 .append($("<span>") 1554 .text("?") 1555 .attr("title","Click here to show where this value comes from")) 1556 ); 1557 retval.prepend($('<h1>').text(tags["name"])); 1558 return retval.html(); 1559 } 1560 1561 function bindPopupOnData(data) { 1562 // first: check if no item with this osm-id exists... 1563 var hashtable_key = data.type + data.id; // e.g. "node1546484546" 1564 if(marker_table[hashtable_key] == 1) //object already there 1565 return; 1566 marker_table[hashtable_key] = 1; 1567 1568 if(!data.tags) { 1569 console.log("no tags on:"); 1570 console.log(data); 1571 return; 1572 } 1573 if(data.tags.disused == "yes" || data.tags.opening_hours == "off" || data.tags["disused:shop"] || data.tags["disused:amenity"]) { 1574 console.log("object disused:" + data.type + data.id); 1575 return; 1576 } 1577 1578 var icon_url = chooseIconSrc(data.tags,overpass_config.icon_size); 1579 1580 var icon_class = (overpass_config.class_selector_key && data.tags[overpass_config.class_selector_key["key"]]) ? overpass_config.class_selector_key["key"] : "color_undef"; 1581 1582 var needs_icon = L.icon({ 1583 iconUrl: icon_url, 1584 iconSize: new L.Point(overpass_config.icon_size, overpass_config.icon_size), 1585 iconAnchor: new L.Point(overpass_config.icon_size / 2, overpass_config.icon_size / 2), 1586 popupAnchor: new L.Point(0, - overpass_config.icon_size / 2), 1587 className: "v-" + data.tags[icon_class] + " k-" + icon_class 1588 }); 1589 1590 var pdata = { 1591 lat: data.lat, 1592 lon: data.lon, 1593 id: data.id, 1594 type: data.type, 1595 icon: needs_icon, 1596 title: data.tags.name, 1597 popup: fillPopup(data.tags,data.type,data.id,data.lat,data.lon), 1598 tags: data.tags 1599 } 1600 var pmarker = new PruneCluster.Marker(data.lat, data.lon, pdata); 1601 1602 return pmarker; 1603 } 1604 1605 function nodeFunction(data) { 1606 if (! data.tags) 1607 return null; 1608 1609 var is_one_of_queried=0; // for filtering out tagged nodes which are part of ways 1610 for ( var i = 0; i < overpass_config.q_array.length; i++) { 1611 var res = overpass_config.q_array[i][0].replace(/["]?/,"").replace(/["].*$/,""); 1612 if(data.tags[res]) { 1613 is_one_of_queried=1; 1614 break; 1615 } 1616 } 1617 if (! data.tags.name && ! is_one_of_queried) 1618 return; 1619 if (! data.tags.name && data.tags.entrance) 1620 return null; 1621 return bindPopupOnData(data); 1622 } 1623 function wayFunction(data) { 1624 //calculate centre of polygon 1625 1626 var centroid = $.geo.centroid(data.geometry); 1627 //var style = {}; 1628 centroid.tags = data.tags; 1629 centroid.id = data.id; 1630 centroid.type = data.type; 1631 centroid.lon = centroid.coordinates[0]; 1632 centroid.lat = centroid.coordinates[1]; 1633 return bindPopupOnData(centroid); 1634 } 1635 function relationFunction(data) { 1636 // calculate mean coordinates as center 1637 // for all members, calculate centroid 1638 // then calculate mean over all nodes and centroids. 1639 var centroids = []; 1640 var sum_lon = 0; 1641 var sum_lat = 0; 1642 //console.log(data); 1643 for (var i = 0; i < data.members.length; i++) { 1644 var p = data.members[i]; 1645 var centroid; 1646 switch (p.type) { 1647 case 'node': 1648 1649 if(!p.obj) { 1650 console.log("!p.obj: "); 1651 console.log(p); 1652 } else { 1653 centroid = p.obj.coordinates; 1654 centroids.push(centroid); 1655 } 1656 break; 1657 case 'way': 1658 //console.log(p); 1659 if (p.role == "outer") {// FIXME add handling of rel members 1660 if(!p.obj) { 1661 console.log("!p.obj: "); 1662 console.log(p); 1663 } else { 1664 var centroid_point = $.geo.centroid(p.obj.geometry); 1665 centroid = centroid_point.coordinates; 1666 centroids.push(centroid); 1667 } 1668 } 1669 break; 1670 } 1671 if(centroid){ 1672 if(centroid.length != 0) { 1673 sum_lon += centroid[0]; 1674 sum_lat += centroid[1]; 1675 } else 1676 console.log("centroid empty!"); 1677 } else 1678 console.log("centroid nonexisting!"); 1679 1680 } 1681 //console.log(centroids); 1682 var sum_centroid = { 1683 id : data.id, 1684 lon : sum_lon / data.members.length, 1685 lat : sum_lat / data.members.length, 1686 tags : data.tags, 1687 type : data.type 1688 } 1689 1690 //console.log(sum_centroid); 1691 return bindPopupOnData(sum_centroid); 1692 // todo: in the long term, all areas should be displayed as areas (as in overpass turbo) 1693 } 1694 1695 function handleNodes(overpassJSON) { 1696 var pid; 1697 for(i_pid in pids.node.active) { 1698 if(pids.node.active[i_pid].state == "timeouted") 1699 continue; 1700 if(JSON.stringify(pids.node.active[i_pid].bounds) === JSON.stringify(overpassJSON.bounds)) { 1701 pid = i_pid; 1702 delete pids.node.active[i_pid]; 1703 break; 1704 } 1705 } 1706 console.log("handleNodes called (pid " + pid + ")"); 1707 1708 var new_markers = []; 1709 for (var i = 0; i < overpassJSON.elements.length; i++) { 1710 var p = overpassJSON.elements[i]; 1711 if(p.type != 'node') 1712 continue; 1713 p.coordinates = [p.lon, p.lat]; 1714 p.geometry = {type: 'Point', coordinates: p.coordinates}; 1715 1716 var retval = nodeFunction(p); 1717 if (retval) { 1718 if(window.filters) 1719 retval.filtered = ! getFilterStatusOnPoi(retval); 1720 new_markers.push(retval); 1721 } 1722 } 1723 var number = new_markers.length; 1724 if(number) { 1725 markers.RegisterMarkers(new_markers); 1726 markers.ProcessView(); 1727 if(window.createSideBar) { 1728 var json_date = new Date(overpassJSON.osm3s.timestamp_osm_base); 1729 $('#tnode').css("display", "block");
1730 $('#tnode').html(json_date.toLocaleString()); 1731 updateElementCount(); 1732 updatePOIlist(); 1733 if(window.filters) 1734 updateFilterCount(); // TODO it is relatively inefficient to run check all filters every time a single entry is changed - later only the filters affected on change should be counted 1735 } 1736 new_markers = []; 1737 } 1738 1739 changeLoadingIndicator("loading_node", -1); 1740 if(! open_popup_on_load.already_shown && open_popup_on_load.type == "node") { 1741 open_popup_on_load.already_shown = true; 1742 setTimeout(function () { 1743 MytogglePopup(open_popup_on_load.type, open_popup_on_load.id); 1744 },200 ); 1745 } 1746 console.log("handleNodes (pid " + pid + ") done, " + number + " added."); 1747 } 1748 function handleWays(overpassJSON) { 1749 var pid; 1750 for(i_pid in pids.way.active) { 1751 if(pids.way.active[i_pid].state == "timeouted") 1752 continue; 1753 if(JSON.stringify(pids.way.active[i_pid].bounds) === JSON.stringify(overpassJSON.bounds)) { 1754 pid = i_pid; 1755 delete pids.way.active[i_pid]; 1756 break; 1757 } 1758 } 1759 if(!pid) { 1760 //console.log("handleWays: JSON bounds:"); 1761 //console.log(overpassJSON.bounds); 1762 //console.log("handleWays: pid way objects:"); 1763 //console.log(pids.way.active); 1764 1765 //FIXME BUG: the french overpass server (used for ways) doesn't supply the bounds... 1766 for(i_pid in pids.way.active) { 1767 if(pids.way.active[i_pid].state == "timeouted") 1768 continue; 1769 pid = i_pid; 1770 break;// get first one 1771 } 1772 delete pids.way.active[pid]; 1773 } 1774 console.log("handleWays called (pid " + pid + ")"); 1775 1776 var new_markers = []; 1777 var nodes = {}; 1778 for (var i = 0; i < overpassJSON.elements.length; i++) { 1779 var p = overpassJSON.elements[i]; 1780 switch (p.type) { 1781 case 'node': 1782 p.coordinates = [p.lon, p.lat]; 1783 p.geometry = {type: 'Point', coordinates: p.coordinates}; 1784 nodes[p.id] = p; 1785 break; 1786 case 'way': 1787 p.coordinates = p.nodes.map(function (id) { 1788 return nodes[id].coordinates; 1789 }); 1790 p.geometry = {type: 'LineString', coordinates: p.coordinates}; 1791 1792 var retval = wayFunction(p); 1793 if (retval) { 1794 if(window.filters) 1795 retval.filtered = ! getFilterStatusOnPoi(retval); 1796 new_markers.push(retval); 1797 } 1798 } 1799 } 1800 1801 var number = new_markers.length; 1802 if(number) { 1803 markers.RegisterMarkers(new_markers); 1804 markers.ProcessView(); 1805 if(window.createSideBar) { 1806 var json_date = new Date(overpassJSON.osm3s.timestamp_osm_base); 1807 $('#tway').css("display", "block"); 1808 $('#tway').html(json_date.toLocaleString()); 1809 updateElementCount(); 1810 updatePOIlist(); 1811 if(window.filters) 1812 updateFilterCount(); // TODO it is relatively inefficient to run check all filters every time a single entry is changed - later only the filters affected on change should be counted 1813 } 1814 new_markers = []; 1815 } 1816 1817 changeLoadingIndicator("loading_way", -1); 1818 if(! open_popup_on_load.already_shown && open_popup_on_load.type == "way") { 1819 open_popup_on_load.already_shown = true; 1820 setTimeout(function () { 1821 MytogglePopup(open_popup_on_load.type, open_popup_on_load.id); 1822 },200 ); 1823 } 1824 console.log("handleWays (pid " + pid + ") done, " + number + " added."); 1825 } 1826 function handleRelations(overpassJSON) { 1827 var pid; 1828 for(i_pid in pids.relation.active) { 1829 if(pids.relation.active[i_pid].state == "timeouted") 1830 continue; 1831 if(JSON.stringify(pids.relation.active[i_pid].bounds) === JSON.stringify(overpassJSON.bounds)) { 1832 pid = i_pid; 1833 delete pids.relation.active[i_pid]; 1834 break; 1835 } 1836 } 1837 console.log("handleRelations called (pid " + pid + ")"); 1838 var nodes = {}, ways = {}; 1839 1840 //overpass returns elements unsorted: rels, nodes, ways - should be nodes, ways, rels 1841 var rels = []; // to handle them last 1842 1843 var new_markers = []; 1844 //console.log(overpassJSON.elements); 1845 for (var i = 0; i < overpassJSON.elements.length; i++) { 1846 var p = overpassJSON.elements[i]; 1847 switch (p.type) { 1848 case 'node': 1849 p.coordinates = [p.lon, p.lat]; 1850 p.geometry = {type: 'Point', coordinates: p.coordinates}; 1851 nodes[p.id] = p; 1852 break; 1853 case 'way': 1854 p.coordinates = p.nodes.map(function (id) { 1855 return nodes[id].coordinates; 1856 }); 1857 p.geometry = {type: 'LineString', coordinates: p.coordinates}; 1858 ways[p.id] = p; 1859 break; 1860 case 'relation': 1861 rels.push(p); 1862 break; 1863 } 1864 } 1865 //console.log("nodes count:" + Object.keys(nodes).length + "; ways count:" + Object.keys(ways).length + "; rel count: " + rels.length); 1866 1867 // handle relations last 1868 for (var i = 0; i < rels.length; i++) { 1869 var p = rels[i]; 1870 p.members.map(function (mem) { 1871 if (mem.type == 'node') { 1872 1873 if(!nodes[mem.ref]) 1874 console.log("mem.type=node missing: " + mem.ref); 1875 1876 mem.obj = nodes[mem.ref]; 1877 } else if (mem.type == 'way') { 1878 1879 if(!ways[mem.ref]) 1880 console.log("mem.type=way missing: " + mem.ref); //FIXME this seems to come from overpass query not returning childs of rels... change query! 1881 1882 mem.obj = ways[mem.ref]; 1883 } else 1884 console.log("mem.type=" + mem.type);// FIXME handle rels of rels 1885 }); 1886 // p has type=relaton, id, tags={k:v}, members=[{role, obj}] 1887 var retval = relationFunction(p); 1888 if (retval) { 1889 if(window.filters) 1890 retval.filtered = ! getFilterStatusOnPoi(retval); 1891 new_markers.push(retval); 1892 } 1893 } 1894 1895 var number = new_markers.length; 1896 if(number) { 1897 markers.RegisterMarkers(new_markers); 1898 markers.ProcessView(); 1899 if(window.createSideBar) { 1900 var json_date = new Date(overpassJSON.osm3s.timestamp_osm_base); 1901 $('#trel').css("display", "block");
1902 $('#trel').html(json_date.toLocaleString()); 1903 updateElementCount(); 1904 updatePOIlist(); 1905 if(window.filters) 1906 updateFilterCount(); // TODO it is relatively inefficient to run check all filters every time a single entry is changed - later only the filters affected on change should be counted 1907 } 1908 new_markers = []; 1909 } 1910 1911 changeLoadingIndicator("loading_relation", -1); 1912 if(! open_popup_on_load.already_shown && open_popup_on_load.type == "relation") { 1913 open_popup_on_load.already_shown = true; 1914 setTimeout(function () { 1915 MytogglePopup(open_popup_on_load.type, open_popup_on_load.id); 1916 },200 ); 1917 } 1918 console.log("handleRelations (pid " + pid + ") done, " + number + " added."); 1919 } 1920 1921 var query = overpass_query; 1922 1923 var node_query = overpass_query_nodes; 1924 var way_query = overpass_query_ways; 1925 var rel_query = overpass_query_rels; 1926 var op_bounds = bounds.toOverpassBBoxString(); 1927 1928 var allUrl = query.replace(/BBOX/g, op_bounds); 1929 1930 var node_url = node_query.replace(/BBOX/g, op_bounds); 1931 var way_url = way_query.replace(/BBOX/g, op_bounds); 1932 var rel_url = rel_query.replace(/BBOX/g, op_bounds); 1933 1934 var bounds_rounded = { // the 'bounds' is the only way where we can identify to which pid a returned overpassJSON belongs 1935 minlat : L.Util.formatNum(bounds._southWest.lat,4), 1936 minlon : L.Util.formatNum(bounds._southWest.lng,4), 1937 maxlat : L.Util.formatNum(bounds._northEast.lat,4), 1938 maxlon : L.Util.formatNum(bounds._northEast.lng,4) 1939 } 1940 1941 changeLoadingIndicator("loading_node", +1); 1942 var this_pid = pids.node.counter++; 1943 pids.node.active[this_pid] = { state : "running", bounds : bounds_rounded } ; 1944 console.log("loadPOI: before JSON call pid node"+this_pid+": " + node_url); 1945 $.getJSON(node_url, handleNodes); 1946 setTimeout(function () { 1947 timeOutOverpassCall("node", this_pid); 1948 },1000*overpass_config.timeout); 1949 1950 changeLoadingIndicator("loading_way", +1); 1951 this_pid = pids.way.counter++; 1952 pids.way.active[this_pid] = { state : "running", bounds : bounds_rounded } ; 1953 console.log("loadPOI: before JSON call pid way"+this_pid+": " + way_url); 1954 $.getJSON(way_url, handleWays); 1955 setTimeout(function () { 1956 timeOutOverpassCall("way", this_pid); 1957 },1000*overpass_config.timeout); 1958 1959 changeLoadingIndicator("loading_relation", +1); 1960 this_pid = pids.relation.counter++; 1961 pids.relation.active[this_pid] = { state : "running", bounds : bounds_rounded } ; 1962 console.log("loadPOI: before JSON call pid rel"+this_pid+": " + rel_url); 1963 $.getJSON(rel_url, handleRelations); 1964 setTimeout(function () { 1965 timeOutOverpassCall("relation", this_pid); 1966 },1000*overpass_config.timeout); 1967} 1968 1969function timeOutOverpassCall(osm_type,pid) { 1970 if (pids[osm_type].active[pid] && pids[osm_type].active[pid].state == "running") { 1971 changeLoadingIndicator("loading_" + osm_type, -1); 1972 pids[osm_type].active[pid].state = "timeouted"; 1973 console.log("timeOutOverpassCall: pid " + osm_type + pid + " timeouted after " + overpass_config.timeout + " seconds."); 1974 } 1975} 1976 1977function updateLinks() { 1978 var centre = map.getCenter(); 1979 var query = encodeURIComponent(overpass_ql_text); 1980 turbolink = "<a href=\'http://overpass-turbo.eu/?Q=" 1981 + query.replace(/BBOX/g, map.getBounds().toOverpassBBoxString()) 1982 + '&R&C=' + centre.lat + ';' + centre.lng + ';' + map.getZoom() 1983 + '\' title="Export OSM data with Overpass Turbo">Export data <img src="'+assethost+'assets/turbo.png" height=12px style="margin-bottom:-2px"/></a>'; 1984 1985 if(window.updateMapSwitcherLinks) 1986 updateMapSwitcherLinks(); 1987} 1988 1989 1990/* taken from https://github.com/ardhi/Leaflet.MousePosition 1991Licence: MIT, see file MIT-LICENCE-Leaflet.MousePosition.txt */ 1992 1993 1994L.Control.MousePosition = L.Control.extend({ 1995 options: { 1996 position: 'bottomright', 1997 separator: ' : ', 1998 emptyString: 'Unavailable', 1999 lngFirst: false, 2000 numDigits: 5, 2001 lngFormatter: undefined, 2002 latFormatter: undefined, 2003 prefix: "" 2004 }, 2005 2006 onAdd: function (map) { 2007 this._container = L.DomUtil.create('div', 'leaflet-control-mouseposition'); 2008 L.DomEvent.disableClickPropagation(this._container); 2009 map.on('mousemove', this._onMouseMove, this); 2010 updateLinks(); 2011 this._container.innerHTML= ' | ' + turbolink; 2012 return this._container; 2013 }, 2014 2015 onRemove: function (map) { 2016 map.off('mousemove', this._onMouseMove) 2017 }, 2018 2019 _onMouseMove: function (e) { 2020 var lng = this.options.lngFormatter ? this.options.lngFormatter(e.latlng.lng) : L.Util.formatNum
2020(e.latlng.lng, this.options.numDigits); 2021 var lat = this.options.latFormatter ? this.options.latFormatter(e.latlng.lat) : L.Util.formatNum(e.latlng.lat, this.options.numDigits); 2022 var lng_length = lng.toString().split(".")[1].length; // it MAY be if you're on exactly one integer coordinate to throw an error, but I don't care 2023 var lat_length = lat.toString().split(".")[1].length; 2024 for(var i = 0; i < this.options.numDigits - lng_length; i++) { 2025 lng += "0"; 2026 } 2027 for(var i = 0; i < this.options.numDigits - lat_length; i++) { 2028 lat += "0"; 2029 } 2030 2031 var value = this.options.lngFirst ? lng + this.options.separator + lat : lat + this.options.separator + lng; 2032 var prefixAndValue = this.options.prefix + ' ' + value; 2033 this._container.innerHTML = prefixAndValue + ' | ' + turbolink; 2034 } 2035 2036}); 2037 2038L.Map.mergeOptions({ 2039 positionControl: false 2040}); 2041 2042L.Map.addInitHook(function () { 2043 if (this.options.positionControl) { 2044 this.positionControl = new L.Control.MousePosition(); 2045 this.addControl(this.positionControl); 2046 } 2047}); 2048 2049L.control.mousePosition = function (options) { 2050 return new L.Control.MousePosition(options); 2051}; 2052 2053var pois_lz; 2054if (window.url_pois_lz) { //TODO: must be called after map pois_lz set ... but how to have it in global namespace? 2055 var http_request_lz = new XMLHttpRequest(); 2056 http_request_lz.open("GET", url_pois_lz, true); 2057 http_request_lz.onreadystatechange = function () { 2058 var done = 4, ok = 200; 2059 if (http_request_lz.readyState === done && http_request_lz.status === ok) { 2060 pois_lz = JSON.parse(http_request_lz.responseText); 2061 loadPoi(); 2062 } 2063 }; 2064 http_request_lz.send(null); 2065 console.log("XMLHttpRequest for pois_lz sent"); 2066} else { 2067 console.log("XMLHttpRequest for pois_lz NOT sent, no url"); 2068} 2069 2070var wikipedia_images = {}; 2071 2072/** 2073 * jQuery.browser.mobile (http://detectmobilebrowser.com/) 2074 * 2075 * jQuery.browser.mobile will be true if the browser is a mobile device 2076 * 2077 **/ 2078(function(a){(jQuery.browser=jQuery.browser||{}).mobile=/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))})(navigator.userAgent||navigator.vendor||window.opera); 2079 2080window.onload = function () { 2081 var text = 'Warning: You seem to use Internet Explorer, which is known to be buggy. This site may not work as expected. We recommend a standards-compl
2081iant free web-browser like <a href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a> or <a href="http://chromium.woolyss.com/">Chromium</a>.', 2082 h; 2083 if(navigator.userAgent.toLowerCase().indexOf('msie') > -1) { 2084 var h = document.createElement("h1"); 2085 h.setAttribute('style', 'text-align:center;color:red;background:white;position:absolute;top:5px;left:55px;right:55px;z-index:15000;padding:5px;margin:0;'); 2086 } else if (navigator.userAgent.toLowerCase().indexOf('trident') > -1) { 2087 var h = document.createElement("h3"); 2088 h.setAttribute('style', 'text-align:center;color:red;position:absolute;top:5px;left:55px;right:55px;z-index:15000;padding:5px;margin:0;background-color:rgba(255,255,255,0.7);'); 2089 } 2090 else return; 2091 h.innerHTML = text; 2092 2093 var map = document.getElementById('map'); 2094 map.appendChild(h); 2095 map.setAttribute( 'class', map.getAttribute('class') + ' ie'); 2096} 2097
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.