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