xref: /plugin/openlayersmap/script.js (revision a0e148596671717ee1531a34ce9e520a08633d83)
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				'//a.tile.thunderforest.com/cycle/${z}/${x}/${y}.png?apikey='+tfApiKey,
223				'//b.tile.thunderforest.com/cycle/${z}/${x}/${y}.png?apikey='+tfApiKey,
224				'//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				"http://a.tile.thunderforest.com/transport/${z}/${x}/${y}.png?apikey="+tfApiKey,
230				"http://b.tile.thunderforest.com/transport/${z}/${x}/${y}.png?apikey="+tfApiKey,
231				"http://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				"http://a.tile.thunderforest.com/landscape/${z}/${x}/${y}.png?apikey="+tfApiKey,
237				"http://b.tile.thunderforest.com/landscape/${z}/${x}/${y}.png?apikey="+tfApiKey,
238				"http://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				"http://a.tile.thunderforest.com/outdoors/${z}/${x}/${y}.png?apikey="+tfApiKey,
244				"http://b.tile.thunderforest.com/outdoors/${z}/${x}/${y}.png?apikey="+tfApiKey,
245				"http://c.tile.thunderforest.com/outdoors/${z}/${x}/${y}.png?apikey="+tfApiKey ], {
246			visibility : mapOpts.baselyr === "outdoors",
247			apikey : tfApiKey
248		}));
249
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	 * add Stamen map layers, see: http://maps.stamen.com/
260	 */
261	if (stamenEnable) {
262		m.addLayer(new OpenLayersMap.Layer.StamenTerrain());
263		m.addLayer(new OpenLayersMap.Layer.StamenToner());
264	}
265
266	if (gEnable) {
267		/* load google maps */
268		try {
269			m.addLayer(new OpenLayers.Layer.Google("google relief", {
270				type : google.maps.MapTypeId.TERRAIN,
271				numZoomLevels : 16,
272				animationEnabled : true,
273				visibility : mapOpts.baselyr === "google relief"
274			}));
275			m.addLayer(new OpenLayers.Layer.Google("google sat", {
276				type : google.maps.MapTypeId.SATELLITE,
277				animationEnabled : true,
278				visibility : mapOpts.baselyr === "google sat"
279			}));
280			m.addLayer(new OpenLayers.Layer.Google("google hybrid", {
281				type : google.maps.MapTypeId.HYBRID,
282				animationEnabled : true,
283				visibility : mapOpts.baselyr === "google hybrid"
284			}));
285			m.addLayer(new OpenLayers.Layer.Google("google road", {
286				animationEnabled : true,
287				visibility : mapOpts.baselyr === "google road"
288			}));
289		} catch (ol_err1) {
290			Openlayers.Console.userError('Error loading Google maps' + ol_err1);
291		}
292	}
293
294	if (bEnable && bApiKey !== '') {
295		try {
296			/* add Bing tiles */
297			m.addLayer(new OpenLayers.Layer.Bing({
298				key : bApiKey,
299				type : "Road",
300				name : "bing road",
301				visibility : mapOpts.baselyr === "bing road",
302				wrapDateLine : true,
303				attributionTemplate : '<a target="_blank" href="http://www.bing.com/maps/">'
304						+ 'Bing™</a><img src="//www.bing.com/favicon.ico" alt="Bing logo"/> ${copyrights}'
305						+ '<a target="_blank" href="http://www.microsoft.com/maps/product/terms.html">Terms of Use</a>'
306			}));
307			m.addLayer(new OpenLayers.Layer.Bing({
308				key : bApiKey,
309				type : "Aerial",
310				name : "bing sat",
311				visibility : mapOpts.baselyr === "bing sat",
312				wrapDateLine : true,
313				attributionTemplate : '<a target="_blank" href="http://www.bing.com/maps/">'
314						+ 'Bing™</a><img src="//www.bing.com/favicon.ico" alt="Bing logo"/> ${copyrights}'
315						+ '<a target="_blank" href="http://www.microsoft.com/maps/product/terms.html">Terms of Use</a>'
316			}));
317			m.addLayer(new OpenLayers.Layer.Bing({
318				key : bApiKey,
319				type : "AerialWithLabels",
320				name : "bing hybrid",
321				visibility : mapOpts.baselyr === "bing hybrid",
322				wrapDateLine : true,
323				attributionTemplate : '<a target="_blank" href="http://www.bing.com/maps/">'
324						+ 'Bing™</a><img src="//www.bing.com/favicon.ico" alt="Bing logo"/> ${copyrights}'
325						+ '<a target="_blank" href="http://www.microsoft.com/maps/product/terms.html">Terms of Use</a>'
326			}));
327		} catch (ol_errBing) {
328			Openlayers.Console.userError('Error loading Bing maps: ' + ol_errBing);
329		}
330	}
331
332	m.setCenter(new OpenLayers.LonLat(mapOpts.lon, mapOpts.lat).transform(m.displayProjection, m.projection),
333			mapOpts.zoom);
334	extent.extend(m.getExtent());
335
336	// change/set alternative baselyr
337	try {
338		m.setBaseLayer(((m.getLayersByName(mapOpts.baselyr))[0]));
339	} catch (ol_err4) {
340		m.setBaseLayer(m.layers[0]);
341	}
342
343	m.addControls([ new OpenLayers.Control.ScaleLine({
344		geodesic : true
345	}), new OpenLayers.Control.KeyboardDefaults({
346		observeElement : mapOpts.id
347	}), new OpenLayers.Control.Navigation() ]);
348
349	if (mapOpts.statusbar === 1) {
350		// statusbar control: mouse pos.
351		m.addControl(new OpenLayers.Control.MousePosition({
352			'div' : OpenLayers.Util.getElement(mapOpts.id + '-statusbar-mouseposition')
353		}));
354		// statusbar control: scale
355		m.addControl(new OpenLayers.Control.Scale(mapOpts.id + '-statusbar-scale'));
356		// statusbar control: attribution
357		m.addControl(new OpenLayers.Control.Attribution({
358			'div' : OpenLayers.Util.getElement(mapOpts.id + '-statusbar-text')
359		}));
360		// statusbar control: projection
361		OpenLayers.Util.getElement(mapOpts.id + '-statusbar-projection').innerHTML = m.displayProjection;
362	} else {
363		OpenLayers.Util.getElement(mapOpts.id + '-olStatusBar').display = 'none';
364	}
365
366	if (OLmapPOI.length > 0) {
367		var markers = new OpenLayers.Layer.Vector("POI", {
368			styleMap : new OpenLayers.StyleMap({
369				"default" : {
370					cursor : "help",
371					externalGraphic : "${img}",
372					graphicHeight : 16,
373					graphicWidth : 16,
374					// graphicXOffset : 0,
375					// graphicYOffset : -8,
376					graphicOpacity : "${opacity}",
377					rotation : "${angle}",
378					backgroundGraphic : DOKU_BASE + "lib/plugins/openlayersmap/icons/marker_shadow.png",
379					// backgroundXOffset : 0,
380					// backgroundYOffset : -4,
381					backgroundRotation : "${angle}",
382					pointRadius : 10,
383					labelXOffset : 8,
384					labelYOffset : 8,
385					labelAlign : "lb",
386					label : "${label}",
387					// fontColor : "",
388					fontFamily : "monospace",
389					fontSize : "12px",
390					fontWeight : "bold"
391				},
392				"select" : {
393					cursor : "help",
394					externalGraphic : DOKU_BASE + "lib/plugins/openlayersmap/icons/marker-red.png",
395					graphicHeight : 16,
396					graphicWidth : 16,
397					// graphicXOffset : 0,
398					// graphicYOffset : -8,
399					graphicOpacity : 1.0,
400					rotation : "${angle}"
401				}
402			}),
403			isBaseLayer : false,
404			rendererOptions : {
405				yOrdering : true
406			}
407		});
408		m.addLayer(markers);
409		var features = [];
410		for (var j = 0; j < OLmapPOI.length; j++) {
411			var feat = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(OLmapPOI[j].lon, OLmapPOI[j].lat)
412					.transform(m.displayProjection, m.projection), {
413				angle : OLmapPOI[j].angle,
414				opacity : OLmapPOI[j].opacity,
415				img : DOKU_BASE + "lib/plugins/openlayersmap/icons/" + OLmapPOI[j].img,
416				label : OLmapPOI[j].rowId
417			});
418			var _latlon = OLmapPOI[j].lat + 'º;' + OLmapPOI[j].lon + 'º';
419			if (mapOpts.displayformat === 'DMS') {
420				_latlon = OpenLayers.Util.getFormattedLonLat(OLmapPOI[j].lat, 'lat') + ';'
421						+ OpenLayers.Util.getFormattedLonLat(OLmapPOI[j].lon, 'lon');
422			}
423			feat.data = {
424				name : OLmapPOI[j].txt,
425				rowId : OLmapPOI[j].rowId,
426				latlon : _latlon,
427				lat: OLmapPOI[j].lat,
428				lon: OLmapPOI[j].lon,
429                alt : OLmapPOI[j].img.substring(0, OLmapPOI[j].img.lastIndexOf("."))
430			};
431			features.push(feat);
432		}
433		markers.addFeatures(features);
434		extent.extend(markers.getDataExtent());
435		m.zoomToExtent(extent);
436	}
437
438	/* GPX layer */
439	if (mapOpts.gpxfile.length > 0) {
440		var layerGPX = new OpenLayers.Layer.Vector("GPS route", {
441			protocol : new OpenLayers.Protocol.HTTP({
442				url : DOKU_BASE + "lib/exe/fetch.php?media=" + mapOpts.gpxfile,
443				format : new OpenLayers.Format.GPX({
444					extractWaypoints : true,
445					extractTracks : true,
446					extractStyles : true,
447					extractAttributes : true,
448					handleHeight : true,
449					maxDepth : 3
450				})
451			}),
452			style : {
453				strokeColor : "#0000FF",
454				strokeWidth : 3,
455				strokeOpacity : 0.7,
456				pointRadius : 4,
457				fillColor : "#0099FF",
458				fillOpacity : 0.7
459			// , label:"${name}"
460			},
461			projection : new OpenLayers.Projection("EPSG:4326"),
462			strategies : [ new OpenLayers.Strategy.Fixed() ]
463		});
464		m.addLayer(layerGPX);
465		layerGPX.events.register('loadend', m, function() {
466			extent.extend(layerGPX.getDataExtent());
467			m.zoomToExtent(extent);
468		});
469	}
470
471	/* GeoJSON layer */
472	if (mapOpts.geojsonfile.length > 0) {
473		var layerGJS = new OpenLayers.Layer.Vector("json data", {
474			protocol : new OpenLayers.Protocol.HTTP({
475				url : DOKU_BASE + "lib/exe/fetch.php?media=" + mapOpts.geojsonfile,
476				format : new OpenLayers.Format.GeoJSON({
477					ignoreExtraDims : true
478				})
479			}),
480			style : {
481				strokeColor : "#FF00FF",
482				strokeWidth : 3,
483				strokeOpacity : 0.7,
484				pointRadius : 4,
485				fillColor : "#FF99FF",
486				fillOpacity : 0.7
487			// , label:"${name}"
488			},
489			projection : new OpenLayers.Projection("EPSG:4326"),
490			strategies : [ new OpenLayers.Strategy.Fixed() ]
491		});
492		m.addLayer(layerGJS);
493		layerGJS.events.register('loadend', m, function() {
494			extent.extend(layerGJS.getDataExtent());
495			m.zoomToExtent(extent);
496		});
497	}
498
499	/* KML layer */
500	if (mapOpts.kmlfile.length > 0) {
501		var layerKML = new OpenLayers.Layer.Vector("KML file", {
502			protocol : new OpenLayers.Protocol.HTTP({
503				url : DOKU_BASE + "lib/exe/fetch.php?media=" + mapOpts.kmlfile,
504				format : new OpenLayers.Format.KML({
505					extractStyles : true,
506					extractAttributes : true,
507					maxDepth : 3
508				})
509			}),
510			style : {
511				label : "${name}"
512			},
513			projection : new OpenLayers.Projection("EPSG:4326"),
514			strategies : [ new OpenLayers.Strategy.Fixed() ]
515		});
516		m.addLayer(layerKML);
517		layerKML.events.register('loadend', m, function() {
518			extent.extend(layerKML.getDataExtent());
519			m.zoomToExtent(extent);
520		});
521	}
522
523	// selectcontrol for layers
524	if ((m.getLayersByClass('OpenLayers.Layer.GML').length > 0)
525			|| m.getLayersByClass('OpenLayers.Layer.Vector').length > 0) {
526		selectControl = new OpenLayers.Control.SelectFeature((m.getLayersByClass('OpenLayers.Layer.Vector')).concat(m
527				.getLayersByClass('OpenLayers.Layer.GML')), {
528			hover : mapOpts.poihoverstyle,
529			onSelect : onFeatureSelect,
530			onUnselect : onFeatureUnselect
531		});
532		m.addControl(selectControl);
533		selectControl.activate();
534
535		// keyboard select control
536		var iControl = new OpenLayersMap.Control.KeyboardClick({
537			observeElement : mapOpts.id,
538			selectControl : selectControl
539		});
540		m.addControl(iControl);
541	}
542
543	if (mapOpts.controls === 1) {
544		/* add base controls to map */
545		m.addControls([ new OpenLayersMap.Control.LayerSwitcher(), new OpenLayers.Control.Graticule({
546			visible : false
547		}), new OpenLayersMap.Control.OverviewMap({
548			mapOptions : {
549				theme : null
550			}
551		}), new OpenLayersMap.Control.Zoom(), new OpenLayersMap.Control.Fullscreen() ]);
552
553		// add hillshade, since this is off by default only add when we have a
554		// layerswitcher
555		/*
556		m.addLayer(new OpenLayers.Layer.OSM("Hillshade", "http://toolserver.org/~cmarqu/hill/${z}/${x}/${y}.png", {
557			isBaseLayer : false,
558			transparent : true,
559			visibility : false,
560			displayOutsideMaxExtent : true,
561			attribution : '',
562			tileOptions : {
563				crossOriginKeyword : null
564			}
565		}));
566		*/
567	}
568
569	return m;
570}
571
572/** init. */
573function olInit() {
574	if (olEnable) {
575		var _i = 0;
576		// create the maps in the page
577		for (_i = 0; _i < olMapData.length; _i++) {
578			var _id = olMapData[_i].mapOpts.id;
579			olMaps[_id] = createMap(olMapData[_i].mapOpts, olMapData[_i].poi);
580
581			// set max-width on help pop-over
582			jQuery('#' + _id).parent().parent().find('.olMapHelp').css('max-width', olMapData[_i].mapOpts.width);
583
584			// shrink the map width to fit inside page container
585			//TODO also do this when window is resized
586			var _w = jQuery('#' + _id + '-olContainer').parent().innerWidth();
587			if (parseInt(olMapData[_i].mapOpts.width) > _w) {
588				jQuery('#' + _id).width(_w);
589				jQuery('#' + _id + '-olStatusBar').width(_w);
590				jQuery('#' + _id).parent().parent().find('.olMapHelp').width(_w);
591				olMaps[_id].updateSize();
592			}
593		}
594
595		// hide the table(s) with POI by giving it a print-only style
596		jQuery('.olPOItableSpan').addClass('olPrintOnly');
597		// hide the static map image(s) by giving it a print only style
598		jQuery('.olStaticMap').addClass('olPrintOnly');
599		// add help button with toggle.
600		jQuery('.olWebOnly > .olMap')
601				.prepend(
602						'<div class="olMapHelpButtonDiv">'
603								+ '<button onclick="jQuery(\'.olMapHelp\').toggle(500);" class="olMapHelpButton olHasTooltip"><span>'
604								+ OpenLayers.i18n("toggle_help") + '</span>?</button></div>');
605		// toggle to switch dynamic vs. static map
606		jQuery('.olMapHelp').before(
607				'<div class="a11y"><button onclick="jQuery(\'.olPrintOnly\').toggle();jQuery(\'.olWebOnly\').toggle();">'
608						+ OpenLayers.i18n("toggle_dynamic_map") + '</button></div>');
609	}
610}
611
612/**
613 * ol api flag.
614 *
615 * @type {Boolean}
616 */
617var olEnable = false,
618/**
619 * An array with data for each map in the page.
620 *
621 * @type {Array}
622 */
623olMapData = [],
624/**
625 * Holds a reference to all of the maps on this page with the map's id as key.
626 * Can be used as an extension point.
627 *
628 * @type {Object}
629 */
630olMaps = new Object(),
631/**
632 * Stamen tiles flag.
633 *
634 * @type {Boolean}
635 */
636stamenEnable = false,
637/**
638 * google map api flag.
639 *
640 * @type {Boolean}
641 */
642gEnable = false,
643/**
644 * Bing tiles flag.
645 *
646 * @type {Boolean}
647 */
648bEnable = false,
649/**
650 * Bing API key.
651 *
652 * @type {String}
653 */
654bApiKey = '',
655/**
656 * Google API key.
657 *
658 * @type {String}
659 */
660gApiKey = '',
661/**
662 * Thunderforest API key.
663 *
664 * @type {String}
665 */
666tfApiKey = '',
667/**
668 * OSM tiles flag.
669 *
670 * @type {Boolean}
671 */
672osmEnable = true,
673/**
674 * CSS support flag.
675 *
676 * @type {Boolean}
677 */
678olCSSEnable = true;
679
680/* register olInit to run with onload event. */
681jQuery(olInit);
682