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