/*! Copyright (c) 2011-2015, Pavel Shramov, Bruno Bergot - MIT licence */ L.KML = L.FeatureGroup.extend({ initialize: function (kml, kmlOptions) { this._kml = kml; this._layers = {}; this._kmlOptions = kmlOptions; if (kml) { this.addKML(kml, kmlOptions); } }, addKML: function (xml, kmlOptions) { var layers = L.KML.parseKML(xml, kmlOptions); if (!layers || !layers.length) return; for (var i = 0; i < layers.length; i++) { this.fire('addlayer', { layer: layers[i] }); this.addLayer(layers[i]); } this.latLngs = L.KML.getLatLngs(xml); this.fire('loaded'); }, latLngs: [] }); L.Util.extend(L.KML, { parseKML: function (xml, kmlOptions) { var style = this.parseStyles(xml, kmlOptions); this.parseStyleMap(xml, style); var el = xml.getElementsByTagName('Folder'); var layers = [], l; for (var i = 0; i < el.length; i++) { if (!this._check_folder(el[i])) { continue; } l = this.parseFolder(el[i], style); if (l) { layers.push(l); } } el = xml.getElementsByTagName('Placemark'); for (var j = 0; j < el.length; j++) { if (!this._check_folder(el[j])) { continue; } l = this.parsePlacemark(el[j], xml, style); if (l) { layers.push(l); } } el = xml.getElementsByTagName('GroundOverlay'); for (var k = 0; k < el.length; k++) { l = this.parseGroundOverlay(el[k]); if (l) { layers.push(l); } } return layers; }, // Return false if e's first parent Folder is not [folder] // - returns true if no parent Folders _check_folder: function (e, folder) { e = e.parentNode; while (e && e.tagName !== 'Folder') { e = e.parentNode; } return !e || e === folder; }, parseStyles: function (xml, kmlOptions) { var styles = {}; var sl = xml.getElementsByTagName('Style'); for (var i=0, len=sl.length; i 1) { layer = new L.FeatureGroup(layers); } this.addPlacePopup(place, layer); return layer; }, addPlacePopup: function(place, layer) { var el, i, j, name, descr = ''; el = place.getElementsByTagName('name'); if (el.length && el[0].childNodes.length) { name = el[0].childNodes[0].nodeValue; } el = place.getElementsByTagName('description'); for (i = 0; i < el.length; i++) { for (j = 0; j < el[i].childNodes.length; j++) { descr = descr + el[i].childNodes[j].nodeValue; } } if (name) { layer.bindPopup('

' + name + '

' + descr, { className: 'kml-popup'}); } }, parseCoords: function (xml) { var el = xml.getElementsByTagName('coordinates'); return this._read_coords(el[0]); }, parseLineString: function (line, xml, options) { var coords = this.parseCoords(line); if (!coords.length) { return; } return new L.Polyline(coords, options); }, parseTrack: function (line, xml, options) { var el = xml.getElementsByTagName('gx:coord'); if (el.length === 0) { el = xml.getElementsByTagName('coord'); } var coords = []; for (var j = 0; j < el.length; j++) { coords = coords.concat(this._read_gxcoords(el[j])); } if (!coords.length) { return; } return new L.Polyline(coords, options); }, parsePoint: function (line, xml, options) { var el = line.getElementsByTagName('coordinates'); if (!el.length) { return; } var ll = el[0].childNodes[0].nodeValue.split(','); return new L.KMLMarker(new L.LatLng(ll[1], ll[0]), options); }, parsePolygon: function (line, xml, options) { var el, polys = [], inner = [], i, coords; el = line.getElementsByTagName('outerBoundaryIs'); for (i = 0; i < el.length; i++) { coords = this.parseCoords(el[i]); if (coords) { polys.push(coords); } } el = line.getElementsByTagName('innerBoundaryIs'); for (i = 0; i < el.length; i++) { coords = this.parseCoords(el[i]); if (coords) { inner.push(coords); } } if (!polys.length) { return; } if (options.fillColor) { options.fill = true; } if (polys.length === 1) { return new L.Polygon(polys.concat(inner), options); } return new L.MultiPolygon(polys, options); }, getLatLngs: function (xml) { var el = xml.getElementsByTagName('coordinates'); var coords = []; for (var j = 0; j < el.length; j++) { // text might span many childNodes coords = coords.concat(this._read_coords(el[j])); } return coords; }, _read_coords: function (el) { var text = '', coords = [], i; for (i = 0; i < el.childNodes.length; i++) { text = text + el.childNodes[i].nodeValue; } text = text.split(/[\s\n]+/); for (i = 0; i < text.length; i++) { var ll = text[i].split(','); if (ll.length < 2) { continue; } coords.push(new L.LatLng(ll[1], ll[0])); } return coords; }, _read_gxcoords: function (el) { var text = '', coords = []; text = el.firstChild.nodeValue.split(' '); coords.push(new L.LatLng(text[1], text[0])); return coords; }, parseGroundOverlay: function (xml) { var latlonbox = xml.getElementsByTagName('LatLonBox')[0]; var bounds = new L.LatLngBounds( [ latlonbox.getElementsByTagName('south')[0].childNodes[0].nodeValue, latlonbox.getElementsByTagName('west')[0].childNodes[0].nodeValue ], [ latlonbox.getElementsByTagName('north')[0].childNodes[0].nodeValue, latlonbox.getElementsByTagName('east')[0].childNodes[0].nodeValue ] ); var attributes = {Icon: true, href: true, color: true}; function _parse (xml) { var options = {}, ioptions = {}; for (var i = 0; i < xml.childNodes.length; i++) { var e = xml.childNodes[i]; var key = e.tagName; if (!attributes[key]) { continue; } var value = e.childNodes[0].nodeValue; if (key === 'Icon') { ioptions = _parse(e); if (ioptions.href) { options.href = ioptions.href; } } else if (key === 'href') { options.href = value; } else if (key === 'color') { options.opacity = parseInt(value.substring(0, 2), 16) / 255.0; options.color = '#' + value.substring(6, 8) + value.substring(4, 6) + value.substring(2, 4); } } return options; } var options = {}; options = _parse(xml); if (latlonbox.getElementsByTagName('rotation')[0] !== undefined) { var rotation = latlonbox.getElementsByTagName('rotation')[0].childNodes[0].nodeValue; options.rotation = parseFloat(rotation); } return new L.RotatedImageOverlay(options.href, bounds, {opacity: options.opacity, angle: options.rotation}); } }); L.KMLIcon = L.Icon.extend({ options: { iconSize: [32, 32], iconAnchor: [16, 16], }, _setIconStyles: function (img, name) { L.Icon.prototype._setIconStyles.apply(this, [img, name]); }, _createImg: function (src, el) { el = el || document.createElement('img'); el.onload = this.applyCustomStyles.bind(this,el) el.src = src; return el; }, applyCustomStyles: function(img) { var options = this.options; var width = options.iconSize[0]; var height = options.iconSize[1]; this.options.popupAnchor = [0,(-0.83*height)]; if (options.anchorType.x === 'fraction') img.style.marginLeft = (-options.anchorRef.x * width) + 'px'; if (options.anchorType.y === 'fraction') img.style.marginTop = ((-(1 - options.anchorRef.y) * height) + 1) + 'px'; if (options.anchorType.x === 'pixels') img.style.marginLeft = (-options.anchorRef.x) + 'px'; if (options.anchorType.y === 'pixels') img.style.marginTop = (options.anchorRef.y - height + 1) + 'px'; } }); L.KMLMarker = L.Marker.extend({ options: { icon: new L.KMLIcon.Default() } }); // Inspired by https://github.com/bbecquet/Leaflet.PolylineDecorator/tree/master/src L.RotatedImageOverlay = L.ImageOverlay.extend({ options: { angle: 0 }, _reset: function () { L.ImageOverlay.prototype._reset.call(this); this._rotate(); }, _animateZoom: function (e) { L.ImageOverlay.prototype._animateZoom.call(this, e); this._rotate(); }, _rotate: function () { if (L.DomUtil.TRANSFORM) { // use the CSS transform rule if available this._image.style[L.DomUtil.TRANSFORM] += ' rotate(' + this.options.angle + 'deg)'; } else if (L.Browser.ie) { // fallback for IE6, IE7, IE8 var rad = this.options.angle * (Math.PI / 180), costheta = Math.cos(rad), sintheta = Math.sin(rad); this._image.style.filter += ' progid:DXImageTransform.Microsoft.Matrix(sizingMethod=\'auto expand\', M11=' + costheta + ', M12=' + (-sintheta) + ', M21=' + sintheta + ', M22=' + costheta + ')'; } }, getBounds: function () { return this._bounds; } });