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