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