xref: /plugin/openlayersmap/script.js (revision ba56c9628d64cad1e23908648397ba879975ccd1)
1/*
2 * Copyright (c) 2008-2018 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 * @fileoverview Javascript voor OpenLayers plugin.
19 *
20 * @requires {lib/OpenLayers.js} or a full openlayers build
21 * @author Mark C. Prins <mprins@users.sf.net>
22 *
23 */
24
25/**
26 * Openlayers selectcontrol.
27 *
28 * @type {OpenLayers.Control.SelectFeature}
29 * @private
30 */
31var selectControl;
32
33/**
34 * handle feature select event.
35 *
36 * @param {OpenLayers.Feature.Vector}
37 *            selFeature the selected feature
38 */
39function onFeatureSelect(selFeature) {
40    // 'this' is selectFeature control
41    var pPos = selFeature.geometry.getBounds().getCenterLonLat();
42    // != OpenLayers.Geometry.Point
43    if (selFeature.geometry.CLASS_NAME === "OpenLayers.Geometry.LineString") {
44        try {
45            // for lines make the popup show at the cursor position
46            pPos = selFeature.layer.map.getLonLatFromViewPortPx(this.handlers.feature.evt.xy);
47        } catch (anErr) {
48            OpenLayers.Console.warn("unable to get event position; reverting to boundingbox center.");
49            pPos = selFeature.geometry.getBounds().getCenterLonLat();
50        }
51    }
52
53    var pContent = '<div class="spacer">&nbsp;</div>';
54    var locDesc = '';
55    if (selFeature.data.rowId !== undefined) {
56        pContent += '<span class="rowId">' + selFeature.data.rowId + ': </span>';
57    }
58    if (selFeature.data.name !== undefined) {
59        pContent += '<span class="txt">' + selFeature.data.name + '</span>';
60        locDesc = selFeature.data.name;
61        // TODO strip <p> tag from locDesc
62        // locDesc = selFeature.data.name.split(/\s+/).slice(0,2).join('+');
63    }
64    if (selFeature.data.ele !== undefined) {
65        pContent += '<div class="ele">elevation: ' + selFeature.data.ele + '</div>';
66    }
67    if (selFeature.data.type !== undefined) {
68        pContent += '<div>' + selFeature.data.type + '</div>';
69    }
70    if (selFeature.data.time !== undefined) {
71        pContent += '<div class="time">time: ' + selFeature.data.time + '</div>';
72    }
73    if (selFeature.data.description !== undefined) {
74        pContent += '<div class="desc">' + selFeature.data.description + '</div>';
75    }
76    // mapillary layer
77    if (selFeature.attributes.location !== undefined) {
78        pContent += '<div class="desc">' + selFeature.data.location + '</div>';
79    }
80    // mapillary layer
81    if (selFeature.attributes.image !== undefined) {
82        pContent += '<img class="img" src=' + selFeature.data.image + ' width="320" />';
83    }
84    // mapillary layer
85    if (selFeature.attributes.ca !== undefined) {
86        var angle = Math.floor(selFeature.data.ca);
87        pContent += '<div class="coord"><img src="' + DOKU_BASE + 'lib/plugins/openlayersmapoverlays/icons/arrow-up-20.png'
88                + '" width="16" height="16" style="transform:rotate(' + angle + 'deg)" alt="' + angle + 'º"/> '+OpenLayers.i18n("compass") + angle + 'º</div>';
89    }
90
91    if (selFeature.attributes.img !== undefined) {
92        pContent += '<div class="coord" title="lat;lon"><img src="' + selFeature.attributes.img
93                + '" width="16" height="16" style="transform:rotate(' + selFeature.attributes.angle + 'deg)" />&nbsp;'
94                + '<a href="geo:'+ selFeature.data.lat + ',' + selFeature.data.lon
95                + '?q=' + selFeature.data.lat + ',' + selFeature.data.lon + '(' + selFeature.data.alt + ')" title="' + OpenLayers.i18n("navi") + '">'
96                + selFeature.data.latlon + '</a></div>';
97    }
98    if (pContent.length > 0) {
99        // only show when there is something to show...
100        var popup = new OpenLayersMap.Popup.FramedCloud("olPopup", pPos, null, pContent, null, true, function() {
101            selectControl.unselect(selFeature);
102            jQuery('#' + selectControl.layer.map.div.id).focus();
103        });
104        selFeature.popup = popup;
105        selFeature.layer.map.addPopup(popup);
106        jQuery('#olPopup').attr("tabindex", -1).focus();
107    }
108}
109
110/**
111 * handle feature unselect event. remove & destroy the popup.
112 *
113 * @param {OpenLayers.Feature.Vector}
114 *            selFeature the un-selected feature
115 */
116function onFeatureUnselect(selFeature) {
117    if (selFeature.popup !== null) {
118        selFeature.layer.map.removePopup(selFeature.popup);
119        selFeature.popup.destroy();
120        selFeature.popup = null;
121    }
122}
123/**
124 * Test for css support in the browser by sniffing for a css class we added
125 * using javascript added by the action plugin; this is an edge case because
126 * browsers that support javascript generally support css as well.
127 *
128 * @returns {Boolean} true when the browser supports css (and implicitly
129 *          javascript)
130 */
131function olTestCSSsupport() {
132    return (jQuery('.olCSSsupported').length > 0);
133}
134
135/**
136 * Creates a DocumentFragment to insert into the dom.
137 *
138 * @param mapid
139 *            id for the map div
140 * @param width
141 *            width for the map div
142 * @param height
143 *            height for the map div
144 * @returns a {DocumentFragment} element that can be injected into the dom
145 */
146function olCreateMaptag(mapid, width, height) {
147    var mEl = '<div id="' + mapid + '-olContainer" class="olContainer olWebOnly">'
148    // map
149    + '<div id="' + mapid + '" tabindex="0" style="width:' + width + ';height:' + height + ';" class="olMap"></div>'
150    // statusbar
151    + '<div id="' + mapid + '-olStatusBar" style="width:' + width + ';" class="olStatusBarContainer">' + '  <div id="'
152            + mapid + '-statusbar-scale" class="olStatusBar olStatusBarScale">scale</div>' + '  <div id="' + mapid
153            + '-statusbar-mouseposition" class="olStatusBar olStatusBarMouseposition"></div>' + '  <div id="' + mapid
154            + '-statusbar-projection" class="olStatusBar olStatusBarProjection">proj</div>' + '  <div id="' + mapid
155            + '-statusbar-text" class="olStatusBar olStatusBarText">txt</div>' + '</div>'
156            //
157            + '</div>',
158    // fragment
159    frag = document.createDocumentFragment(),
160    // temp node
161    temp = document.createElement('div');
162    temp.innerHTML = mEl;
163    while (temp.firstChild) {
164        frag.appendChild(temp.firstChild);
165    }
166    return frag;
167}
168
169/**
170 * Create the map based on the params given.
171 *
172 * @param {Object}
173 *            mapOpts MapOptions hash {id:'olmap', width:500px, height:500px,
174 *            lat:6710200, lon:506500, zoom:13, statusbar:1, controls:1,
175 *            poihoverstyle:1, baselyr:'', kmlfile:'', gpxfile:'', geojsonfile,
176 *            summary:''}
177 * @param {Array}
178 *            OLmapPOI array with POI's [ {lat:6710300,lon:506000,txt:'instap
179 *            punt',angle:180,opacity:.9,img:'', rowId:n},... ]);
180 *
181 * @return {OpenLayers.Map} the created map
182 */
183function createMap(mapOpts, OLmapPOI) {
184    if (!olEnable) {
185        return;
186    }
187    if (!olTestCSSsupport()) {
188        olEnable = false;
189        return;
190    }
191    OpenLayers.ImgPath = DOKU_BASE + 'lib/plugins/openlayersmap/lib/img/';
192    OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3;
193
194    // find map element location
195    var cleartag = document.getElementById(mapOpts.id + '-clearer');
196    if (cleartag === null) {
197        return;
198    }
199    // create map element and add to document
200    var fragment = olCreateMaptag(mapOpts.id, mapOpts.width, mapOpts.height);
201    cleartag.parentNode.insertBefore(fragment, cleartag);
202
203    /** dynamic map extent. */
204    var extent = new OpenLayers.Bounds(),
205
206    /** map. */
207    m = new OpenLayers.Map({
208        div : mapOpts.id,
209        projection : 'EPSG:3857',
210        displayProjection : new OpenLayers.Projection("EPSG:4326"),
211        numZoomLevels : 22,
212        controls : [],
213        theme : null
214    });
215
216    if (osmEnable) {
217        /* add OSM map layers */
218        m.addLayer(new OpenLayers.Layer.OSM());
219
220        /* open cycle map */
221        m.addLayer(new OpenLayersMap.Layer.OCM("cycle map",[
222                'https://a.tile.thunderforest.com/cycle/${z}/${x}/${y}.png?apikey='+tfApiKey,
223                'https://b.tile.thunderforest.com/cycle/${z}/${x}/${y}.png?apikey='+tfApiKey,
224                'https://c.tile.thunderforest.com/cycle/${z}/${x}/${y}.png?apikey='+tfApiKey ], {
225            visibility : mapOpts.baselyr === "transport",
226            apikey : tfApiKey
227        }));
228        m.addLayer(new OpenLayersMap.Layer.OCM("transport", [
229                "https://a.tile.thunderforest.com/transport/${z}/${x}/${y}.png?apikey="+tfApiKey,
230                "https://b.tile.thunderforest.com/transport/${z}/${x}/${y}.png?apikey="+tfApiKey,
231                "https://c.tile.thunderforest.com/transport/${z}/${x}/${y}.png?apikey="+tfApiKey ], {
232            visibility : mapOpts.baselyr === "transport",
233            apikey : tfApiKey
234        }));
235        m.addLayer(new OpenLayersMap.Layer.OCM("landscape", [
236                "https://a.tile.thunderforest.com/landscape/${z}/${x}/${y}.png?apikey="+tfApiKey,
237                "https://b.tile.thunderforest.com/landscape/${z}/${x}/${y}.png?apikey="+tfApiKey,
238                "https://c.tile.thunderforest.com/landscape/${z}/${x}/${y}.png?apikey="+tfApiKey ], {
239            visibility : mapOpts.baselyr === "landscape",
240            apikey : tfApiKey
241        }));
242        m.addLayer(new OpenLayersMap.Layer.OCM("outdoors", [
243                "https://a.tile.thunderforest.com/outdoors/${z}/${x}/${y}.png?apikey="+tfApiKey,
244                "https://b.tile.thunderforest.com/outdoors/${z}/${x}/${y}.png?apikey="+tfApiKey,
245                "https://c.tile.thunderforest.com/outdoors/${z}/${x}/${y}.png?apikey="+tfApiKey ], {
246            visibility : mapOpts.baselyr === "outdoors",
247            apikey : tfApiKey
248        }));
249        /* hike and bike map seem to be offline
250        m.addLayer(new OpenLayers.Layer.OSM(
251                "hike and bike map", "http://toolserver.org/tiles/hikebike/${z}/${x}/${y}.png", {
252                    visibility : mapOpts.baselyr === "hike and bike map",
253                    tileOptions : {
254                        crossOriginKeyword : null
255                    }
256        }));
257        */
258    }
259    /*
260     * add Stamen map layers, see: http://maps.stamen.com/
261     */
262    if (stamenEnable) {
263        m.addLayer(new OpenLayersMap.Layer.StamenTerrain());
264        m.addLayer(new OpenLayersMap.Layer.StamenToner());
265    }
266
267    if (gEnable) {
268        /* load google maps */
269        try {
270            m.addLayer(new OpenLayers.Layer.Google("google relief", {
271                type : google.maps.MapTypeId.TERRAIN,
272                numZoomLevels : 16,
273                animationEnabled : true,
274                visibility : mapOpts.baselyr === "google relief"
275            }));
276            m.addLayer(new OpenLayers.Layer.Google("google sat", {
277                type : google.maps.MapTypeId.SATELLITE,
278                animationEnabled : true,
279                visibility : mapOpts.baselyr === "google sat"
280            }));
281            m.addLayer(new OpenLayers.Layer.Google("google hybrid", {
282                type : google.maps.MapTypeId.HYBRID,
283                animationEnabled : true,
284                visibility : mapOpts.baselyr === "google hybrid"
285            }));
286            m.addLayer(new OpenLayers.Layer.Google("google road", {
287                animationEnabled : true,
288                visibility : mapOpts.baselyr === "google road"
289            }));
290        } catch (ol_err1) {
291            Openlayers.Console.userError('Error loading Google maps' + ol_err1);
292        }
293    }
294
295    if (bEnable && bApiKey !== '') {
296        try {
297            /* add Bing tiles */
298            m.addLayer(new OpenLayers.Layer.Bing({
299                key : bApiKey,
300                type : "Road",
301                name : "bing road",
302                visibility : mapOpts.baselyr === "bing road",
303                wrapDateLine : true,
304                attributionTemplate : '<a target="_blank" href="http://www.bing.com/maps/">'
305                        + 'Bing™</a><img src="//www.bing.com/favicon.ico" alt="Bing logo"/> ${copyrights}'
306                        + '<a target="_blank" href="http://www.microsoft.com/maps/product/terms.html">Terms of Use</a>'
307            }));
308            m.addLayer(new OpenLayers.Layer.Bing({
309                key : bApiKey,
310                type : "Aerial",
311                name : "bing sat",
312                visibility : mapOpts.baselyr === "bing sat",
313                wrapDateLine : true,
314                attributionTemplate : '<a target="_blank" href="http://www.bing.com/maps/">'
315                        + 'Bing™</a><img src="//www.bing.com/favicon.ico" alt="Bing logo"/> ${copyrights}'
316                        + '<a target="_blank" href="http://www.microsoft.com/maps/product/terms.html">Terms of Use</a>'
317            }));
318            m.addLayer(new OpenLayers.Layer.Bing({
319                key : bApiKey,
320                type : "AerialWithLabels",
321                name : "bing hybrid",
322                visibility : mapOpts.baselyr === "bing hybrid",
323                wrapDateLine : true,
324                attributionTemplate : '<a target="_blank" href="http://www.bing.com/maps/">'
325                        + 'Bing™</a><img src="//www.bing.com/favicon.ico" alt="Bing logo"/> ${copyrights}'
326                        + '<a target="_blank" href="http://www.microsoft.com/maps/product/terms.html">Terms of Use</a>'
327            }));
328        } catch (ol_errBing) {
329            Openlayers.Console.userError('Error loading Bing maps: ' + ol_errBing);
330        }
331    }
332
333    m.setCenter(new OpenLayers.LonLat(mapOpts.lon, mapOpts.lat).transform(m.displayProjection, m.projection),
334            mapOpts.zoom);
335    extent.extend(m.getExtent());
336
337    // change/set alternative baselyr
338    try {
339        m.setBaseLayer(((m.getLayersByName(mapOpts.baselyr))[0]));
340    } catch (ol_err4) {
341        m.setBaseLayer(m.layers[0]);
342    }
343
344    m.addControls([ new OpenLayers.Control.ScaleLine({
345        geodesic : true
346    }), new OpenLayers.Control.KeyboardDefaults({
347        observeElement : mapOpts.id
348    }), new OpenLayers.Control.Navigation() ]);
349
350    if (mapOpts.statusbar === 1) {
351        // statusbar control: mouse pos.
352        m.addControl(new OpenLayers.Control.MousePosition({
353            'div' : OpenLayers.Util.getElement(mapOpts.id + '-statusbar-mouseposition')
354        }));
355        // statusbar control: scale
356        m.addControl(new OpenLayers.Control.Scale(mapOpts.id + '-statusbar-scale'));
357        // statusbar control: attribution
358        m.addControl(new OpenLayers.Control.Attribution({
359            'div' : OpenLayers.Util.getElement(mapOpts.id + '-statusbar-text')
360        }));
361        // statusbar control: projection
362        OpenLayers.Util.getElement(mapOpts.id + '-statusbar-projection').innerHTML = m.displayProjection;
363    } else {
364        OpenLayers.Util.getElement(mapOpts.id + '-olStatusBar').display = 'none';
365    }
366
367    if (OLmapPOI.length > 0) {
368        var markers = new OpenLayers.Layer.Vector("POI", {
369            styleMap : new OpenLayers.StyleMap({
370                "default" : {
371                    cursor : "help",
372                    externalGraphic : "${img}",
373                    graphicHeight : 16,
374                    graphicWidth : 16,
375                    // graphicXOffset : 0,
376                    // graphicYOffset : -8,
377                    graphicOpacity : "${opacity}",
378                    rotation : "${angle}",
379                    backgroundGraphic : DOKU_BASE + "lib/plugins/openlayersmap/icons/marker_shadow.png",
380                    // backgroundXOffset : 0,
381                    // backgroundYOffset : -4,
382                    backgroundRotation : "${angle}",
383                    pointRadius : 10,
384                    labelXOffset : 8,
385                    labelYOffset : 8,
386                    labelAlign : "lb",
387                    label : "${label}",
388                    // fontColor : "",
389                    fontFamily : "monospace",
390                    fontSize : "12px",
391                    fontWeight : "bold"
392                },
393                "select" : {
394                    cursor : "help",
395                    externalGraphic : DOKU_BASE + "lib/plugins/openlayersmap/icons/marker-red.png",
396                    graphicHeight : 16,
397                    graphicWidth : 16,
398                    // graphicXOffset : 0,
399                    // graphicYOffset : -8,
400                    graphicOpacity : 1.0,
401                    rotation : "${angle}"
402                }
403            }),
404            isBaseLayer : false,
405            rendererOptions : {
406                yOrdering : true
407            }
408        });
409        m.addLayer(markers);
410        var features = [];
411        for (var j = 0; j < OLmapPOI.length; j++) {
412            var feat = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(OLmapPOI[j].lon, OLmapPOI[j].lat)
413                    .transform(m.displayProjection, m.projection), {
414                angle : OLmapPOI[j].angle,
415                opacity : OLmapPOI[j].opacity,
416                img : DOKU_BASE + "lib/plugins/openlayersmap/icons/" + OLmapPOI[j].img,
417                label : OLmapPOI[j].rowId
418            });
419            var _latlon = OLmapPOI[j].lat + 'º;' + OLmapPOI[j].lon + 'º';
420            if (mapOpts.displayformat === 'DMS') {
421                _latlon = OpenLayers.Util.getFormattedLonLat(OLmapPOI[j].lat, 'lat') + ';'
422                        + OpenLayers.Util.getFormattedLonLat(OLmapPOI[j].lon, 'lon');
423            }
424            feat.data = {
425                name : OLmapPOI[j].txt,
426                rowId : OLmapPOI[j].rowId,
427                latlon : _latlon,
428                lat: OLmapPOI[j].lat,
429                lon: OLmapPOI[j].lon,
430                alt : OLmapPOI[j].img.substring(0, OLmapPOI[j].img.lastIndexOf("."))
431            };
432            features.push(feat);
433        }
434        markers.addFeatures(features);
435        if (mapOpts.autozoom) {
436            extent.extend(markers.getDataExtent());
437            m.zoomToExtent(extent);
438        }
439    }
440
441    /* GPX layer */
442    if (mapOpts.gpxfile.length > 0) {
443        var layerGPX = new OpenLayers.Layer.Vector("GPS route", {
444            protocol : new OpenLayers.Protocol.HTTP({
445                url : DOKU_BASE + "lib/exe/fetch.php?media=" + mapOpts.gpxfile,
446                format : new OpenLayers.Format.GPX({
447                    extractWaypoints : true,
448                    extractTracks : true,
449                    extractStyles : true,
450                    extractAttributes : true,
451                    handleHeight : true,
452                    maxDepth : 3
453                })
454            }),
455            style : {
456                strokeColor : "#0000FF",
457                strokeWidth : 3,
458                strokeOpacity : 0.7,
459                pointRadius : 4,
460                fillColor : "#0099FF",
461                fillOpacity : 0.7
462            // , label:"${name}"
463            },
464            projection : new OpenLayers.Projection("EPSG:4326"),
465            strategies : [ new OpenLayers.Strategy.Fixed() ]
466        });
467        m.addLayer(layerGPX);
468        if (mapOpts.autozoom) {
469            layerGPX.events.register('loadend', m, function() {
470                extent.extend(layerGPX.getDataExtent());
471                m.zoomToExtent(extent);
472            });
473        }
474    }
475
476    /* GeoJSON layer */
477    if (mapOpts.geojsonfile.length > 0) {
478        var layerGJS = new OpenLayers.Layer.Vector("json data", {
479            protocol : new OpenLayers.Protocol.HTTP({
480                url : DOKU_BASE + "lib/exe/fetch.php?media=" + mapOpts.geojsonfile,
481                format : new OpenLayers.Format.GeoJSON({
482                    ignoreExtraDims : true
483                })
484            }),
485            style : {
486                strokeColor : "#FF00FF",
487                strokeWidth : 3,
488                strokeOpacity : 0.7,
489                pointRadius : 4,
490                fillColor : "#FF99FF",
491                fillOpacity : 0.7
492            // , label:"${name}"
493            },
494            projection : new OpenLayers.Projection("EPSG:4326"),
495            strategies : [ new OpenLayers.Strategy.Fixed() ]
496        });
497        m.addLayer(layerGJS);
498        if (mapOpts.autozoom) {
499            layerGJS.events.register('loadend', m, function() {
500                extent.extend(layerGJS.getDataExtent());
501                m.zoomToExtent(extent);
502            });
503        }
504    }
505
506    /* KML layer */
507    if (mapOpts.kmlfile.length > 0) {
508        var layerKML = new OpenLayers.Layer.Vector("KML file", {
509            protocol : new OpenLayers.Protocol.HTTP({
510                url : DOKU_BASE + "lib/exe/fetch.php?media=" + mapOpts.kmlfile,
511                format : new OpenLayers.Format.KML({
512                    extractStyles : true,
513                    extractAttributes : true,
514                    maxDepth : 3
515                })
516            }),
517            style : {
518                label : "${name}"
519            },
520            projection : new OpenLayers.Projection("EPSG:4326"),
521            strategies : [ new OpenLayers.Strategy.Fixed() ]
522        });
523        m.addLayer(layerKML);
524        if (mapOpts.autozoom) {
525            layerKML.events.register('loadend', m, function() {
526                extent.extend(layerKML.getDataExtent());
527                m.zoomToExtent(extent);
528            });
529        }
530    }
531
532    // selectcontrol for layers
533    if ((m.getLayersByClass('OpenLayers.Layer.GML').length > 0)
534            || m.getLayersByClass('OpenLayers.Layer.Vector').length > 0) {
535        selectControl = new OpenLayers.Control.SelectFeature((m.getLayersByClass('OpenLayers.Layer.Vector')).concat(m
536                .getLayersByClass('OpenLayers.Layer.GML')), {
537            hover : mapOpts.poihoverstyle,
538            onSelect : onFeatureSelect,
539            onUnselect : onFeatureUnselect
540        });
541        m.addControl(selectControl);
542        selectControl.activate();
543
544        // keyboard select control
545        var iControl = new OpenLayersMap.Control.KeyboardClick({
546            observeElement : mapOpts.id,
547            selectControl : selectControl
548        });
549        m.addControl(iControl);
550    }
551
552    if (mapOpts.controls === 1) {
553        /* add base controls to map */
554        m.addControls([ new OpenLayersMap.Control.LayerSwitcher(), new OpenLayers.Control.Graticule({
555            visible : false
556        }), new OpenLayersMap.Control.OverviewMap({
557            mapOptions : {
558                theme : null
559            }
560        }), new OpenLayersMap.Control.Zoom(), new OpenLayersMap.Control.Fullscreen() ]);
561
562        // add hillshade, since this is off by default only add when we have a
563        // layerswitcher
564        m.addLayer(new OpenLayers.Layer.OSM("Hillshade", "https://tiles.wmflabs.org/hillshading/${z}/${x}/${y}.png", {
565            isBaseLayer : false,
566            transparent : true,
567            visibility : false,
568            displayOutsideMaxExtent : true,
569            attribution : '',
570            tileOptions : {
571                crossOriginKeyword : null
572            }
573        }));
574    }
575
576    return m;
577}
578
579/** init. */
580function olInit() {
581    if (olEnable) {
582        var _i = 0;
583        // create the maps in the page
584        for (_i = 0; _i < olMapData.length; _i++) {
585            var _id = olMapData[_i].mapOpts.id;
586            olMaps[_id] = createMap(olMapData[_i].mapOpts, olMapData[_i].poi);
587
588            // set max-width on help pop-over
589            jQuery('#' + _id).parent().parent().find('.olMapHelp').css('max-width', olMapData[_i].mapOpts.width);
590
591            // shrink the map width to fit inside page container
592            var _w = jQuery('#' + _id + '-olContainer').parent().innerWidth();
593            if (parseInt(olMapData[_i].mapOpts.width) > _w) {
594                jQuery('#' + _id).width(_w);
595                jQuery('#' + _id + '-olStatusBar').width(_w);
596                jQuery('#' + _id).parent().parent().find('.olMapHelp').width(_w);
597                olMaps[_id].updateSize();
598            }
599        }
600
601        var resizeTimer;
602        jQuery(window).on('resize', function(e) {
603            clearTimeout(resizeTimer);
604            resizeTimer = setTimeout(function() {
605                for (_i = 0; _i < olMapData.length; _i++) {
606                    var _id = olMapData[_i].mapOpts.id;
607                    var _w = jQuery('#' + _id + '-olContainer').parent().innerWidth();
608                    if (parseInt(olMapData[_i].mapOpts.width) > _w) {
609                        jQuery('#' + _id).width(_w);
610                        jQuery('#' + _id + '-olStatusBar').width(_w);
611                        jQuery('#' + _id).parent().parent().find('.olMapHelp').width(_w);
612                        olMaps[_id].updateSize();
613                    }
614                }
615            }, 250);
616        });
617
618        // hide the table(s) with POI by giving it a print-only style
619        jQuery('.olPOItableSpan').addClass('olPrintOnly');
620        // hide the static map image(s) by giving it a print only style
621        jQuery('.olStaticMap').addClass('olPrintOnly');
622        // add help button with toggle.
623        jQuery('.olWebOnly > .olMap')
624                .prepend(
625                        '<div class="olMapHelpButtonDiv">'
626                                + '<button onclick="jQuery(\'.olMapHelp\').toggle(500);" class="olMapHelpButton olHasTooltip"><span>'
627                                + OpenLayers.i18n("toggle_help") + '</span>?</button></div>');
628        // toggle to switch dynamic vs. static map
629        jQuery('.olMapHelp').before(
630                '<div class="a11y"><button onclick="jQuery(\'.olPrintOnly\').toggle();jQuery(\'.olWebOnly\').toggle();">'
631                        + OpenLayers.i18n("toggle_dynamic_map") + '</button></div>');
632    }
633}
634
635/**
636 * ol api flag.
637 *
638 * @type {Boolean}
639 */
640var olEnable = false,
641/**
642 * An array with data for each map in the page.
643 *
644 * @type {Array}
645 */
646olMapData = [],
647/**
648 * Holds a reference to all of the maps on this page with the map's id as key.
649 * Can be used as an extension point.
650 *
651 * @type {Object}
652 */
653olMaps = new Object(),
654/**
655 * Stamen tiles flag.
656 *
657 * @type {Boolean}
658 */
659stamenEnable = false,
660/**
661 * google map api flag.
662 *
663 * @type {Boolean}
664 */
665gEnable = false,
666/**
667 * Bing tiles flag.
668 *
669 * @type {Boolean}
670 */
671bEnable = false,
672/**
673 * Bing API key.
674 *
675 * @type {String}
676 */
677bApiKey = '',
678/**
679 * Google API key.
680 *
681 * @type {String}
682 */
683gApiKey = '',
684/**
685 * Thunderforest API key.
686 *
687 * @type {String}
688 */
689tfApiKey = '',
690/**
691 * OSM tiles flag.
692 *
693 * @type {Boolean}
694 */
695osmEnable = true,
696/**
697 * CSS support flag.
698 *
699 * @type {Boolean}
700 */
701olCSSEnable = true;
702
703/* register olInit to run with onload event. */
704jQuery(olInit);
705