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