Subversion Repositories eFlore/Applications.moissonnage

Rev

Rev 31 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
28 alex 1
/*
2
 *
3
 * Copyright (c) 2011-2012, Pavel Shramov
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without modification, are
7
 * permitted provided that the following conditions are met:
8
 *
9
 *    1. Redistributions of source code must retain the above copyright notice, this list of
10
 *       conditions and the following disclaimer.
11
 *
12
 *    2. Redistributions in binary form must reproduce the above copyright notice, this list
13
 *       of conditions and the following disclaimer in the documentation and/or other materials
14
 *       provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
17
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
23
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
 *
26
 */
27
 
28
 
29
L.KML = L.FeatureGroup.extend({
30
	options: {
31
		async: true
32
	},
33
 
34
	initialize: function(kml, options) {
35
		L.Util.setOptions(this, options);
36
		this._kml = kml;
37
		this._layers = {};
38
 
39
		if (kml) {
40
			this.addKML(kml, options, this.options.async);
41
		}
42
	},
43
 
44
	loadXML: function(url, cb, options, async) {
45
		if (async == undefined) async = this.options.async;
46
		if (options == undefined) options = this.options;
47
 
48
		var req = new window.XMLHttpRequest();
49
		req.open('GET', url, async);
50
		try {
51
			req.overrideMimeType('text/xml'); // unsupported by IE
52
		} catch(e) {}
53
		req.onreadystatechange = function() {
54
			if (req.readyState != 4) return;
55
			if(req.status == 200) cb(req.responseXML, options);
56
		};
57
		req.send(null);
58
	},
59
 
60
	addKML: function(url, options, async) {
61
		var _this = this;
62
		var cb = function(gpx, options) { _this._addKML(gpx, options) };
63
		this.loadXML(url, cb, options, async);
64
	},
65
 
66
	_addKML: function(xml, options) {
67
		var layers = L.KML.parseKML(xml);
68
		if (!layers || !layers.length) return;
69
		for (var i = 0; i < layers.length; i++)
70
		{
71
			this.fire('addlayer', {
72
				layer: layers[i]
73
			});
74
			this.addLayer(layers[i]);
75
		}
76
		this.latLngs = L.KML.getLatLngs(xml);
77
		this.fire("loaded");
78
	},
79
 
80
	latLngs: []
81
});
82
 
83
L.Util.extend(L.KML, {
84
 
85
	parseKML: function (xml) {
86
		var style = this.parseStyle(xml);
87
		var el = xml.getElementsByTagName("Folder");
88
		var layers = [], l;
89
		for (var i = 0; i < el.length; i++) {
90
			if (!this._check_folder(el[i])) { continue; }
91
			l = this.parseFolder(el[i], style);
92
			if (l) { layers.push(l); }
93
		}
94
		el = xml.getElementsByTagName('Placemark');
95
		for (var j = 0; j < el.length; j++) {
96
			if (!this._check_folder(el[j])) { continue; }
97
			l = this.parsePlacemark(el[j], xml, style);
98
			if (l) { layers.push(l); }
99
		}
100
		return layers;
101
	},
102
 
103
	// Return false if e's first parent Folder is not [folder]
104
	// - returns true if no parent Folders
105
	_check_folder: function (e, folder) {
106
		e = e.parentElement;
107
		while (e && e.tagName !== "Folder")
108
		{
109
			e = e.parentElement;
110
		}
111
		return !e || e === folder;
112
	},
113
 
114
	parseStyle: function (xml) {
115
		var style = {};
116
		var sl = xml.getElementsByTagName("Style");
117
 
118
		//for (var i = 0; i < sl.length; i++) {
119
		var attributes = {color: true, width: true, Icon: true, href: true,
120
						  hotSpot: true};
121
 
122
		function _parse(xml) {
123
			var options = {};
124
			for (var i = 0; i < xml.childNodes.length; i++) {
125
				var e = xml.childNodes[i];
126
				var key = e.tagName;
127
				if (!attributes[key]) { continue; }
128
				if (key === 'hotSpot')
129
				{
130
					for (var j = 0; j < e.attributes.length; j++) {
131
						options[e.attributes[j].name] = e.attributes[j].nodeValue;
132
					}
133
				} else {
134
					var value = e.childNodes[0].nodeValue;
135
					if (key === 'color') {
136
						options.opacity = parseInt(value.substring(0, 2), 16) / 255.0;
137
						options.color = "#" + value.substring(2, 8);
138
					} else if (key === 'width') {
139
						options.weight = value;
140
					} else if (key === 'Icon') {
141
						ioptions = _parse(e);
142
						if (ioptions.href) { options.href = ioptions.href; }
143
					} else if (key === 'href') {
144
						options.href = value;
145
					}
146
				}
147
			}
148
			return options;
149
		}
150
 
151
		for (var i = 0; i < sl.length; i++) {
152
			var e = sl[i], el;
153
			var options = {}, poptions = {}, ioptions = {};
154
			el = e.getElementsByTagName("LineStyle");
155
			if (el && el[0]) { options = _parse(el[0]); }
156
			el = e.getElementsByTagName("PolyStyle");
157
			if (el && el[0]) { poptions = _parse(el[0]); }
158
			if (poptions.color) { options.fillColor = poptions.color; }
159
			if (poptions.opacity) { options.fillOpacity = poptions.opacity; }
160
			el = e.getElementsByTagName("IconStyle");
161
			if (el && el[0]) { ioptions = _parse(el[0]); }
162
			if (ioptions.href) {
163
				// save anchor info until the image is loaded
164
				options.icon = new L.KMLIcon({
165
					iconUrl: ioptions.href,
166
					shadowUrl: null,
167
					iconAnchorRef: {x: ioptions.x, y: ioptions.y},
168
					iconAnchorType:	{x: ioptions.xunits, y: ioptions.yunits}
169
				});
170
			}
171
			style['#' + e.getAttribute('id')] = options;
172
		}
173
		return style;
174
	},
175
 
176
	parseFolder: function (xml, style) {
177
		var el, layers = [], l;
178
		el = xml.getElementsByTagName('Folder');
179
		for (var i = 0; i < el.length; i++) {
180
			if (!this._check_folder(el[i], xml)) { continue; }
181
			l = this.parseFolder(el[i], style);
182
			if (l) { layers.push(l); }
183
		}
184
		el = xml.getElementsByTagName('Placemark');
185
		for (var j = 0; j < el.length; j++) {
186
			if (!this._check_folder(el[j], xml)) { continue; }
187
			l = this.parsePlacemark(el[j], xml, style);
188
			if (l) { layers.push(l); }
189
		}
190
		if (!layers.length) { return; }
191
		if (layers.length === 1) { return layers[0]; }
192
		return new L.FeatureGroup(layers);
193
	},
194
 
195
	parsePlacemark: function (place, xml, style) {
196
		var i, j, el, options = {};
197
		el = place.getElementsByTagName('styleUrl');
198
		for (i = 0; i < el.length; i++) {
199
			var url = el[i].childNodes[0].nodeValue;
200
			for (var a in style[url])
201
			{
202
				// for jshint
203
				if (true)
204
				{
205
					options[a] = style[url][a];
206
				}
207
			}
208
		}
209
		var layers = [];
210
 
211
		var parse = ['LineString', 'Polygon', 'Point'];
212
		for (j in parse) {
213
			// for jshint
214
			if (true)
215
			{
216
				var tag = parse[j];
217
				el = place.getElementsByTagName(tag);
218
				for (i = 0; i < el.length; i++) {
219
					var l = this["parse" + tag](el[i], xml, options);
220
					if (l) { layers.push(l); }
221
				}
222
			}
223
		}
224
 
225
		if (!layers.length) {
226
			return;
227
		}
228
		var layer = layers[0];
229
		if (layers.length > 1) {
230
			layer = new L.FeatureGroup(layers);
231
		}
232
 
233
		var name, descr = "";
234
		el = place.getElementsByTagName('name');
235
		if (el.length) {
236
			name = el[0].childNodes[0].nodeValue;
237
		}
238
		el = place.getElementsByTagName('description');
239
		for (i = 0; i < el.length; i++) {
240
			for (j = 0; j < el[i].childNodes.length; j++) {
241
				descr = descr + el[i].childNodes[j].nodeValue;
242
			}
243
		}
244
 
245
		if (name) {
246
			layer.bindPopup("<h2>" + name + "</h2>" + descr);
247
		}
248
 
249
		return layer;
250
	},
251
 
252
	parseCoords: function (xml) {
253
		var el = xml.getElementsByTagName('coordinates');
254
		return this._read_coords(el[0]);
255
	},
256
 
257
	parseLineString: function (line, xml, options) {
258
		var coords = this.parseCoords(line);
259
		if (!coords.length) { return; }
260
		return new L.Polyline(coords, options);
261
	},
262
 
263
	parsePoint: function (line, xml, options) {
264
		var el = line.getElementsByTagName('coordinates');
265
		if (!el.length) {
266
			return;
267
		}
268
		var ll = el[0].childNodes[0].nodeValue.split(',');
269
		return new L.KMLMarker(new L.LatLng(ll[1], ll[0]), options);
270
	},
271
 
272
	parsePolygon: function (line, xml, options) {
273
		var el, polys = [], inner = [], i, coords;
274
		el = line.getElementsByTagName('outerBoundaryIs');
275
		for (i = 0; i < el.length; i++) {
276
			coords = this.parseCoords(el[i]);
277
			if (coords) {
278
				polys.push(coords);
279
			}
280
		}
281
		el = line.getElementsByTagName('innerBoundaryIs');
282
		for (i = 0; i < el.length; i++) {
283
			coords = this.parseCoords(el[i]);
284
			if (coords) {
285
				inner.push(coords);
286
			}
287
		}
288
		if (!polys.length) {
289
			return;
290
		}
291
		if (options.fillColor) {
292
			options.fill = true;
293
		}
294
		if (polys.length === 1) {
295
			return new L.Polygon(polys.concat(inner), options);
296
		}
297
		return new L.MultiPolygon(polys, options);
298
	},
299
 
300
	getLatLngs: function (xml) {
301
		var el = xml.getElementsByTagName('coordinates');
302
		var coords = [];
303
		for (var j = 0; j < el.length; j++) {
304
			// text might span many childnodes
305
			coords = coords.concat(this._read_coords(el[j]));
306
		}
307
		return coords;
308
	},
309
 
310
	_read_coords: function (el) {
311
		var text = "", coords = [], i;
312
		for (i = 0; i < el.childNodes.length; i++) {
313
			text = text + el.childNodes[i].nodeValue;
314
		}
315
		text = text.split(/[\s\n]+/);
316
		for (i = 0; i < text.length; i++) {
317
			var ll = text[i].split(',');
318
			if (ll.length < 2) {
319
				continue;
320
			}
321
			coords.push(new L.LatLng(ll[1], ll[0]));
322
		}
323
		return coords;
324
	}
325
 
326
});
327
 
328
L.KMLIcon = L.Icon.extend({
329
 
330
	createIcon: function () {
331
		var img = this._createIcon('icon');
332
		img.onload = function () {
333
			var i = new Image();
334
			i.src = this.src;
335
			this.style.width = i.width + 'px';
336
			this.style.height = i.height + 'px';
337
 
338
			if (this.anchorType.x === 'UNITS_FRACTION' || this.anchorType.x === 'fraction') {
339
				img.style.marginLeft = (-this.anchor.x * i.width) + 'px';
340
			}
341
			if (this.anchorType.y === 'UNITS_FRACTION' || this.anchorType.x === 'fraction') {
342
				img.style.marginTop  = (-(1 - this.anchor.y) * i.height) + 'px';
343
			}
344
			this.style.display = "";
345
		};
346
		return img;
347
	},
348
 
349
	_setIconStyles: function (img, name) {
350
		L.Icon.prototype._setIconStyles.apply(this, [img, name])
351
		// save anchor information to the image
352
		img.anchor = this.options.iconAnchorRef;
353
		img.anchorType = this.options.iconAnchorType;
354
	}
355
});
356
 
357
 
358
L.KMLMarker = L.Marker.extend({
359
	options: {
360
		icon: new L.KMLIcon.Default()
361
	}
362
});
363