xref: /plugin/openlayersmap/script.js (revision 787a5195b91bca60f913c3d8074ae47274e4289c)
1/*
2 * Copyright (c) 2008-2011 Mark C. Prins <mc.prins@gmail.com>
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 other full openlayers build
21 * @author Mark C. Prins <mc.prins@gmail.com>
22 *
23 */
24
25/**
26 * Openlayers selectcontrol.
27 *
28 * @type {OpenLayers.Control.SelectFeature}
29 * @private
30 */
31var selectControl;
32/**
33 * Openlayers bounds used for managing the map extent.
34 *
35 * @type {OpenLayers.Bounds}
36 * @private
37 */
38var extent;
39
40/**
41 * handle feature select event.
42 *
43 * @param {OpenLayers.Feature.Vector}
44 *            the selected feature
45 */
46function onFeatureSelect(feature) {
47	var selectedFeature = feature;
48	// 'this' is selectFeature control
49	var pPos = selectedFeature.geometry.getBounds().getCenterLonLat();
50	// != OpenLayers.Geometry.Point
51	if (selectedFeature.geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") {
52		try {
53			// for lines make the popup show at the cursor position
54			pPos = feature.layer.map
55					.getLonLatFromViewPortPx(this.handlers.feature.evt.xy);
56		} catch (anErr) {
57			console
58					.warn("unable to get event position; reverting to boundingbox center.");
59			pPos = selectedFeature.geometry.getBounds().getCenterLonLat();
60		}
61	}
62
63	var pContent = "";
64	if (feature.data.rowId != undefined) {
65		pContent += "<span style=''>" + feature.data.rowId + ": </span>";
66	}
67	if (feature.data.name != undefined) {
68		pContent += "<div style=''>" + feature.data.name + "<br /></div>";
69	}
70	if (feature.data.ele != undefined) {
71		pContent += "<div style=''>elevation: " + feature.data.ele
72				+ "<br /></div>";
73	}
74	if (feature.data.type != undefined) {
75		pContent += "<div style=''>" + feature.data.type + "<br /></div>";
76	}
77	if (feature.data.time != undefined) {
78		pContent += "<div style=''>time: " + feature.data.time + "<br /></div>";
79	}
80	if (feature.data.description != undefined) {
81		pContent += "<div style=''>" + feature.data.description + "</div>";
82	}
83
84	if (pContent.length > 0) {
85		var popup = new OpenLayers.Popup.FramedCloud("olPopup", pPos, null,
86				pContent, null, true, function() {
87					selectControl.unselect(selectedFeature);
88				});
89		feature.popup = popup;
90		feature.layer.map.addPopup(popup);
91	}
92}
93
94/**
95 * handle feature unselect event. remove & destroy the popup.
96 *
97 * @param {OpenLayers.Feature.Vector}
98 *            the un-selected feature
99 */
100function onFeatureUnselect(feature) {
101	if (feature.popup != null) {
102		feature.layer.map.removePopup(feature.popup);
103		feature.popup.destroy();
104		feature.popup = null;
105	}
106}
107
108// TODO IE7 and lower don't have document.getElementsByClassName so we make one;
109// seems to conflict with openlayers prototypes?
110// Object.prototype.getElementsByClassName = document.getElementsByClassName =
111// document.getElementsByClassName
112// || function(className) {
113// className = className.replace(/\s+/g, ' ').replace(
114// /^\s|![A-Za-z0-9-_\s]|\s$/g, '').split(' ');
115// for ( var i = 0, elements = this.getElementsByTagName('*'), elementsLength =
116// elements.length, b = [], classNameLength = className.length, passed = true; i
117// < elementsLength; i++, passed = true) {
118// for ( var j = 0; j < classNameLength && passed; j++) {
119// passed = (new RegExp(
120// '(^|\\\s)' + className[j] + '(\\\s|$)', 'i'))
121// .test(elements[i].className);
122// }
123// if (passed) {
124// b.push(elements[i]);
125// }
126// }
127// return b;
128// };
129
130/** init. */
131function olInit() {
132	// hide the table with POI
133	// var tbls = getElementsByClass('olPOItable', document, 'table');
134	var tbls = getElementsByClass('olPOItable', null, null);
135	// var tbls = getElementsByClassName('olPOItable');
136	// console.log(tbls);
137	for (i = 0; i < tbls.length; i++) {
138		tbls[i].className = tbls[i].className + ' olPrintOnly';
139	}
140
141	// hide the static image
142	var statImg = getElementsByClass('olStaticMap', null, null);
143	for (i = 0; i < statImg.length; i++) {
144		statImg[i].style.display = 'none';
145	}
146
147}
148
149/**
150 * create the map based on the params given.
151 *
152 * @param {Object}mapOpts
153 *            MapOptions hash {id:'olmap', lat:6710200, lon:506500, zoom:13,
154 *            toolbar:1, statusbar:1, controls:1, poihoverstyle:1, baselyr:'',
155 *            kmlfile:'', gpxfile:'', summary:''}
156 * @param {Array}OLmapPOI
157 *            array with POI's [ {lat:6710300,lon:506000,txt:'instap
158 *            punt',angle:180,opacity:.9,img:'', rowId:n},... ]);
159 *
160 */
161function createMap(mapOpts, OLmapPOI) {
162	if (!olEnable) {
163		return;
164	}
165	OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3;
166	OpenLayers.Util.onImageLoadErrorColor = "transparent";
167	// http://mapbox.com/documentation/adding-tiles-your-site/openlayers-themes
168	// OpenLayers.ImgPath = '';
169
170	var extent = new OpenLayers.Bounds();
171
172	var mOpts = {
173		projection : new OpenLayers.Projection("EPSG:900913"),
174		displayProjection : new OpenLayers.Projection("EPSG:4326"),
175		units : "m",
176		maxResolution : 156543.0339,
177		maxExtent : new OpenLayers.Bounds(-20037508.3392, -20037508.3392,
178				20037508.3392, 20037508.3392),
179		controls : [],
180		numZoomLevels : 19
181	};
182	var m = new OpenLayers.Map(mapOpts.id, mOpts);
183	/* OSM maps */
184	m.addLayer(new OpenLayers.Layer.OSM("OpenStreetMap"), {
185		transitionEffect : "resize"
186	});
187	m.addLayer(new OpenLayers.Layer.OSM("t@h",
188			"http://tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png"), {
189		transitionEffect : "resize"
190	});
191	m
192			.addLayer(
193					new OpenLayers.Layer.OSM("cycle map",
194							"http://andy.sandbox.cloudmade.com/tiles/cycle/${z}/${x}/${y}.png"),
195					{
196						transitionEffect : "resize"
197					});
198	m
199			.addLayer(new OpenLayers.Layer.OSM(
200					"cloudmade map",
201					"http://tile.cloudmade.com/2f59745a6b525b4ebdb100891d5b6711/3/256/${z}/${x}/${y}.png",
202					{
203						transitionEffect : "resize"
204					}));
205	m.addLayer(new OpenLayers.Layer.OSM("hike and bike map",
206			"http://toolserver.org/tiles/hikebike/${z}/${x}/${y}.png", {
207				transitionEffect : "resize"
208			}));
209	/* open aerial map */
210	/*
211	 * turn this off; project is asleep:
212	 * https://sourceforge.net/tracker/?func=detail&aid=2897327&group_id=239475&atid=1110186
213	 * m.addLayer(new OpenLayers.Layer.XYZ("OpenAerialMap",
214	 * "http://tile.openaerialmap.org/tiles/1.0.0/openaerialmap-900913/${z}/${x}/${y}.jpg",
215	 * {name: "OpenStreetMap", attribution: "Data CC-By by <a
216	 * href='http://www.openaerialmap.org/licensing/'>OpenAerialMap</a>",
217	 * sphericalMercator: true, transitionEffect: "resize"} ));
218	 */
219
220	/* controle of google/yahoo/ve api's beschikbaar zijn.. */
221	if (gEnable) {
222		try {
223			m.addLayer(new OpenLayers.Layer.Google("google relief", {
224				type : G_PHYSICAL_MAP,
225				'sphericalMercator' : true,
226				transitionEffect : "resize"
227			}));
228			m.addLayer(new OpenLayers.Layer.Google("google sat", {
229				type : G_SATELLITE_MAP,
230				'sphericalMercator' : true,
231				transitionEffect : "resize"
232			}));
233			m.addLayer(new OpenLayers.Layer.Google("google hybrid", {
234				type : G_HYBRID_MAP,
235				'sphericalMercator' : true,
236				transitionEffect : "resize"
237			}));
238			m.addLayer(new OpenLayers.Layer.Google("google normal", {
239				type : G_NORMAL_MAP,
240				'sphericalMercator' : true,
241				transitionEffect : "resize"
242			}));
243		} catch (ol_err1) {
244		}
245	}
246
247	if (yEnable) {
248		try {
249			m.addLayer(new OpenLayers.Layer.Yahoo("yahoo", {
250				'type' : YAHOO_MAP_HYB,
251				'sphericalMercator' : true,
252				transitionEffect : resize
253			}));
254		} catch (ol_err2) {
255		}
256	}
257
258	if (veEnable) {
259		try {
260			m.addLayer(new OpenLayers.Layer.VirtualEarth("ve", {
261				'type' : VEMapStyle.Hybrid,
262				'sphericalMercator' : true,
263				transitionEffect : resize
264			}));
265		} catch (ol_err3) {
266		}
267	}
268	m.setCenter(new OpenLayers.LonLat(mapOpts.lon, mapOpts.lat).transform(
269			m.displayProjection, m.projection), mapOpts.zoom);
270	extent.extend(m.getExtent());
271
272	m.addControl(new OpenLayers.Control.KeyboardDefaults());
273	m.addControl(new OpenLayers.Control.Navigation());
274	if (mapOpts.controls === 1) {
275		/* add base controls to map */
276		m.addControl(new OpenLayers.Control.LayerSwitcher());
277		m.addControl(new OpenLayers.Control.ScaleLine({
278			geodesic : true
279		}));
280		m.addControl(new OpenLayers.Control.PanZoomBar());
281		m.addControl(new OpenLayers.Control.Graticule({
282			visible : false
283		}));
284		// TODO optioneel overzichts kaart toevoegen
285		// var overViewOpts = {layers: [wms.clone()],size: new
286		// OpenLayers.Size(120,120),projection: new
287		// OpenLayers.Projection("EPSG:900913"),opacity: 0.0,mapOptions: {
288		// /* Available resolutions are: [156543.03390000001,
289		// 78271.516950000005,
290		// 39135.758475000002, 19567.879237500001, 9783.9396187500006,
291		// 4891.9698093750003, 2445.9849046875001, 1222.9924523437501,
292		// 611.49622617187504, 305.74811308593752, 152.87405654296876,
293		// 76.43702827148438, 38.21851413574219, 19.109257067871095,
294		// 9.5546285339355475,
295		// 4.7773142669677737, 2.3886571334838869, 1.1943285667419434,
296		// 0.59716428337097172, 0.29858214168548586]*/
297		// maxResolution: 78271.51695,maxExtent: new
298		// OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34),
299		// /*
300		// minExtent: new OpenLayers.Bounds(1000,400000,400000,515000),*/
301		// numZoomLevels: 5},'div':OpenLayers.Util.getElement('overview')};
302		// map.addControl(new OpenLayers.Control.OverviewMap(overViewOpts));
303	}
304
305	if (mapOpts.statusbar === 1) {
306		// statusbar control: permalink
307		m.addControl(new OpenLayers.Control.Permalink(mapOpts.id
308				+ '-statusbar-link-ref'));
309		// statusbar control: mouse pos.
310		// TODO kijken naar afronding met aNumber.toFixed(0)
311		m.addControl(new OpenLayers.Control.MousePosition({
312			'div' : OpenLayers.Util.getElement(mapOpts.id
313					+ '-statusbar-mouseposition')
314		}));
315		// statusbar control: scale
316		m.addControl(new OpenLayers.Control.Scale(mapOpts.id
317				+ '-statusbar-scale'));
318		// statusbar control: attribution
319		m.addControl(new OpenLayers.Control.Attribution({
320			'div' : OpenLayers.Util.getElement(mapOpts.id + '-statusbar-text')
321		}));
322		// statusbar control: projection
323		OpenLayers.Util.getElement(mapOpts.id + '-statusbar-projection').innerHTML = m.displayProjection;
324	} else {
325		OpenLayers.Util.getElement(mapOpts.id + '-olStatusBar').display = 'none';
326	}
327
328	if (mapOpts.toolbar === 1) {
329		// buttons + panel
330		var zoomin = new OpenLayers.Control.ZoomBox({
331			title : "Zoom in"
332		});
333		var zoomout = new OpenLayers.Control.ZoomBox({
334			out : true,
335			title : "Zoom uit",
336			displayClass : "olControlZoomOut"
337		});
338		var pan = new OpenLayers.Control.DragPan({
339			title : "Verschuif"
340		});
341		// icon_query.png
342		var nav = new OpenLayers.Control.NavigationHistory();
343		m.addControl(nav);
344		var panel = new OpenLayers.Control.Panel({
345			defaultControl : zoomin,
346			displayClass : "olToolbar",
347			"div" : OpenLayers.Util.getElement(mapOpts.id + "-olToolbar")
348		});
349		panel.addControls([ zoomin, zoomout, pan ]);
350		panel.addControls([ nav.next, nav.previous ]);
351		m.addControl(panel);
352	} else {
353		OpenLayers.Util.getElement(mapOpts.id + '-olToolbar').display = 'none';
354	}
355
356	// add overlays
357	m.addLayer(new OpenLayers.Layer.OSM("Hillshade",
358			"http://toolserver.org/~cmarqu/hill/${z}/${x}/${y}.png", {
359				transitionEffect : "resize",
360				isBaseLayer : false,
361				transparent : true,
362				visibility : false
363			}));
364
365	var DocBase = DOKU_BASE;
366	if (OLmapPOI.length > 0) {
367		var markers = new OpenLayers.Layer.Vector(
368				"POI",
369				{
370					styleMap : new OpenLayers.StyleMap(
371							{
372								"default" : {
373									externalGraphic : "${img}",
374									graphicHeight : 16,
375									graphicWidth : 16,
376									graphicXOffset : 0,
377									graphicYOffset : -8,
378									graphicOpacity : "${opacity}",
379									rotation : "${angle}",
380									backgroundGraphic : DocBase
381											+ "lib/plugins/openlayersmap/icons/marker_shadow.png",
382									backgroundXOffset : 0,
383									backgroundYOffset : -4,
384									backgroundRotation : "${angle}",
385									pointRadius : 10,
386									labelXOffset : 8,
387									labelYOffset : 8,
388									labelAlign : "lb",
389									label : "${label}",
390									// fontColor : "",
391									fontFamily: "monospace",
392									fontSize : "12px",
393									fontWeight : "bold"
394								},
395								"select" : {
396									cursor : "crosshair",
397									externalGraphic : DocBase
398											+ "lib/plugins/openlayersmap/icons/marker-red.png",
399									graphicHeight : 16,
400									graphicWidth : 16,
401									graphicXOffset : 0,
402									graphicYOffset : -8,
403									graphicOpacity : 1.0,
404									rotation : "${angle}"
405								}
406							}),
407					isBaseLayer : false,
408					rendererOptions : {
409						yOrdering : true
410					}
411				});
412
413		m.addLayer(markers);
414		var features = [];
415		var lonLat;
416		for ( var j = 0; j < OLmapPOI.length; j++) {
417			var feat = new OpenLayers.Feature.Vector(
418					new OpenLayers.Geometry.Point(OLmapPOI[j].lon,
419							OLmapPOI[j].lat).transform(m.displayProjection,
420							m.projection), {
421						angle : OLmapPOI[j].angle,
422						opacity : OLmapPOI[j].opacity,
423						img : DocBase + "lib/plugins/openlayersmap/icons/"
424								+ OLmapPOI[j].img,
425						label : OLmapPOI[j].rowId
426					});
427			feat.data = {
428				name : OLmapPOI[j].txt,
429				rowId : OLmapPOI[j].rowId
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.GML("GPS route", DocBase
441				+ "lib/exe/fetch.php?media=" + mapOpts.gpxfile, {
442			format : OpenLayers.Format.GPX,
443			formatOptions : {
444				extractWaypoints : true,
445				extractTracks : true,
446				extractStyles : true,
447				extractAttributes : true,
448				handleHeight : true,
449				maxDepth : 3
450			},
451			style : {
452				strokeColor : "#0000FF",
453				strokeWidth : 3,
454				strokeOpacity : 0.7,
455				pointRadius : 4,
456				fillColor : "#0099FF",
457				fillOpacity : 0.7
458			/*
459			 * , label:"${name}"
460			 */},
461			projection : new OpenLayers.Projection("EPSG:4326")
462		});
463		m.addLayer(layerGPX);
464		layerGPX.events.register('loadend', m, function() {
465			extent.extend(layerGPX.getDataExtent());
466			m.zoomToExtent(extent);
467		});
468
469	}
470
471	/* KML layer */
472	if (mapOpts.kmlfile.length > 0) {
473		var layerKML = new OpenLayers.Layer.GML("KML file", DocBase
474				+ "lib/exe/fetch.php?media=" + mapOpts.kmlfile, {
475			format : OpenLayers.Format.KML,
476			formatOptions : {
477				extractStyles : true,
478				extractAttributes : true,
479				maxDepth : 3
480			},
481			style : {
482				label : "${name}"
483			},
484			projection : new OpenLayers.Projection("EPSG:4326")
485		});
486		m.addLayer(layerKML);
487		layerKML.events.register('loadend', m, function() {
488			extent.extend(layerKML.getDataExtent());
489			m.zoomToExtent(extent);
490		});
491	}
492
493	// selectcontrol for layers
494	if ((m.getLayersByClass('OpenLayers.Layer.GML').length > 0)
495			|| m.getLayersByClass('OpenLayers.Layer.Vector').length > 0) {
496		selectControl = new OpenLayers.Control.SelectFeature((m
497				.getLayersByClass('OpenLayers.Layer.Vector')).concat(m
498				.getLayersByClass('OpenLayers.Layer.GML')), {
499			multiple : true,
500			hover : mapOpts.poihoverstyle,
501			onSelect : onFeatureSelect,
502			onUnselect : onFeatureUnselect
503		});
504		m.addControl(selectControl);
505		selectControl.activate();
506	}
507
508	// change/set alternative baselyr
509	try {
510		m.setBaseLayer(m.getLayersByName(mapOpts.baselyr)[0]);
511	} catch (ol_err4) {
512		m.setBaseLayer(m.layers[0]);
513	}
514	return m;
515}
516
517/**
518 * ol api flag.
519 *
520 * @type {Boolean}
521 */
522var olEnable = false;
523/**
524 * google map api flag.
525 *
526 * @type {Boolean}
527 */
528var gEnable = false;
529/**
530 * virtual earth map api flag.
531 *
532 * @type {Boolean}
533 */
534var veEnable = false;
535/**
536 * yahoo map api flag.
537 *
538 * @type {Boolean}
539 */
540var yEnable = false;
541
542/* register olInit to run with onload event. */
543addInitEvent(olInit);
544