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 this.addPlacePopup(place, layer); 229 return layer; 230 } 231 } 232 233 var layers = []; 234 235 var parse = ['LineString', 'Polygon', 'Point', 'Track', 'gx:Track']; 236 for (j in parse) { 237 var tag = parse[j]; 238 el = place.getElementsByTagName(tag); 239 for (i = 0; i < el.length; i++) { 240 var l = this['parse' + tag.replace(/gx:/, '')](el[i], xml, opts); 241 if (l) { layers.push(l); } 242 } 243 } 244 245 if (!layers.length) { 246 return; 247 } 248 var layer = layers[0]; 249 if (layers.length > 1) { 250 layer = new L.FeatureGroup(layers); 251 } 252 253 this.addPlacePopup(place, layer); 254 return layer; 255 }, 256 257 addPlacePopup: function(place, layer) { 258 var el, i, j, name, descr = ''; 259 el = place.getElementsByTagName('name'); 260 if (el.length && el[0].childNodes.length) { 261 name = el[0].childNodes[0].nodeValue; 262 } 263 el = place.getElementsByTagName('description'); 264 for (i = 0; i < el.length; i++) { 265 for (j = 0; j < el[i].childNodes.length; j++) { 266 descr = descr + el[i].childNodes[j].nodeValue; 267 } 268 } 269 270 if (name) { 271 layer.bindPopup('<h2>' + name + '</h2>' + descr, { className: 'kml-popup'}); 272 } 273 }, 274 275 parseCoords: function (xml) { 276 var el = xml.getElementsByTagName('coordinates'); 277 return this._read_coords(el[0]); 278 }, 279 280 parseLineString: function (line, xml, options) { 281 var coords = this.parseCoords(line); 282 if (!coords.length) { return; } 283 return new L.Polyline(coords, options); 284 }, 285 286 parseTrack: function (line, xml, options) { 287 var el = xml.getElementsByTagName('gx:coord'); 288 if (el.length === 0) { el = xml.getElementsByTagName('coord'); } 289 var coords = []; 290 for (var j = 0; j < el.length; j++) { 291 coords = coords.concat(this._read_gxcoords(el[j])); 292 } 293 if (!coords.length) { return; } 294 return new L.Polyline(coords, options); 295 }, 296 297 parsePoint: function (line, xml, options) { 298 var el = line.getElementsByTagName('coordinates'); 299 if (!el.length) { 300 return; 301 } 302 var ll = el[0].childNodes[0].nodeValue.split(','); 303 return new L.KMLMarker(new L.LatLng(ll[1], ll[0]), options); 304 }, 305 306 parsePolygon: function (line, xml, options) { 307 var el, polys = [], inner = [], i, coords; 308 el = line.getElementsByTagName('outerBoundaryIs'); 309 for (i = 0; i < el.length; i++) { 310 coords = this.parseCoords(el[i]); 311 if (coords) { 312 polys.push(coords); 313 } 314 } 315 el = line.getElementsByTagName('innerBoundaryIs'); 316 for (i = 0; i < el.length; i++) { 317 coords = this.parseCoords(el[i]); 318 if (coords) { 319 inner.push(coords); 320 } 321 } 322 if (!polys.length) { 323 return; 324 } 325 if (options.fillColor) { 326 options.fill = true; 327 } 328 if (polys.length === 1) { 329 return new L.Polygon(polys.concat(inner), options); 330 } 331 return new L.MultiPolygon(polys, options); 332 }, 333 334 getLatLngs: function (xml) { 335 var el = xml.getElementsByTagName('coordinates'); 336 var coords = []; 337 for (var j = 0; j < el.length; j++) { 338 // text might span many childNodes 339 coords = coords.concat(this._read_coords(el[j])); 340 } 341 return coords; 342 }, 343 344 _read_coords: function (el) { 345 var text = '', coords = [], i; 346 for (i = 0; i < el.childNodes.length; i++) { 347 text = text + el.childNodes[i].nodeValue; 348 } 349 text = text.split(/[\s\n]+/); 350 for (i = 0; i < text.length; i++) { 351 var ll = text[i].split(','); 352 if (ll.length < 2) { 353 continue; 354 } 355 coords.push(new L.LatLng(ll[1], ll[0])); 356 } 357 return coords; 358 }, 359 360 _read_gxcoords: function (el) { 361 var text = '', coords = []; 362 text = el.firstChild.nodeValue.split(' '); 363 coords.push(new L.LatLng(text[1], text[0])); 364 return coords; 365 }, 366 367 parseGroundOverlay: function (xml) { 368 var latlonbox = xml.getElementsByTagName('LatLonBox')[0]; 369 var bounds = new L.LatLngBounds( 370 [ 371 latlonbox.getElementsByTagName('south')[0].childNodes[0].nodeValue, 372 latlonbox.getElementsByTagName('west')[0].childNodes[0].nodeValue 373 ], 374 [ 375 latlonbox.getElementsByTagName('north')[0].childNodes[0].nodeValue, 376 latlonbox.getElementsByTagName('east')[0].childNodes[0].nodeValue 377 ] 378 ); 379 var attributes = {Icon: true, href: true, color: true}; 380 function _parse (xml) { 381 var options = {}, ioptions = {}; 382 for (var i = 0; i < xml.childNodes.length; i++) { 383 var e = xml.childNodes[i]; 384 var key = e.tagName; 385 if (!attributes[key]) { continue; } 386 var value = e.childNodes[0].nodeValue; 387 if (key === 'Icon') { 388 ioptions = _parse(e); 389 if (ioptions.href) { options.href = ioptions.href; } 390 } else if (key === 'href') { 391 options.href = value; 392 } else if (key === 'color') {
393 options.opacity = parseInt(value.substring(0, 2), 16) / 255.0; 394 options.color = '#' + value.substring(6, 8) + value.substring(4, 6) + value.substring(2, 4); 395 } 396 } 397 return options; 398 } 399 var options = {}; 400 options = _parse(xml); 401 if (latlonbox.getElementsByTagName('rotation')[0] !== undefined) { 402 var rotation = latlonbox.getElementsByTagName('rotation')[0].childNodes[0].nodeValue; 403 options.rotation = parseFloat(rotation); 404 } 405 return new L.RotatedImageOverlay(options.href, bounds, {opacity: options.opacity, angle: options.rotation}); 406 } 407 408}); 409 410L.KMLIcon = L.Icon.extend({ 411 options: { 412 iconSize: [32, 32], 413 iconAnchor: [16, 16], 414 }, 415 _setIconStyles: function (img, name) { 416 L.Icon.prototype._setIconStyles.apply(this, [img, name]); 417 }, 418 _createImg: function (src, el) { 419 el = el || document.createElement('img'); 420 el.onload = this.applyCustomStyles.bind(this,el) 421 el.src = src; 422 return el; 423 }, 424 applyCustomStyles: function(img) { 425 var options = this.options; 426 var width = options.iconSize[0]; 427 var height = options.iconSize[1]; 428 429 this.options.popupAnchor = [0,(-0.83*height)]; 430 if (options.anchorType.x === 'fraction') 431 img.style.marginLeft = (-options.anchorRef.x * width) + 'px'; 432 if (options.anchorType.y === 'fraction') 433 img.style.marginTop = ((-(1 - options.anchorRef.y) * height) + 1) + 'px'; 434 if (options.anchorType.x === 'pixels') 435 img.style.marginLeft = (-options.anchorRef.x) + 'px'; 436 if (options.anchorType.y === 'pixels') 437 img.style.marginTop = (options.anchorRef.y - height + 1) + 'px'; 438 } 439}); 440 441 442L.KMLMarker = L.Marker.extend({ 443 options: { 444 icon: new L.KMLIcon.Default() 445 } 446}); 447 448// Inspired by https://github.com/bbecquet/Leaflet.PolylineDecorator/tree/master/src 449L.RotatedImageOverlay = L.ImageOverlay.extend({ 450 options: { 451 angle: 0 452 }, 453 _reset: function () { 454 L.ImageOverlay.prototype._reset.call(this); 455 this._rotate(); 456 }, 457 _animateZoom: function (e) { 458 L.ImageOverlay.prototype._animateZoom.call(this, e); 459 this._rotate(); 460 }, 461 _rotate: function () { 462 if (L.DomUtil.TRANSFORM) { 463 // use the CSS transform rule if available 464 this._image.style[L.DomUtil.TRANSFORM] += ' rotate(' + this.options.angle + 'deg)'; 465 } else if (L.Browser.ie) { 466 // fallback for IE6, IE7, IE8 467 var rad = this.options.angle * (Math.PI / 180), 468 costheta = Math.cos(rad), 469 sintheta = Math.sin(rad); 470 this._image.style.filter += ' progid:DXImageTransform.Microsoft.Matrix(sizingMethod=\'auto expand\', M11=' + 471 costheta + ', M12=' + (-sintheta) + ', M21=' + sintheta + ', M22=' + costheta + ')'; 472 } 473 }, 474 getBounds: function () { 475 return this._bounds; 476 } 477});
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.