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