[PLUGINS] ~maj gis v4.26.1-->4.26.10
[lhc/web/clavette_www.git] / www / plugins / gis / lib / leaflet / plugins / KML.js
1 L.KML = L.FeatureGroup.extend({
2 options: {
3 async: true
4 },
5
6 initialize: function(kml, options) {
7 L.Util.setOptions(this, options);
8 this._kml = kml;
9 this._layers = {};
10
11 if (kml) {
12 this.addKML(kml, options, this.options.async);
13 }
14 },
15
16 loadXML: function(url, cb, options, async) {
17 if (async === undefined) async = this.options.async;
18 if (options === undefined) options = this.options;
19
20 var req = new window.XMLHttpRequest();
21 req.open('GET', url, async);
22 try {
23 req.overrideMimeType('text/xml'); // unsupported by IE
24 } catch(e) {}
25 req.onreadystatechange = function() {
26 if (req.readyState !== 4) return;
27 if (req.status === 200) cb(req.responseXML, options);
28 };
29 req.send(null);
30 },
31
32 addKML: function(url, options, async) {
33 var _this = this;
34 var cb = function(gpx, options) { _this._addKML(gpx, options); };
35 this.loadXML(url, cb, options, async);
36 },
37
38 _addKML: function(xml, options) {
39 var layers = L.KML.parseKML(xml);
40 if (!layers || !layers.length) return;
41 for (var i = 0; i < layers.length; i++) {
42 this.fire('addlayer', {
43 layer: layers[i]
44 });
45 this.addLayer(layers[i]);
46 }
47 this.latLngs = L.KML.getLatLngs(xml);
48 this.fire('loaded');
49 },
50
51 latLngs: []
52 });
53
54 L.Util.extend(L.KML, {
55
56 parseKML: function (xml) {
57 var style = this.parseStyle(xml);
58 this.parseStyleMap(xml, style);
59 var el = xml.getElementsByTagName('Folder');
60 var layers = [], l;
61 for (var i = 0; i < el.length; i++) {
62 if (!this._check_folder(el[i])) { continue; }
63 l = this.parseFolder(el[i], style);
64 if (l) { layers.push(l); }
65 }
66 el = xml.getElementsByTagName('Placemark');
67 for (var j = 0; j < el.length; j++) {
68 if (!this._check_folder(el[j])) { continue; }
69 l = this.parsePlacemark(el[j], xml, style);
70 if (l) { layers.push(l); }
71 }
72 el = xml.getElementsByTagName('GroundOverlay');
73 for (var k = 0; k < el.length; k++) {
74 l = this.parseGroundOverlay(el[k]);
75 if (l) { layers.push(l); }
76 }
77 return layers;
78 },
79
80 // Return false if e's first parent Folder is not [folder]
81 // - returns true if no parent Folders
82 _check_folder: function (e, folder) {
83 e = e.parentElement;
84 while (e && e.tagName !== 'Folder')
85 {
86 e = e.parentElement;
87 }
88 return !e || e === folder;
89 },
90
91 parseStyle: function (xml) {
92 var style = {};
93 var sl = xml.getElementsByTagName('Style');
94
95 var attributes = { color: true, width: true, Icon: true, href: true, hotSpot: true };
96
97 function _parse(xml) {
98 var options = {};
99 for (var i = 0; i < xml.childNodes.length; i++) {
100 var e = xml.childNodes[i];
101 var key = e.tagName;
102 if (!attributes[key]) { continue; }
103 if (key === 'hotSpot')
104 {
105 for (var j = 0; j < e.attributes.length; j++) {
106 options[e.attributes[j].name] = e.attributes[j].nodeValue;
107 }
108 } else {
109 var value = e.childNodes[0].nodeValue;
110 if (key === 'color') {
111 options.opacity = parseInt(value.substring(0, 2), 16) / 255.0;
112 options.color = '#' + value.substring(6, 8) + value.substring(4, 6) + value.substring(2, 4);
113 } else if (key === 'width') {
114 options.weight = value;
115 } else if (key === 'Icon') {
116 ioptions = _parse(e);
117 if (ioptions.href) { options.href = ioptions.href; }
118 } else if (key === 'href') {
119 options.href = value;
120 }
121 }
122 }
123 return options;
124 }
125
126 for (var i = 0; i < sl.length; i++) {
127 var e = sl[i], el;
128 var options = {}, poptions = {}, ioptions = {};
129 el = e.getElementsByTagName('LineStyle');
130 if (el && el[0]) { options = _parse(el[0]); }
131 el = e.getElementsByTagName('PolyStyle');
132 if (el && el[0]) { poptions = _parse(el[0]); }
133 if (poptions.color) { options.fillColor = poptions.color; }
134 if (poptions.opacity) { options.fillOpacity = poptions.opacity; }
135 el = e.getElementsByTagName('IconStyle');
136 if (el && el[0]) { ioptions = _parse(el[0]); }
137 if (ioptions.href) {
138 // save anchor info until the image is loaded
139 options.icon = new L.KMLIcon({
140 iconUrl: ioptions.href,
141 shadowUrl: null,
142 iconAnchorRef: {x: ioptions.x, y: ioptions.y},
143 iconAnchorType: {x: ioptions.xunits, y: ioptions.yunits}
144 });
145 }
146 style['#' + e.getAttribute('id')] = options;
147 }
148 return style;
149 },
150
151 parseStyleMap: function (xml, existingStyles) {
152 var sl = xml.getElementsByTagName('StyleMap');
153
154 for (var i = 0; i < sl.length; i++) {
155 var e = sl[i], el;
156 var smKey, smStyleUrl;
157
158 el = e.getElementsByTagName('key');
159 if (el && el[0]) { smKey = el[0].textContent; }
160 el = e.getElementsByTagName('styleUrl');
161 if (el && el[0]) { smStyleUrl = el[0].textContent; }
162
163 if (smKey === 'normal')
164 {
165 existingStyles['#' + e.getAttribute('id')] = existingStyles[smStyleUrl];
166 }
167 }
168
169 return;
170 },
171
172 parseFolder: function (xml, style) {
173 var el, layers = [], l;
174 el = xml.getElementsByTagName('Folder');
175 for (var i = 0; i < el.length; i++) {
176 if (!this._check_folder(el[i], xml)) { continue; }
177 l = this.parseFolder(el[i], style);
178 if (l) { layers.push(l); }
179 }
180 el = xml.getElementsByTagName('Placemark');
181 for (var j = 0; j < el.length; j++) {
182 if (!this._check_folder(el[j], xml)) { continue; }
183 l = this.parsePlacemark(el[j], xml, style);
184 if (l) { layers.push(l); }
185 }
186 el = xml.getElementsByTagName('GroundOverlay');
187 for (var k = 0; k < el.length; k++) {
188 if (!this._check_folder(el[k], xml)) { continue; }
189 l = this.parseGroundOverlay(el[k]);
190 if (l) { layers.push(l); }
191 }
192 if (!layers.length) { return; }
193 if (layers.length === 1) { return layers[0]; }
194 return new L.FeatureGroup(layers);
195 },
196
197 parsePlacemark: function (place, xml, style) {
198 var h, i, j, el, options = {};
199
200 var multi = ['MultiGeometry', 'MultiTrack', 'gx:MultiTrack'];
201 for (h in multi) {
202 el = place.getElementsByTagName(multi[h]);
203 for (i = 0; i < el.length; i++) {
204 return this.parsePlacemark(el[i], xml, style);
205 }
206 }
207
208 el = place.getElementsByTagName('styleUrl');
209 for (i = 0; i < el.length; i++) {
210 var url = el[i].childNodes[0].nodeValue;
211 for (var a in style[url]) {
212 options[a] = style[url][a];
213 }
214 }
215 var layers = [];
216
217 var parse = ['LineString', 'Polygon', 'Point', 'Track', 'gx:Track'];
218 for (j in parse) {
219 var tag = parse[j];
220 el = place.getElementsByTagName(tag);
221 for (i = 0; i < el.length; i++) {
222 var l = this['parse' + tag.replace(/gx:/, '')](el[i], xml, options);
223 if (l) { layers.push(l); }
224 }
225 }
226
227 if (!layers.length) {
228 return;
229 }
230 var layer = layers[0];
231 if (layers.length > 1) {
232 layer = new L.FeatureGroup(layers);
233 }
234
235 var name, descr = '';
236 el = place.getElementsByTagName('name');
237 if (el.length && el[0].childNodes.length) {
238 name = el[0].childNodes[0].nodeValue;
239 }
240 el = place.getElementsByTagName('description');
241 for (i = 0; i < el.length; i++) {
242 for (j = 0; j < el[i].childNodes.length; j++) {
243 descr = descr + el[i].childNodes[j].nodeValue;
244 }
245 }
246
247 if (name) {
248 layer.bindPopup('<h2>' + name + '</h2>' + descr);
249 }
250
251 return layer;
252 },
253
254 parseCoords: function (xml) {
255 var el = xml.getElementsByTagName('coordinates');
256 return this._read_coords(el[0]);
257 },
258
259 parseLineString: function (line, xml, options) {
260 var coords = this.parseCoords(line);
261 if (!coords.length) { return; }
262 return new L.Polyline(coords, options);
263 },
264
265 parseTrack: function (line, xml, options) {
266 var el = xml.getElementsByTagName('gx:coord');
267 if (el.length === 0) { el = xml.getElementsByTagName('coord'); }
268 var coords = [];
269 for (var j = 0; j < el.length; j++) {
270 coords = coords.concat(this._read_gxcoords(el[j]));
271 }
272 if (!coords.length) { return; }
273 return new L.Polyline(coords, options);
274 },
275
276 parsePoint: function (line, xml, options) {
277 var el = line.getElementsByTagName('coordinates');
278 if (!el.length) {
279 return;
280 }
281 var ll = el[0].childNodes[0].nodeValue.split(',');
282 return new L.KMLMarker(new L.LatLng(ll[1], ll[0]), options);
283 },
284
285 parsePolygon: function (line, xml, options) {
286 var el, polys = [], inner = [], i, coords;
287 el = line.getElementsByTagName('outerBoundaryIs');
288 for (i = 0; i < el.length; i++) {
289 coords = this.parseCoords(el[i]);
290 if (coords) {
291 polys.push(coords);
292 }
293 }
294 el = line.getElementsByTagName('innerBoundaryIs');
295 for (i = 0; i < el.length; i++) {
296 coords = this.parseCoords(el[i]);
297 if (coords) {
298 inner.push(coords);
299 }
300 }
301 if (!polys.length) {
302 return;
303 }
304 if (options.fillColor) {
305 options.fill = true;
306 }
307 if (polys.length === 1) {
308 return new L.Polygon(polys.concat(inner), options);
309 }
310 return new L.MultiPolygon(polys, options);
311 },
312
313 getLatLngs: function (xml) {
314 var el = xml.getElementsByTagName('coordinates');
315 var coords = [];
316 for (var j = 0; j < el.length; j++) {
317 // text might span many childNodes
318 coords = coords.concat(this._read_coords(el[j]));
319 }
320 return coords;
321 },
322
323 _read_coords: function (el) {
324 var text = '', coords = [], i;
325 for (i = 0; i < el.childNodes.length; i++) {
326 text = text + el.childNodes[i].nodeValue;
327 }
328 text = text.split(/[\s\n]+/);
329 for (i = 0; i < text.length; i++) {
330 var ll = text[i].split(',');
331 if (ll.length < 2) {
332 continue;
333 }
334 coords.push(new L.LatLng(ll[1], ll[0]));
335 }
336 return coords;
337 },
338
339 _read_gxcoords: function (el) {
340 var text = '', coords = [];
341 text = el.firstChild.nodeValue.split(' ');
342 coords.push(new L.LatLng(text[1], text[0]));
343 return coords;
344 },
345
346 parseGroundOverlay: function (xml) {
347 var latlonbox = xml.getElementsByTagName('LatLonBox')[0];
348 var bounds = new L.LatLngBounds(
349 [
350 latlonbox.getElementsByTagName('south')[0].childNodes[0].nodeValue,
351 latlonbox.getElementsByTagName('west')[0].childNodes[0].nodeValue
352 ],
353 [
354 latlonbox.getElementsByTagName('north')[0].childNodes[0].nodeValue,
355 latlonbox.getElementsByTagName('east')[0].childNodes[0].nodeValue
356 ]
357 );
358 var attributes = {Icon: true, href: true, color: true};
359 function _parse(xml) {
360 var options = {}, ioptions = {};
361 for (var i = 0; i < xml.childNodes.length; i++) {
362 var e = xml.childNodes[i];
363 var key = e.tagName;
364 if (!attributes[key]) { continue; }
365 var value = e.childNodes[0].nodeValue;
366 if (key === 'Icon') {
367 ioptions = _parse(e);
368 if (ioptions.href) { options.href = ioptions.href; }
369 } else if (key === 'href') {
370 options.href = value;
371 } else if (key === 'color') {
372 options.opacity = parseInt(value.substring(0, 2), 16) / 255.0;
373 options.color = '#' + value.substring(6, 8) + value.substring(4, 6) + value.substring(2, 4);
374 }
375 }
376 return options;
377 }
378 var options = {};
379 options = _parse(xml);
380 if (latlonbox.getElementsByTagName('rotation')[0] !== undefined) {
381 var rotation = latlonbox.getElementsByTagName('rotation')[0].childNodes[0].nodeValue;
382 options.rotation = parseFloat(rotation);
383 }
384 return new L.RotatedImageOverlay(options.href, bounds, {opacity: options.opacity, angle: options.rotation});
385 }
386
387 });
388
389 L.KMLIcon = L.Icon.extend({
390
391 createIcon: function () {
392 var img = this._createIcon('icon');
393 img.onload = function () {
394 var i = img;
395 this.style.width = i.width + 'px';
396 this.style.height = i.height + 'px';
397
398 if (this.anchorType.x === 'fraction' && this.anchorType.y === 'fraction') {
399 img.style.marginLeft = (-this.anchor.x * i.width) + 'px';
400 img.style.marginTop = (-(1 - this.anchor.y) * i.height) + 'px';
401 }
402 if (this.anchorType.x === 'pixels' && this.anchorType.y === 'pixels') {
403 img.style.marginLeft = (-this.anchor.x) + 'px';
404 img.style.marginTop = (this.anchor.y - i.height + 1) + 'px';
405 }
406 this.style.display = '';
407 };
408 return img;
409 },
410
411 _setIconStyles: function (img, name) {
412 L.Icon.prototype._setIconStyles.apply(this, [img, name]);
413 // save anchor information to the image
414 img.anchor = this.options.iconAnchorRef;
415 img.anchorType = this.options.iconAnchorType;
416 }
417 });
418
419
420 L.KMLMarker = L.Marker.extend({
421 options: {
422 icon: new L.KMLIcon.Default()
423 }
424 });
425
426 // Inspired by https://github.com/bbecquet/Leaflet.PolylineDecorator/tree/master/src
427 L.RotatedImageOverlay = L.ImageOverlay.extend({
428 options: {
429 angle: 0
430 },
431 _reset: function () {
432 L.ImageOverlay.prototype._reset.call(this);
433 this._rotate();
434 },
435 _animateZoom: function (e) {
436 L.ImageOverlay.prototype._animateZoom.call(this, e);
437 this._rotate();
438 },
439 _rotate: function () {
440 if (L.DomUtil.TRANSFORM) {
441 // use the CSS transform rule if available
442 this._image.style[L.DomUtil.TRANSFORM] += ' rotate(' + this.options.angle + 'deg)';
443 } else if(L.Browser.ie) {
444 // fallback for IE6, IE7, IE8
445 var rad = this.options.angle * (Math.PI / 180),
446 costheta = Math.cos(rad),
447 sintheta = Math.sin(rad);
448 this._image.style.filter += ' progid:DXImageTransform.Microsoft.Matrix(sizingMethod=\'auto expand\', M11=' +
449 costheta + ', M12=' + (-sintheta) + ', M21=' + sintheta + ', M22=' + costheta + ')';
450 }
451 },
452 getBounds: function() {
453 return this._bounds;
454 }
455 });
456