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