Rev 28 | Go to most recent revision | View as "text/plain" | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*** Copyright (c) 2011-2012, Pavel Shramov* All rights reserved.** Redistribution and use in source and binary forms, with or without modification, are* permitted provided that the following conditions are met:** 1. Redistributions of source code must retain the above copyright notice, this list of* conditions and the following disclaimer.** 2. Redistributions in binary form must reproduce the above copyright notice, this list* of conditions and the following disclaimer in the documentation and/or other materials* provided with the distribution.** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.**/// Adaptation Alexandre GALIBERT :// - Define fill opacity for polygons at 0 for transparent rendering// - Disable creation of icons for KML elements// - Specific beahaviour to add an array of files by their urls. A variable will define// the status of the processing (BUSY or READY) and managed with a counter for the number// of files remaining to parse. Once all files parsed, the map zooms on KML spatial elementsconst KML_READY = 0;const KML_BUSY = 1;L.KML = L.FeatureGroup.extend({options: {async: true},initialize: function(kml, options) {L.Util.setOptions(this, options);this._kml = kml;this._status = KML_READY;this._onWaiting = 0;this._layers = {};if (kml) {this.addKML(kml, options, this.options.async);}},loadXML: function(url, cb, options, async) {if (async == undefined) async = this.options.async;if (options == undefined) options = this.options;var req = new window.XMLHttpRequest();req.open('GET', url, async);try {req.overrideMimeType('text/xml'); // unsupported by IE} catch(e) {}req.onreadystatechange = function() {if (req.readyState != 4) return;if(req.status == 200) cb(req.responseXML, options);};req.send(null);},addKMLFiles: function(urlList, options, async) {this._status = KML_BUSY;this._onWaiting = urlList.length;for (var index = 0; index < urlList.length; index ++) {this.addKML(urlList[index], options, async);}},addKML: function(url, options, async) {var _this = this;var cb = function(gpx, options) { _this._addKML(gpx, options) };this.loadXML(url, cb, options, async);},_addKML: function(xml, options) {var layers = L.KML.parseKML(xml);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");this._onWaiting --;if (this._onWaiting == 0) {this._status = KML_READY;this._map.fitBounds(this.getBounds());}},getStatus: function() {return this._status;},latLngs: []});L.Util.extend(L.KML, {parseKML: function (xml) {var style = this.parseStyle(xml);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); }}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.parentElement;while (e && e.tagName !== "Folder"){e = e.parentElement;}return !e || e === folder;},parseStyle: function (xml) {var style = {};var sl = xml.getElementsByTagName("Style");//for (var i = 0; i < sl.length; i++) {var attributes = {color: true, width: true, Icon: true, href: true,hotSpot: true};function _parse(xml) {var options = {};for (var i = 0; i < xml.childNodes.length; i++) {var e = xml.childNodes[i];var key = e.tagName;if (!attributes[key]) { continue; }if (key === 'hotSpot'){for (var j = 0; j < e.attributes.length; j++) {options[e.attributes[j].name] = e.attributes[j].nodeValue;}} else {var value = e.childNodes[0].nodeValue;if (key === 'color') {options.opacity = parseInt(value.substring(0, 2), 16) / 255.0;options.color = "#" + value.substring(2, 8);} else if (key === 'width') {options.weight = value;} /*else if (key === 'Icon') {ioptions = _parse(e);if (ioptions.href) { options.href = ioptions.href; }}*/ else if (key === 'href') {options.href = value;}}}options.fillOpacity = 0;return options;}for (var i = 0; i < sl.length; i++) {var e = sl[i], el;var options = {}, poptions = {}, ioptions = {};el = e.getElementsByTagName("LineStyle");if (el && el[0]) { options = _parse(el[0]); }el = e.getElementsByTagName("PolyStyle");if (el && el[0]) { poptions = _parse(el[0]); }if (poptions.color) { options.fillColor = poptions.color; }if (poptions.opacity) { options.fillOpacity = poptions.opacity; }el = e.getElementsByTagName("IconStyle");if (el && el[0]) { ioptions = _parse(el[0]); }if (ioptions.href) {// save anchor info until the image is loadedoptions.icon = new L.KMLIcon({iconUrl: ioptions.href,shadowUrl: null,iconAnchorRef: {x: ioptions.x, y: ioptions.y},iconAnchorType: {x: ioptions.xunits, y: ioptions.yunits}});}style['#' + e.getAttribute('id')] = options;}return style;},parseFolder: function (xml, style) {var el, layers = [], l;el = xml.getElementsByTagName('Folder');for (var i = 0; i < el.length; i++) {if (!this._check_folder(el[i], xml)) { 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], xml)) { continue; }l = this.parsePlacemark(el[j], xml, style);if (l) { layers.push(l); }}if (!layers.length) { return; }if (layers.length === 1) { return layers[0]; }return new L.FeatureGroup(layers);},parsePlacemark: function (place, xml, style) {var i, j, el, options = {};el = place.getElementsByTagName('styleUrl');for (i = 0; i < el.length; i++) {var url = el[i].childNodes[0].nodeValue;for (var a in style[url]){// for jshintif (true){options[a] = style[url][a];}}}var layers = [];var parse = ['LineString', 'Polygon', 'Point'];for (j in parse) {// for jshintif (true){var tag = parse[j];el = place.getElementsByTagName(tag);for (i = 0; i < el.length; i++) {var l = this["parse" + tag](el[i], xml, options);if (l) { layers.push(l); }}}}if (!layers.length) {return;}var layer = layers[0];if (layers.length > 1) {layer = new L.FeatureGroup(layers);}var name, descr = "";el = place.getElementsByTagName('name');if (el.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("<h2>" + name + "</h2>" + descr);}return layer;},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);},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 childnodescoords = 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;}});L.KMLIcon = L.Icon.extend({createIcon: function () {var img = this._createIcon('icon');img.onload = function () {var i = new Image();i.src = this.src;this.style.width = i.width + 'px';this.style.height = i.height + 'px';if (this.anchorType.x === 'UNITS_FRACTION' || this.anchorType.x === 'fraction') {img.style.marginLeft = (-this.anchor.x * i.width) + 'px';}if (this.anchorType.y === 'UNITS_FRACTION' || this.anchorType.x === 'fraction') {img.style.marginTop = (-(1 - this.anchor.y) * i.height) + 'px';}this.style.display = "";};return img;},_setIconStyles: function (img, name) {L.Icon.prototype._setIconStyles.apply(this, [img, name])// save anchor information to the imageimg.anchor = this.options.iconAnchorRef;img.anchorType = this.options.iconAnchorType;}});L.KMLMarker = L.Marker.extend({options: {icon: new L.KMLIcon.Default()}});