1/* 2 * Copyright (c) 2008-2022 Mark C. Prins <mprins@users.sf.net> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 18/** 19 * Test for css support in the browser by sniffing for a css class we added 20 * using javascript added by the action plugin; this is an edge case because 21 * browsers that support javascript generally support css as well. 22 * 23 * @returns {Boolean} true when the browser supports css (and implicitly 24 * javascript) 25 */ 26function olTestCSSsupport() { 27 return (jQuery('.olCSSsupported').length > 0); 28} 29 30/** 31 * Creates a DocumentFragment to insert into the dom. 32 * 33 * @param mapid 34 * id for the map div 35 * @param width 36 * width for the map div 37 * @param height 38 * height for the map div 39 * @returns a {DocumentFragment} element that can be injected into the dom 40 */ 41function olCreateMaptag(mapid, width, height) { 42 const // fragment 43 frag = document.createDocumentFragment(), 44 // temp node 45 temp = document.createElement('div'); 46 temp.innerHTML = '<div id="' + mapid + '-olContainer" class="olContainer olWebOnly">' 47 // map 48 + '<div id="' + mapid + '" tabindex="0" style="width:' + width + ';height:' + height + ';" class="olMap"></div>' 49 + '</div>'; 50 while (temp.firstChild) { 51 frag.appendChild(temp.firstChild); 52 } 53 return frag; 54} 55 56/** 57 * Create the map based on the params given. 58 * 59 * @param mapOpts {Object} 60 * mapOpts MapOptions hash {id:'olmap', width:500px, height:500px, 61 * lat:6710200, lon:506500, zoom:13, controls:1, 62 * baselyr:'', kmlfile:'', gpxfile:'', geojsonfile, 63 * summary:''} 64 * @param poi {Array} 65 * OLmapPOI array with POI's [ {lat:6710300,lon:506000,txt:'instap 66 * punt',angle:180,opacity:.9,img:'', rowId:n},... ]); 67 * 68 * @return {ol.Map} the created map 69 */ 70function createMap(mapOpts, poi) { 71 72 // const mapOpts = olMapData[0].mapOpts; 73 // const poi = olMapData[0].poi; 74 75 if (!olEnable) { 76 return null; 77 } 78 if (!olTestCSSsupport()) { 79 olEnable = false; 80 return null; 81 } 82 83 // find map element location 84 const cleartag = document.getElementById(mapOpts.id + '-clearer'); 85 if (cleartag === null) { 86 return null; 87 } 88 // create map element and add to document 89 const fragment = olCreateMaptag(mapOpts.id, mapOpts.width, mapOpts.height); 90 cleartag.parentNode.insertBefore(fragment, cleartag); 91 92 /** dynamic map extent. */ 93 let extent = ol.extent.createEmpty(); 94 let overlayGroup = new ol.layer.Group({title: 'Overlays', fold: 'open', layers: []}); 95 const baseLyrGroup = new ol.layer.Group({'title': 'Base maps', layers: []}); 96 97 const map = new ol.Map({ 98 target: document.getElementById(mapOpts.id), 99 layers: [baseLyrGroup, overlayGroup], 100 view: new ol.View({ 101 center: ol.proj.transform([mapOpts.lon, mapOpts.lat], 'EPSG:4326', 'EPSG:3857'), 102 zoom: mapOpts.zoom, 103 projection: 'EPSG:3857' 104 }), 105 controls: [ 106 new ol.control.Attribution({ 107 collapsible: true, 108 collapsed: true 109 }) 110 ] 111 }); 112 113 if (osmEnable) { 114 baseLyrGroup.getLayers().push( 115 new ol.layer.Tile({ 116 visible: true, 117 title: 'OSM', 118 type: 'base', 119 source: new ol.source.OSM() 120 })); 121 122 baseLyrGroup.getLayers().push( 123 new ol.layer.Tile({ 124 visible: mapOpts.baselyr === "opentopomap", 125 title: 'opentopomap', 126 type: 'base', 127 source: new ol.source.OSM({ 128 url: 'https://{a-c}.tile.opentopomap.org/{z}/{x}/{y}.png', 129 attributions: 'Data ©ODbL <a href="https://openstreetmap.org/copyright" target="_blank">OpenStreetMap</a>, ' 130 + '<a href="http://viewfinderpanoramas.org" target="_blank">SRTM</a>, ' 131 + 'style ©<a href="https://opentopomap.org/" target="_blank">OpenTopoMap</a>' 132 + '(<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)' 133 }) 134 })); 135 136 baseLyrGroup.getLayers().push( 137 new ol.layer.Tile({ 138 visible: mapOpts.baselyr === "cycle map", 139 title: 'cycle map', 140 type: 'base', 141 source: new ol.source.OSM({ 142 url: 'https://{a-c}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png?apikey=' + tfApiKey, 143 attributions: 'Data ©ODbL <a href="https://openstreetmap.org/copyright" target="_blank">OpenStreetMap</a>, ' 144 + 'Tiles ©<a href="https://www.thunderforest.com/" target="_blank">Thunderforest</a>' 145 + '<img src="https://www.thunderforest.com/favicon.ico" alt="Thunderforest logo"/>' 146 }) 147 })); 148 149 baseLyrGroup.getLayers().push( 150 new ol.layer.Tile({ 151 visible: mapOpts.baselyr === "transport", 152 title: 'transport', 153 type: 'base', 154 source: new ol.source.OSM({ 155 url: 'https://{a-c}.tile.thunderforest.com/transport/{z}/{x}/{y}.png?apikey=' + tfApiKey, 156 attributions: 'Data ©ODbL <a href="https://openstreetmap.org/copyright" target="_blank">OpenStreetMap</a>, ' 157 + 'Tiles ©<a href="https://www.thunderforest.com/" target="_blank">Thunderforest</a>' 158 + '<img src="https://www.thunderforest.com/favicon.ico" alt="Thunderforest logo"/>' 159 }) 160 })); 161 162 baseLyrGroup.getLayers().push( 163 new ol.layer.Tile({ 164 visible: mapOpts.baselyr === "landscape", 165 title: 'landscape', 166 type: 'base', 167 source: new ol.source.OSM({ 168 url: 'https://{a-c}.tile.thunderforest.com/landscape/{z}/{x}/{y}.png?apikey=' + tfApiKey, 169 attributions: 'Data ©ODbL <a href="https://openstreetmap.org/copyright" target="_blank">OpenStreetMap</a>, ' 170 + 'Tiles ©<a href="https://www.thunderforest.com/" target="_blank">Thunderforest</a>' 171 + '<img src="https://www.thunderforest.com/favicon.ico" alt="Thunderforest logo"/>' 172 }) 173 })); 174 175 baseLyrGroup.getLayers().push( 176 new ol.layer.Tile({ 177 visible: mapOpts.baselyr === "outdoors", 178 title: 'outdoors', 179 type: 'base', 180 source: new ol.source.OSM({ 181 url: 'https://{a-c}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey=' + tfApiKey, 182 attributions: 'Data ©ODbL <a href="https://openstreetmap.org/copyright" target="_blank">OpenStreetMap</a>, ' 183 + 'Tiles ©<a href="https://www.thunderforest.com/" target="_blank">Thunderforest</a>' 184 + '<img src="https://www.thunderforest.com/favicon.ico" alt="Thunderforest logo"/>' 185 }) 186 })); 187 } 188 189 if (bEnable && bApiKey !== '') { 190 baseLyrGroup.getLayers().push( 191 new ol.layer.Tile({ 192 visible: mapOpts.baselyr === "bing road", 193 title: 'bing road', 194 type: 'base', 195 source: new ol.source.BingMaps({ 196 key: bApiKey, 197 imagerySet: 'Road' 198 }) 199 })); 200 201 baseLyrGroup.getLayers().push( 202 new ol.layer.Tile({ 203 visible: mapOpts.baselyr === "bing sat", 204 title: 'bing sat', 205 type: 'base', 206 source: new ol.source.BingMaps({ 207 key: bApiKey, 208 imagerySet: 'Aerial' 209 }) 210 })); 211 212 baseLyrGroup.getLayers().push( 213 new ol.layer.Tile({ 214 visible: mapOpts.baselyr === "bing hybrid", 215 title: 'bing hybrid', 216 type: 'base', 217 source: new ol.source.BingMaps({ 218 key: bApiKey, 219 imagerySet: 'AerialWithLabels' 220 }) 221 })); 222 } 223 224 if (stamenEnable) { 225 baseLyrGroup.getLayers().push( 226 new ol.layer.Tile({ 227 visible: mapOpts.baselyr === "toner", 228 type: 'base', 229 title: 'toner', 230 source: new ol.source.Stamen({layer: 'toner'}) 231 }) 232 ); 233 234 baseLyrGroup.getLayers().push( 235 new ol.layer.Tile({ 236 visible: mapOpts.baselyr === "terrain", 237 type: 'base', 238 title: 'terrain', 239 source: new ol.source.Stamen({layer: 'terrain'}) 240 }) 241 ); 242 } 243 244 extent = ol.extent.extend(extent, map.getView().calculateExtent()); 245 246 const iconScale = window.devicePixelRatio ?? 1.0; 247 const vectorSource = new ol.source.Vector(); 248 poi.forEach((p) => { 249 const f = new ol.Feature({ 250 geometry: new ol.geom.Point(ol.proj.fromLonLat([p.lon, p.lat])), 251 description: p.txt, 252 img: p.img, 253 rowId: p.rowId, 254 lat: p.lat, 255 lon: p.lon, 256 angle: p.angle, 257 opacity: p.opacity, 258 alt: p.img.substring(0, p.img.lastIndexOf(".")) 259 }); 260 f.setId(p.rowId); 261 vectorSource.addFeature(f); 262 }); 263 264 const vectorLayer = new ol.layer.Vector({ 265 title: 'POI', 266 visible: true, 267 source: vectorSource, 268 style(feature, resolution) { 269 const img = feature.get('img'); 270 const opacity = feature.get('opacity'); 271 const angle = feature.get('angle'); 272 const text = feature.get('rowId'); 273 274 return new ol.style.Style({ 275 image: new ol.style.Icon({ 276 src: `${DOKU_BASE}lib/plugins/openlayersmap/icons/${img}`, 277 crossOrigin: '', 278 opacity: opacity, 279 scale: iconScale, 280 rotation: angle * Math.PI / 180, 281 // width/height were added in OpenLayers 7.2.2 282 // see https://github.com/openlayers/openlayers/pull/14364 283 }), 284 text: new ol.style.Text({ 285 text: `${text}`, 286 textAlign: 'center', 287 textBaseline: 'middle', 288 offsetX: (8 + 4 + 2) * iconScale, 289 offsetY: -8 * iconScale, 290 scale: iconScale, 291 fill: new ol.style.Fill({color: 'rgb(0,0,0)'}), 292 font: 'bold 16px monospace', 293 stroke: new ol.style.Stroke({color: 'rgba(255,255,255,.4)', width: 5}), 294 }) 295 }); 296 } 297 }); 298 overlayGroup.getLayers().push(vectorLayer); 299 if (mapOpts.autozoom) { 300 extent = ol.extent.extend(extent, vectorSource.getExtent()); 301 map.getView().fit(extent); 302 } 303 304 if (mapOpts.controls === 1) { 305 map.addControl(new ol.control.Zoom()); 306 map.addControl(new ol.control.ScaleLine({bar: true, text: true})); 307 map.addControl(new ol.control.MousePosition({ 308 coordinateFormat: ol.coordinate.createStringXY(4), projection: 'EPSG:4326', 309 })); 310 map.addControl(new ol.control.FullScreen({ 311 label: '✈' 312 })); 313 map.addControl(new ol.control.OverviewMap({ 314 label: '+', 315 layers: [new ol.layer.Tile({ 316 source: new ol.source.OSM() 317 })] 318 })); 319 map.addControl(new ol.control.LayerSwitcher({ 320 activationMode: 'click', 321 label: '\u2630', 322 collapseLabel: '\u00BB', 323 })); 324 } 325 326 if (mapOpts.kmlfile.length > 0) { 327 try { 328 const kmlSource = new ol.source.Vector({ 329 url: DOKU_BASE + "lib/exe/fetch.php?media=" + mapOpts.kmlfile, 330 format: new ol.format.KML(), 331 }); 332 overlayGroup.getLayers().push(new ol.layer.Vector({title: 'KML file', visible: true, source: kmlSource})); 333 334 if (mapOpts.autozoom) { 335 kmlSource.once('change', function () { 336 extent = ol.extent.extend(extent, kmlSource.getExtent()); 337 map.getView().fit(extent); 338 }); 339 } 340 } catch (e) { 341 console.error(e); 342 } 343 } 344 345 if (mapOpts.geojsonfile.length > 0) { 346 try { 347 // these are the same colour as in StaticMap#drawJSON() 348 const geoJsonStyle = { 349 'Point': new ol.style.Style({ 350 image: new ol.style.Circle({ 351 fill: new ol.style.Fill({ 352 color: 'rgba(255,0,255,0.4)', 353 }), 354 radius: 5, 355 stroke: new ol.style.Stroke({ 356 color: 'rgba(255,0,255,0.9)', 357 width: 1, 358 }), 359 }), 360 }), 361 'LineString': new ol.style.Style({ 362 stroke: new ol.style.Stroke({ 363 color: 'rgba(255,0,255,0.9)', 364 width: 3, 365 }), 366 }), 367 'MultiLineString': new ol.style.Style({ 368 stroke: new ol.style.Stroke({ 369 color: 'rgba(255,0,255,0.9)', 370 width: 3, 371 }), 372 }), 373 'Polygon': new ol.style.Style({ 374 stroke: new ol.style.Stroke({ 375 color: 'rgba(255,0,255,0.9)', 376 width: 3, 377 }), 378 fill: new ol.style.Fill({ 379 color: 'rgba(255,0,255,0.4)', 380 }), 381 }), 382 'MultiPolygon': new ol.style.Style({ 383 stroke: new ol.style.Stroke({ 384 color: 'rgba(255,0,255,0.9)', 385 width: 3, 386 }), 387 fill: new ol.style.Fill({ 388 color: 'rgba(255,0,255,0.4)', 389 }), 390 }), 391 }; 392 const geoJsonSource = new ol.source.Vector({ 393 url: DOKU_BASE + "lib/exe/fetch.php?media=" + mapOpts.geojsonfile, 394 format: new ol.format.GeoJSON(), 395 }); 396 overlayGroup.getLayers().push(new ol.layer.Vector({ 397 title: 'GeoJSON file', visible: true, source: geoJsonSource, 398 style: function (feature) { 399 return geoJsonStyle[feature.getGeometry().getType()]; 400 }, 401 })); 402 403 if (mapOpts.autozoom) { 404 geoJsonSource.once('change', function () { 405 extent = ol.extent.extend(extent, geoJsonSource.getExtent()); 406 map.getView().fit(extent); 407 }); 408 } 409 } catch (e) { 410 console.error(e); 411 } 412 } 413 414 if (mapOpts.gpxfile.length > 0) { 415 try { 416 // these are the same colour as in StaticMap#drawGPX() 417 const gpxJsonStyle = { 418 'Point': new ol.style.Style({ 419 image: new ol.style.Circle({ 420 fill: new ol.style.Fill({ 421 color: 'rgba(0,0,255,0.4)', 422 }), 423 radius: 5, 424 stroke: new ol.style.Stroke({ 425 color: 'rgba(0,0,255,0.9)', 426 width: 1, 427 }), 428 }), 429 }), 430 'LineString': new ol.style.Style({ 431 stroke: new ol.style.Stroke({ 432 color: 'rgba(0,0,255,0.9)', 433 width: 3, 434 }), 435 }), 436 'MultiLineString': new ol.style.Style({ 437 stroke: new ol.style.Stroke({ 438 color: 'rgba(0,0,255,0.9)', 439 width: 3, 440 }), 441 }), 442 }; 443 const gpxSource = new ol.source.Vector({ 444 url: DOKU_BASE + "lib/exe/fetch.php?media=" + mapOpts.gpxfile, 445 format: new ol.format.GPX(), 446 }); 447 overlayGroup.getLayers().push(new ol.layer.Vector({ 448 title: 'GPS track', visible: true, source: gpxSource, 449 style: function (feature) { 450 return gpxJsonStyle[feature.getGeometry().getType()]; 451 }, 452 })); 453 454 if (mapOpts.autozoom) { 455 gpxSource.once('change', function () { 456 extent = ol.extent.extend(extent, gpxSource.getExtent()); 457 map.getView().fit(extent); 458 }); 459 } 460 } catch (e) { 461 console.error(e); 462 } 463 } 464 465 const container = document.getElementById('popup'); 466 const content = document.getElementById('popup-content'); 467 const closer = document.getElementById('popup-closer'); 468 469 const overlay = new ol.Overlay({ 470 element: container, 471 positioning: 'center-center', 472 stopEvent: true, 473 autoPan: { 474 animation: { 475 duration: 250, 476 } 477 }, 478 }); 479 map.addOverlay(overlay); 480 481 /** 482 * Add a click handler to hide the popup. 483 * @return {boolean} Don't follow the href. 484 */ 485 closer.onclick = function () { 486 overlay.setPosition(undefined); 487 closer.blur(); 488 return false; 489 }; 490 491 // display popup on click 492 map.on('singleclick', function (evt) { 493 const selFeature = map.forEachFeatureAtPixel(evt.pixel, function (feature) { 494 return feature; 495 }); 496 if (selFeature) { 497 overlay.setPosition(evt.coordinate); 498 499 let pContent = '<div class="spacer"> </div>'; 500 // let locDesc = ''; 501 502 if (selFeature.get('rowId') !== undefined) { 503 pContent += '<span class="rowId">' + selFeature.get('rowId') + ': </span>'; 504 } 505 if (selFeature.get('name') !== undefined) { 506 pContent += '<span class="txt">' + selFeature.get('name') + '</span>'; 507 // locDesc = selFeature.get('name'); 508 // TODO strip <p> tag from locDesc 509 // locDesc = selFeature.get('name').split(/\s+/).slice(0,2).join('+'); 510 } 511 if (selFeature.get('ele') !== undefined) { 512 pContent += '<div class="ele">elevation: ' + selFeature.get('ele') + '</div>'; 513 } 514 if (selFeature.get('type') !== undefined) { 515 pContent += '<div>' + selFeature.get('type') + '</div>'; 516 } 517 if (selFeature.get('time') !== undefined) { 518 pContent += '<div class="time">time: ' + selFeature.get('time') + '</div>'; 519 } 520 if (selFeature.get('description') !== undefined) { 521 pContent += '<div class="desc">' + selFeature.get('description') + '</div>'; 522 } 523 if (selFeature.get('img') !== undefined) { 524 const _alt = selFeature.get('alt'); 525 pContent += '<div class="coord" title="lat;lon">' + 526 '<img alt="' + _alt + '" src="' + DOKU_BASE + 'lib/plugins/openlayersmap/icons/' + selFeature.get('img') + 527 '" width="16" height="16" ' + 'style="transform:rotate(' + selFeature.get('angle') + 'deg)" /> ' + 528 '<a href="geo:' + selFeature.get('lat') + ',' + selFeature.get('lon') + '?q=' + selFeature.get('lat') + 529 ',' + selFeature.get('lon') + '(' + selFeature.get('alt') + ')" title="Open in navigation app">' + 530 ol.coordinate.format([selFeature.get('lon'), selFeature.get('lat')], '{x}º; {y}º', 4) + '</a></div>'; 531 } 532 content.innerHTML = pContent; 533 } else { 534 // do nothing... 535 } 536 }); 537 538 // change mouse cursor when over marker 539 map.on('pointermove', function (e) { 540 const pixel = map.getEventPixel(e.originalEvent); 541 const hit = map.hasFeatureAtPixel(pixel); 542 map.getTarget().style.cursor = hit ? 'pointer' : ''; 543 }); 544 545 return map; 546} 547 548/** 549 * add layers to the map based on the olMapOverlays object. 550 */ 551function olovAddToMap() { 552 for (const key in olMapOverlays) { 553 const overlay = olMapOverlays[key]; 554 const m = olMaps[overlay.id]; 555 556 switch (overlay.type) { 557 case 'osm': 558 m.addLayer(new ol.layer.Tile({ 559 title: overlay.name, 560 visible: (overlay.visible).toLowerCase() === 'true', 561 opacity: parseFloat(overlay.opacity), 562 source: new ol.source.OSM({ 563 url: overlay.url, 564 crossOrigin: 'Anonymous', 565 attributions: overlay.attribution 566 }) 567 })); 568 break; 569 case 'wms': 570 m.addLayer(new ol.layer.Image({ 571 title: overlay.name, 572 opacity: parseFloat(overlay.opacity), 573 visible: (overlay.visible).toLowerCase() === 'true', 574 source: new ol.source.ImageWMS({ 575 url: overlay.url, 576 params: { 577 'LAYERS': overlay.layers, 578 'VERSION': overlay.version, 579 'TRANSPARENT': overlay.transparent, 580 'FORMAT': overlay.format 581 }, 582 ratio: 1, 583 crossOrigin: 'Anonymous', 584 attributions: overlay.attribution 585 }) 586 })); 587 break; 588 case 'ags': 589 m.addLayer(new ol.layer.Image({ 590 title: overlay.name, 591 opacity: parseFloat(overlay.opacity), 592 visible: (overlay.visible).toLowerCase() === 'true', 593 source: new ol.source.ImageArcGISRest({ 594 url: overlay.url, 595 params: { 596 'LAYERS': overlay.layers, 597 'TRANSPARENT': overlay.transparent, 598 'FORMAT': overlay.format 599 }, 600 ratio: 1, 601 crossOrigin: 'Anonymous', 602 attributions: overlay.attribution 603 }) 604 })); 605 break; 606 // case 'mapillary': 607 // var mUrl = 'http://api.mapillary.com/v1/im/search?'; 608 // if (overlay.skey !== '') { 609 // mUrl = 'http://api.mapillary.com/v1/im/sequence?'; 610 // } 611 // var mLyr = new OpenLayers.Layer.Vector( 612 // "Mapillary", { 613 // projection: new OpenLayers.Projection("EPSG:4326"), 614 // strategies: [new OpenLayers.Strategy.BBOX({ 615 // ratio: 1.1, 616 // resFactor: 1.5 617 // }) /* ,new OpenLayers.Strategy.Cluster({}) */], 618 // protocol: new OpenLayers.Protocol.HTTP({ 619 // url: mUrl, 620 // format: new OpenLayers.Format.GeoJSON(), 621 // params: { 622 // // default to max. 250 locations 623 // 'max-results': 250, 624 // 'geojson': true, 625 // 'skey': overlay.skey 626 // }, 627 // filterToParams: function (filter, params) { 628 // if (filter.type === OpenLayers.Filter.Spatial.BBOX) { 629 // // override the bbox serialization of 630 // // the filter to give the Mapillary 631 // // specific bounds 632 // params['min-lat'] = filter.value.bottom; 633 // params['max-lat'] = filter.value.top; 634 // params['min-lon'] = filter.value.left; 635 // params['max-lon'] = filter.value.right; 636 // // if the width of our bbox width is 637 // // less than 0.15 degrees drop the max 638 // // results 639 // if (filter.value.top - filter.value.bottom < .15) { 640 // OpenLayers.Console.debug('dropping max-results parameter, width is: ', 641 // filter.value.top - filter.value.bottom); 642 // params['max-results'] = null; 643 // } 644 // } 645 // return params; 646 // } 647 // }), 648 // styleMap: new OpenLayers.StyleMap({ 649 // 'default': { 650 // cursor: 'help', 651 // rotation: '${ca}', 652 // externalGraphic: DOKU_BASE + 'lib/plugins/openlayersmapoverlays/icons/arrow-up-20.png', 653 // graphicHeight: 20, 654 // graphicWidth: 20, 655 // }, 656 // 'select': { 657 // externalGraphic: DOKU_BASE + 'lib/plugins/openlayersmapoverlays/icons/arrow-up-20-select.png', 658 // label: '${location}', 659 // fontSize: '1em', 660 // fontFamily: 'monospace', 661 // labelXOffset: '0.5', 662 // labelYOffset: '0.5', 663 // labelAlign: 'lb', 664 // } 665 // }), 666 // attribution: '<a href="http://www.mapillary.com/legal.html">' + 667 // '<img src="http://mapillary.com/favicon.ico" ' + 668 // 'alt="Mapillary" height="16" width="16" />Mapillary (CC-BY-SA)', 669 // visibility: (overlay.visible).toLowerCase() == 'true', 670 // }); 671 // m.addLayer(mLyr); 672 // selectControl.addLayer(mLyr); 673 // break; 674 // case 'search': 675 // m.addLayer(new OpenLayers.Layer.Vector( 676 // overlay.name, 677 // overlay.url, 678 // { 679 // layers: overlay.layers, 680 // version: overlay.version, 681 // transparent: overlay.transparent, 682 // format: overlay.format 683 // }, { 684 // opacity: parseFloat(overlay.opacity), 685 // visibility: (overlay.visible).toLowerCase() == 'true', 686 // isBaseLayer: !1, 687 // attribution: overlay.attribution 688 // } 689 // )); 690 // break; 691 } 692 } 693} 694 695/** init. */ 696function olInit() { 697 if (olEnable) { 698 // add info window to DOM 699 const frag = document.createDocumentFragment(), 700 temp = document.createElement('div'); 701 temp.innerHTML = '<div id="popup" class="olPopup"><a href="#" id="popup-closer" class="olPopupCloseBox"></a><div id="popup-content"></div></div>'; 702 while (temp.firstChild) { 703 frag.appendChild(temp.firstChild); 704 } 705 document.body.appendChild(frag); 706 707 let _i = 0; 708 // create the maps in the page 709 for (_i = 0; _i < olMapData.length; _i++) { 710 const _id = olMapData[_i].mapOpts.id; 711 olMaps[_id] = createMap(olMapData[_i].mapOpts, olMapData[_i].poi); 712 713 // set max-width on help pop-over 714 jQuery('#' + _id).parent().parent().find('.olMapHelp').css('max-width', olMapData[_i].mapOpts.width); 715 716 // shrink the map width to fit inside page container 717 const _w = jQuery('#' + _id + '-olContainer').parent().innerWidth(); 718 if (parseInt(olMapData[_i].mapOpts.width) > _w) { 719 jQuery('#' + _id).width(_w); 720 jQuery('#' + _id).parent().parent().find('.olMapHelp').width(_w); 721 olMaps[_id].updateSize(); 722 } 723 } 724 725 // add overlays 726 olovAddToMap(); 727 728 let resizeTimer; 729 jQuery(window).on('resize', function (e) { 730 clearTimeout(resizeTimer); 731 resizeTimer = setTimeout(function () { 732 for (_i = 0; _i < olMapData.length; _i++) { 733 const _id = olMapData[_i].mapOpts.id; 734 const _w = jQuery('#' + _id + '-olContainer').parent().innerWidth(); 735 if (parseInt(olMapData[_i].mapOpts.width) > _w) { 736 jQuery('#' + _id).width(_w); 737 jQuery('#' + _id).parent().parent().find('.olMapHelp').width(_w); 738 olMaps[_id].updateSize(); 739 } 740 } 741 }, 250); 742 }); 743 744 // hide the table(s) with POI by giving it a print-only style 745 jQuery('.olPOItableSpan').addClass('olPrintOnly'); 746 // hide the static map image(s) by giving it a print only style 747 jQuery('.olStaticMap').addClass('olPrintOnly'); 748 // add help button with toggle. 749 jQuery('.olWebOnly > .olMap') 750 .prepend( 751 '<div class="olMapHelpButtonDiv">' 752 + '<button onclick="jQuery(\'.olMapHelp\').toggle(500);" class="olMapHelpButton olHasTooltip"><span>' 753 + 'Show or hide help</span>?</button></div>'); 754 // toggle to switch dynamic vs. static map 755 jQuery('.olMapHelp').before( 756 '<div class="a11y"><button onclick="jQuery(\'.olPrintOnly\').toggle();jQuery(\'.olWebOnly\').toggle();">' 757 + 'Hide or show the dynamic map</button></div>'); 758 } 759} 760 761/** 762 * CSS support flag. 763 * 764 * @type {Boolean} 765 */ 766let olCSSEnable = true; 767 768/* register olInit to run with onload event. */ 769jQuery(olInit); 770