├── CHANGELOG.md ├── L.KML.js ├── README.md ├── assets ├── example1.kml ├── example2.kml └── screenshot.jpg └── package.json /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### 1.1.0 2 | 3 | - Fixed markers wrong locations for already loaded icons 4 | - Fixed #7 (Featured parsed inside MultiGeometry elements don't bind the correct placemark popup information) 5 | - Fixed #9 (Image assets larger than 'iconSize' offset pop-up windows incorrectly when loaded from a warm cache) 6 | - Fixed #14 (Disappearing polygons) 7 | 8 | ### 1.0.1 9 | 10 | - Updated README 11 | 12 | ### 1.0.0 13 | 14 | - Initial commit, original version with few fixes 15 | -------------------------------------------------------------------------------- /L.KML.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Copyright (c) 2011-2015, Pavel Shramov, Bruno Bergot - MIT licence 3 | */ 4 | 5 | L.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 | 33 | L.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 1) { 255 | layer = new L.FeatureGroup(layers); 256 | } 257 | 258 | this.addPlacePopup(place, layer); 259 | return layer; 260 | }, 261 | 262 | addPlacePopup: function(place, layer) { 263 | var el, i, j, name, descr = ''; 264 | el = place.getElementsByTagName('name'); 265 | if (el.length && el[0].childNodes.length) { 266 | name = el[0].childNodes[0].nodeValue; 267 | } 268 | el = place.getElementsByTagName('description'); 269 | for (i = 0; i < el.length; i++) { 270 | for (j = 0; j < el[i].childNodes.length; j++) { 271 | descr = descr + el[i].childNodes[j].nodeValue; 272 | } 273 | } 274 | 275 | if (name) { 276 | layer.bindPopup('

' + name + '

' + descr, { className: 'kml-popup'}); 277 | } 278 | }, 279 | 280 | parseCoords: function (xml) { 281 | var el = xml.getElementsByTagName('coordinates'); 282 | return this._read_coords(el[0]); 283 | }, 284 | 285 | parseLineString: function (line, xml, options) { 286 | var coords = this.parseCoords(line); 287 | if (!coords.length) { return; } 288 | return new L.Polyline(coords, options); 289 | }, 290 | 291 | parseTrack: function (line, xml, options) { 292 | var el = xml.getElementsByTagName('gx:coord'); 293 | if (el.length === 0) { el = xml.getElementsByTagName('coord'); } 294 | var coords = []; 295 | for (var j = 0; j < el.length; j++) { 296 | coords = coords.concat(this._read_gxcoords(el[j])); 297 | } 298 | if (!coords.length) { return; } 299 | return new L.Polyline(coords, options); 300 | }, 301 | 302 | parsePoint: function (line, xml, options) { 303 | var el = line.getElementsByTagName('coordinates'); 304 | if (!el.length) { 305 | return; 306 | } 307 | var ll = el[0].childNodes[0].nodeValue.split(','); 308 | return new L.KMLMarker(new L.LatLng(ll[1], ll[0]), options); 309 | }, 310 | 311 | parsePolygon: function (line, xml, options) { 312 | var el, polys = [], inner = [], i, coords; 313 | el = line.getElementsByTagName('outerBoundaryIs'); 314 | for (i = 0; i < el.length; i++) { 315 | coords = this.parseCoords(el[i]); 316 | if (coords) { 317 | polys.push(coords); 318 | } 319 | } 320 | el = line.getElementsByTagName('innerBoundaryIs'); 321 | for (i = 0; i < el.length; i++) { 322 | coords = this.parseCoords(el[i]); 323 | if (coords) { 324 | inner.push(coords); 325 | } 326 | } 327 | if (!polys.length) { 328 | return; 329 | } 330 | if (options.fillColor) { 331 | options.fill = true; 332 | } 333 | if (polys.length === 1) { 334 | return new L.Polygon(polys.concat(inner), options); 335 | } 336 | return new L.MultiPolygon(polys, options); 337 | }, 338 | 339 | getLatLngs: function (xml) { 340 | var el = xml.getElementsByTagName('coordinates'); 341 | var coords = []; 342 | for (var j = 0; j < el.length; j++) { 343 | // text might span many childNodes 344 | coords = coords.concat(this._read_coords(el[j])); 345 | } 346 | return coords; 347 | }, 348 | 349 | _read_coords: function (el) { 350 | var text = '', coords = [], i; 351 | for (i = 0; i < el.childNodes.length; i++) { 352 | text = text + el.childNodes[i].nodeValue; 353 | } 354 | text = text.split(/[\s\n]+/); 355 | for (i = 0; i < text.length; i++) { 356 | var ll = text[i].split(','); 357 | if (ll.length < 2) { 358 | continue; 359 | } 360 | coords.push(new L.LatLng(ll[1], ll[0])); 361 | } 362 | return coords; 363 | }, 364 | 365 | _read_gxcoords: function (el) { 366 | var text = '', coords = []; 367 | text = el.firstChild.nodeValue.split(' '); 368 | coords.push(new L.LatLng(text[1], text[0])); 369 | return coords; 370 | }, 371 | 372 | parseGroundOverlay: function (xml) { 373 | var latlonbox = xml.getElementsByTagName('LatLonBox')[0]; 374 | var bounds = new L.LatLngBounds( 375 | [ 376 | latlonbox.getElementsByTagName('south')[0].childNodes[0].nodeValue, 377 | latlonbox.getElementsByTagName('west')[0].childNodes[0].nodeValue 378 | ], 379 | [ 380 | latlonbox.getElementsByTagName('north')[0].childNodes[0].nodeValue, 381 | latlonbox.getElementsByTagName('east')[0].childNodes[0].nodeValue 382 | ] 383 | ); 384 | var attributes = {Icon: true, href: true, color: true}; 385 | function _parse (xml) { 386 | var options = {}, ioptions = {}; 387 | for (var i = 0; i < xml.childNodes.length; i++) { 388 | var e = xml.childNodes[i]; 389 | var key = e.tagName; 390 | if (!attributes[key]) { continue; } 391 | var value = e.childNodes[0].nodeValue; 392 | if (key === 'Icon') { 393 | ioptions = _parse(e); 394 | if (ioptions.href) { options.href = ioptions.href; } 395 | } else if (key === 'href') { 396 | options.href = value; 397 | } else if (key === 'color') { 398 | options.opacity = parseInt(value.substring(0, 2), 16) / 255.0; 399 | options.color = '#' + value.substring(6, 8) + value.substring(4, 6) + value.substring(2, 4); 400 | } 401 | } 402 | return options; 403 | } 404 | var options = {}; 405 | options = _parse(xml); 406 | if (latlonbox.getElementsByTagName('rotation')[0] !== undefined) { 407 | var rotation = latlonbox.getElementsByTagName('rotation')[0].childNodes[0].nodeValue; 408 | options.rotation = parseFloat(rotation); 409 | } 410 | return new L.RotatedImageOverlay(options.href, bounds, {opacity: options.opacity, angle: options.rotation}); 411 | } 412 | 413 | }); 414 | 415 | L.KMLIcon = L.Icon.extend({ 416 | options: { 417 | iconSize: [32, 32], 418 | iconAnchor: [16, 16], 419 | }, 420 | _setIconStyles: function (img, name) { 421 | L.Icon.prototype._setIconStyles.apply(this, [img, name]); 422 | }, 423 | _createImg: function (src, el) { 424 | el = el || document.createElement('img'); 425 | el.onload = this.applyCustomStyles.bind(this,el) 426 | el.src = src; 427 | return el; 428 | }, 429 | applyCustomStyles: function(img) { 430 | var options = this.options; 431 | var width = options.iconSize[0]; 432 | var height = options.iconSize[1]; 433 | 434 | this.options.popupAnchor = [0,(-0.83*height)]; 435 | if (options.anchorType.x === 'fraction') 436 | img.style.marginLeft = (-options.anchorRef.x * width) + 'px'; 437 | if (options.anchorType.y === 'fraction') 438 | img.style.marginTop = ((-(1 - options.anchorRef.y) * height) + 1) + 'px'; 439 | if (options.anchorType.x === 'pixels') 440 | img.style.marginLeft = (-options.anchorRef.x) + 'px'; 441 | if (options.anchorType.y === 'pixels') 442 | img.style.marginTop = (options.anchorRef.y - height + 1) + 'px'; 443 | } 444 | }); 445 | 446 | 447 | L.KMLMarker = L.Marker.extend({ 448 | options: { 449 | icon: new L.KMLIcon.Default() 450 | } 451 | }); 452 | 453 | // Inspired by https://github.com/bbecquet/Leaflet.PolylineDecorator/tree/master/src 454 | L.RotatedImageOverlay = L.ImageOverlay.extend({ 455 | options: { 456 | angle: 0 457 | }, 458 | _reset: function () { 459 | L.ImageOverlay.prototype._reset.call(this); 460 | this._rotate(); 461 | }, 462 | _animateZoom: function (e) { 463 | L.ImageOverlay.prototype._animateZoom.call(this, e); 464 | this._rotate(); 465 | }, 466 | _rotate: function () { 467 | if (L.DomUtil.TRANSFORM) { 468 | // use the CSS transform rule if available 469 | this._image.style[L.DomUtil.TRANSFORM] += ' rotate(' + this.options.angle + 'deg)'; 470 | } else if (L.Browser.ie) { 471 | // fallback for IE6, IE7, IE8 472 | var rad = this.options.angle * (Math.PI / 180), 473 | costheta = Math.cos(rad), 474 | sintheta = Math.sin(rad); 475 | this._image.style.filter += ' progid:DXImageTransform.Microsoft.Matrix(sizingMethod=\'auto expand\', M11=' + 476 | costheta + ', M12=' + (-sintheta) + ', M21=' + sintheta + ', M22=' + costheta + ')'; 477 | } 478 | }, 479 | getBounds: function () { 480 | return this._bounds; 481 | } 482 | }); 483 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Leaflet KML layer plugin 2 | 3 | ![Example](assets/screenshot.jpg) 4 | 5 | Demo: https://www.windy.com/uploader 6 | 7 | This plugin was extracted from Pavel Shramov's Leaflet Plugins [repository](https://github.com/shramov/leaflet-plugins) in order to maintain this code more frequently and separate KML layer from other plugins. 8 | 9 | So far we have fixed few issues. 10 | 11 | Probably will work on Leaflet 1+, tested on Leaflet 1.4. 12 | 13 | ## How to use 14 | 15 | ```html 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 46 | 47 | 48 | 49 | ``` 50 | 51 | ## Licence 52 | 53 | MIT 54 | -------------------------------------------------------------------------------- /assets/example1.kml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | KML Samples 5 | 1 6 | Unleash your creativity with the help of these examples! 7 | 14 | 24 | 33 | 42 | 48 | 56 | 64 | 72 | 80 | 88 | 96 | 105 | 106 | Placemarks 107 | These are just some of the different kinds of placemarks with 108 | which you can mark your favorite places 109 | 110 | -122.0839597145766 111 | 37.42222904525232 112 | 0 113 | -148.4122922628044 114 | 40.5575073395506 115 | 500.6566641072245 116 | 117 | 118 | Simple placemark 119 | Attached to the ground. Intelligently places itself at the 120 | height of the underlying terrain. 121 | 122 | -122.0822035425683,37.42228990140251,0 123 | 124 | 125 | 126 | Floating placemark 127 | 0 128 | Floats a defined distance above the ground. 129 | 130 | -122.0839597145766 131 | 37.42222904525232 132 | 0 133 | -148.4122922628044 134 | 40.5575073395506 135 | 500.6566641072245 136 | 137 | #downArrowIcon 138 | 139 | relativeToGround 140 | -122.084075,37.4220033612141,50 141 | 142 | 143 | 144 | Extruded placemark 145 | 0 146 | Tethered to the ground by a customizable 147 | "tail" 148 | 149 | -122.0845787421525 150 | 37.42215078737763 151 | 0 152 | -148.4126684946234 153 | 40.55750733918048 154 | 365.2646606980322 155 | 156 | #globeIcon 157 | 158 | 1 159 | relativeToGround 160 | -122.0857667006183,37.42156927867553,50 161 | 162 | 163 | 164 | 165 | Styles and Markup 166 | 0 167 | With KML it is easy to create rich, descriptive markup to 168 | annotate and enrich your placemarks 169 | 170 | -122.0845787422371 171 | 37.42215078726837 172 | 0 173 | -148.4126777488172 174 | 40.55750733930874 175 | 365.2646826292919 176 | 177 | #noDrivingDirections 178 | 179 | Highlighted Icon 180 | 0 181 | Place your mouse over the icon to see it display the new 182 | icon 183 | 184 | -122.0856552124024 185 | 37.4224281311035 186 | 0 187 | 0 188 | 0 189 | 265.8520424250024 190 | 191 | 198 | 205 | 206 | 207 | normal 208 | #normalPlacemark 209 | 210 | 211 | highlight 212 | #highlightPlacemark 213 | 214 | 215 | 216 | Roll over this icon 217 | 0 218 | #exampleStyleMap 219 | 220 | -122.0856545755255,37.42243077405461,0 221 | 222 | 223 | 224 | 225 | Descriptive HTML 226 | 0 227 |
228 | Placemark descriptions can be enriched by using many standard HTML tags.
229 | For example: 230 |
231 | Styles:
232 | Italics, 233 | Bold, 234 | Underlined, 235 | Strike Out, 236 | subscriptsubscript, 237 | superscriptsuperscript, 238 | Big, 239 | Small, 240 | Typewriter, 241 | Emphasized, 242 | Strong, 243 | Code 244 |
245 | Fonts:
246 | red by name, 247 | leaf green by hexadecimal RGB 248 |
249 | size 1, 250 | size 2, 251 | size 3, 252 | size 4, 253 | size 5, 254 | size 6, 255 | size 7 256 |
257 | Times, 258 | Verdana, 259 | Arial
260 |
261 | Links: 262 |
263 | Google Earth! 264 |
265 | or: Check out our website at www.google.com 266 |
267 | Alignment:
268 |

left

269 |

center

270 |

right

271 |
272 | Ordered Lists:
273 |
  1. First
  2. Second
  3. Third
274 |
  1. First
  2. Second
  3. Third
275 |
  1. First
  2. Second
  3. Third
276 |
277 | Unordered Lists:
278 |
  • A
  • B
  • C
279 |
  • A
  • B
  • C
280 |
  • A
  • B
  • C
281 |
282 | Definitions:
283 |
284 |
Google:
The best thing since sliced bread
285 |
286 |
287 | Centered:
288 | Time present and time past
289 | Are both perhaps present in time future,
290 | And time future contained in time past.
291 | If all time is eternally present
292 | All time is unredeemable.
293 |
294 |
295 | Block Quote: 296 |
297 |
298 | We shall not cease from exploration
299 | And the end of all our exploring
300 | Will be to arrive where we started
301 | And know the place for the first time.
302 | -- T.S. Eliot 303 |
304 |
305 |
306 | Headings:
307 |

Header 1

308 |

Header 2

309 |

Header 3

310 |

Header 4

311 |

Header 5

312 |
313 | Images:
314 | Remote image
315 |
316 | Scaled image
317 |
318 |
319 | Simple Tables:
320 | 321 | 322 | 323 |
12345
abcde
324 |
325 | [Did you notice that double-clicking on the placemark doesn't cause the viewer to take you anywhere? This is because it is possible to directly author a "placeless placemark". If you look at the code for this example, you will see that it has neither a point coordinate nor a LookAt element.]]]>
326 |
327 |
328 | 329 | Ground Overlays 330 | 0 331 | Examples of ground overlays 332 | 333 | Large-scale overlay on terrain 334 | 0 335 | Overlay shows Mount Etna erupting on July 13th, 2001. 336 | 337 | 15.02468937557116 338 | 37.67395167941667 339 | 0 340 | -16.5581842842829 341 | 58.31228652890705 342 | 30350.36838438907 343 | 344 | 345 | http://developers.google.com/kml/documentation/images/etna.jpg 346 | 347 | 348 | 37.91904192681665 349 | 37.46543388598137 350 | 15.35832653742206 351 | 14.60128369746704 352 | -0.1556640799496235 353 | 354 | 355 | 356 | 357 | Screen Overlays 358 | 0 359 | Screen overlays have to be authored directly in KML. These 360 | examples illustrate absolute and dynamic positioning in screen space. 361 | 362 | Simple crosshairs 363 | 0 364 | This screen overlay uses fractional positioning to put the 365 | image in the exact center of the screen 366 | 367 | http://developers.google.com/kml/documentation/images/crosshairs.png 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | Absolute Positioning: Top left 376 | 0 377 | 378 | http://developers.google.com/kml/documentation/images/top_left.jpg 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | Absolute Positioning: Top right 387 | 0 388 | 389 | http://developers.google.com/kml/documentation/images/top_right.jpg 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | Absolute Positioning: Bottom left 398 | 0 399 | 400 | http://developers.google.com/kml/documentation/images/bottom_left.jpg 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | Absolute Positioning: Bottom right 409 | 0 410 | 411 | http://developers.google.com/kml/documentation/images/bottom_right.jpg 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | Dynamic Positioning: Top of screen 420 | 0 421 | 422 | http://developers.google.com/kml/documentation/images/dynamic_screenoverlay.jpg 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | Dynamic Positioning: Right of screen 431 | 0 432 | 433 | http://developers.google.com/kml/documentation/images/dynamic_right.jpg 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | Paths 443 | 0 444 | Examples of paths. Note that the tessellate tag is by default 445 | set to 0. If you want to create tessellated lines, they must be authored 446 | (or edited) directly in KML. 447 | 448 | Tessellated 449 | 0 450 | tag has a value of 1, the line will contour to the underlying terrain]]> 451 | 452 | -112.0822680013139 453 | 36.09825589333556 454 | 0 455 | 103.8120432044965 456 | 62.04855796276328 457 | 2889.145007690472 458 | 459 | 460 | 1 461 | -112.0814237830345,36.10677870477137,0 462 | -112.0870267752693,36.0905099328766,0 463 | 464 | 465 | 466 | Untessellated 467 | 0 468 | tag has a value of 0, the line follow a simple straight-line path from point to point]]> 469 | 470 | -112.0822680013139 471 | 36.09825589333556 472 | 0 473 | 103.8120432044965 474 | 62.04855796276328 475 | 2889.145007690472 476 | 477 | 478 | 0 479 | -112.080622229595,36.10673460007995,0 480 | -112.085242575315,36.09049598612422,0 481 | 482 | 483 | 484 | Absolute 485 | 0 486 | Transparent purple line 487 | 488 | -112.2719329043177 489 | 36.08890633450894 490 | 0 491 | -106.8161545998597 492 | 44.60763714063257 493 | 2569.386744398339 494 | 495 | #transPurpleLineGreenPoly 496 | 497 | 1 498 | absolute 499 | -112.265654928602,36.09447672602546,2357 500 | -112.2660384528238,36.09342608838671,2357 501 | -112.2668139013453,36.09251058776881,2357 502 | -112.2677826834445,36.09189827357996,2357 503 | -112.2688557510952,36.0913137941187,2357 504 | -112.2694810717219,36.0903677207521,2357 505 | -112.2695268555611,36.08932171487285,2357 506 | -112.2690144567276,36.08850916060472,2357 507 | -112.2681528815339,36.08753813597956,2357 508 | -112.2670588176031,36.08682685262568,2357 509 | -112.2657374587321,36.08646312301303,2357 510 | 511 | 512 | 513 | Absolute Extruded 514 | 0 515 | Transparent green wall with yellow outlines 516 | 517 | -112.2643334742529 518 | 36.08563154742419 519 | 0 520 | -125.7518698668815 521 | 44.61038665812578 522 | 4451.842204068102 523 | 524 | #yellowLineGreenPoly 525 | 526 | 1 527 | 1 528 | absolute 529 | -112.2550785337791,36.07954952145647,2357 530 | -112.2549277039738,36.08117083492122,2357 531 | -112.2552505069063,36.08260761307279,2357 532 | -112.2564540158376,36.08395660588506,2357 533 | -112.2580238976449,36.08511401044813,2357 534 | -112.2595218489022,36.08584355239394,2357 535 | -112.2608216347552,36.08612634548589,2357 536 | -112.262073428656,36.08626019085147,2357 537 | -112.2633204928495,36.08621519860091,2357 538 | -112.2644963846444,36.08627897945274,2357 539 | -112.2656969554589,36.08649599090644,2357 540 | 541 | 542 | 543 | Relative 544 | 0 545 | Black line (10 pixels wide), height tracks terrain 546 | 547 | -112.2580438551384 548 | 36.1072674824385 549 | 0 550 | 4.947421249553717 551 | 44.61324882043339 552 | 2927.61105910266 553 | 554 | #thickBlackLine 555 | 556 | 1 557 | relativeToGround 558 | -112.2532845153347,36.09886943729116,645 559 | -112.2540466121145,36.09919570465255,645 560 | -112.254734666947,36.09984998366178,645 561 | -112.255493345654,36.10051310621746,645 562 | -112.2563157098468,36.10108441943419,645 563 | -112.2568033076439,36.10159722088088,645 564 | -112.257494011321,36.10204323542867,645 565 | -112.2584106072308,36.10229131995655,645 566 | -112.2596588987972,36.10240001286358,645 567 | -112.2610581199487,36.10213176873407,645 568 | -112.2626285262793,36.10157011437219,645 569 | 570 | 571 | 572 | Relative Extruded 573 | 0 574 | Opaque blue walls with red outline, height tracks terrain 575 | 576 | -112.2683594333433 577 | 36.09884362144909 578 | 0 579 | -72.24271551768405 580 | 44.60855445139561 581 | 2184.193522571467 582 | 583 | #redLineBluePoly 584 | 585 | 1 586 | 1 587 | relativeToGround 588 | -112.2656634181359,36.09445214722695,630 589 | -112.2652238941097,36.09520916122063,630 590 | -112.2645079986395,36.09580763864907,630 591 | -112.2638827428817,36.09628572284063,630 592 | -112.2635746835406,36.09679275951239,630 593 | -112.2635711822407,36.09740038871899,630 594 | -112.2640296531825,36.09804913435539,630 595 | -112.264327720538,36.09880337400301,630 596 | -112.2642436562271,36.09963644790288,630 597 | -112.2639148687042,36.10055381117246,630 598 | -112.2626894973474,36.10149062823369,630 599 | 600 | 601 | 602 | 603 | Polygons 604 | 0 605 | Examples of polygon shapes 606 | 607 | Google Campus 608 | 0 609 | A collection showing how easy it is to create 3-dimensional 610 | buildings 611 | 612 | -122.084120030116 613 | 37.42174011925477 614 | 0 615 | -34.82469740081282 616 | 53.454348562403 617 | 276.7870053764046 618 | 619 | 620 | Building 40 621 | 0 622 | #transRedPoly 623 | 624 | 1 625 | relativeToGround 626 | 627 | 628 | -122.0848938459612,37.42257124044786,17 629 | -122.0849580979198,37.42211922626856,17 630 | -122.0847469573047,37.42207183952619,17 631 | -122.0845725380962,37.42209006729676,17 632 | -122.0845954886723,37.42215932700895,17 633 | -122.0838521118269,37.42227278564371,17 634 | -122.083792243335,37.42203539112084,17 635 | -122.0835076656616,37.42209006957106,17 636 | -122.0834709464152,37.42200987395161,17 637 | -122.0831221085748,37.4221046494946,17 638 | -122.0829247374572,37.42226503990386,17 639 | -122.0829339169385,37.42231242843094,17 640 | -122.0833837359737,37.42225046087618,17 641 | -122.0833607854248,37.42234159228745,17 642 | -122.0834204551642,37.42237075460644,17 643 | -122.083659133885,37.42251292011001,17 644 | -122.0839758438952,37.42265873093781,17 645 | -122.0842374743331,37.42265143972521,17 646 | -122.0845036949503,37.4226514386435,17 647 | -122.0848020460801,37.42261133916315,17 648 | -122.0847882750515,37.42256395055121,17 649 | -122.0848938459612,37.42257124044786,17 650 | 651 | 652 | 653 | 654 | 655 | Building 41 656 | 0 657 | #transBluePoly 658 | 659 | 1 660 | relativeToGround 661 | 662 | 663 | -122.0857412771483,37.42227033155257,17 664 | -122.0858169768481,37.42231408832346,17 665 | -122.085852582875,37.42230337469744,17 666 | -122.0858799945639,37.42225686138789,17 667 | -122.0858860101409,37.4222311076138,17 668 | -122.0858069157288,37.42220250173855,17 669 | -122.0858379542653,37.42214027058678,17 670 | -122.0856732640519,37.42208690214408,17 671 | -122.0856022926407,37.42214885429042,17 672 | -122.0855902778436,37.422128290487,17 673 | -122.0855841672237,37.42208171967246,17 674 | -122.0854852065741,37.42210455874995,17 675 | -122.0855067264352,37.42214267949824,17 676 | -122.0854430712915,37.42212783846172,17 677 | -122.0850990714904,37.42251282407603,17 678 | -122.0856769818632,37.42281815323651,17 679 | -122.0860162273783,37.42244918858722,17 680 | -122.0857260327004,37.42229239604253,17 681 | -122.0857412771483,37.42227033155257,17 682 | 683 | 684 | 685 | 686 | 687 | Building 42 688 | 0 689 | #transGreenPoly 690 | 691 | 1 692 | relativeToGround 693 | 694 | 695 | -122.0857862287242,37.42136208886969,25 696 | -122.0857312990603,37.42136935989481,25 697 | -122.0857312992918,37.42140934910903,25 698 | -122.0856077073679,37.42138390166565,25 699 | -122.0855802426516,37.42137299550869,25 700 | -122.0852186221971,37.42137299504316,25 701 | -122.0852277765639,37.42161656508265,25 702 | -122.0852598189347,37.42160565894403,25 703 | -122.0852598185499,37.42168200156,25 704 | -122.0852369311478,37.42170017860346,25 705 | -122.0852643957828,37.42176197982575,25 706 | -122.0853239032746,37.42176198013907,25 707 | -122.0853559454324,37.421852864452,25 708 | -122.0854108752463,37.42188921823734,25 709 | -122.0854795379357,37.42189285337048,25 710 | -122.0855436229819,37.42188921797546,25 711 | -122.0856260178042,37.42186013499926,25 712 | -122.085937287963,37.42186013453605,25 713 | -122.0859428718666,37.42160898590042,25 714 | -122.0859655469861,37.42157992759144,25 715 | -122.0858640462341,37.42147115002957,25 716 | -122.0858548911215,37.42140571326184,25 717 | -122.0858091162768,37.4214057134039,25 718 | -122.0857862287242,37.42136208886969,25 719 | 720 | 721 | 722 | 723 | 724 | Building 43 725 | 0 726 | #transYellowPoly 727 | 728 | 1 729 | relativeToGround 730 | 731 | 732 | -122.0844371128284,37.42177253003091,19 733 | -122.0845118855746,37.42191111542896,19 734 | -122.0850470999805,37.42178755121535,19 735 | -122.0850719913391,37.42143663023161,19 736 | -122.084916406232,37.42137237822116,19 737 | -122.0842193868167,37.42137237801626,19 738 | -122.08421938659,37.42147617161496,19 739 | -122.0838086419991,37.4214613409357,19 740 | -122.0837899728564,37.42131306410796,19 741 | -122.0832796534698,37.42129328840593,19 742 | -122.0832609819207,37.42139213944298,19 743 | -122.0829373621737,37.42137236399876,19 744 | -122.0829062425667,37.42151569778871,19 745 | -122.0828502269665,37.42176282576465,19 746 | -122.0829435788635,37.42176776969635,19 747 | -122.083217411188,37.42179248552686,19 748 | -122.0835970430103,37.4217480074456,19 749 | -122.0839455556771,37.42169364237603,19 750 | -122.0840077894637,37.42176283815853,19 751 | -122.084113587521,37.42174801104392,19 752 | -122.0840762473784,37.42171341292375,19 753 | -122.0841447047739,37.42167881534569,19 754 | -122.084144704223,37.42181720660197,19 755 | -122.0842503333074,37.4218170700446,19 756 | -122.0844371128284,37.42177253003091,19 757 | 758 | 759 | 760 | 761 | 762 | 763 | Extruded Polygon 764 | A simple way to model a building 765 | 766 | The Pentagon 767 | 768 | -77.05580139178142 769 | 38.870832443487 770 | 59.88865561738225 771 | 48.09646074797388 772 | 742.0552506670548 773 | 774 | 775 | 1 776 | relativeToGround 777 | 778 | 779 | -77.05788457660967,38.87253259892824,100 780 | -77.05465973756702,38.87291016281703,100 781 | -77.05315536854791,38.87053267794386,100 782 | -77.05552622493516,38.868757801256,100 783 | -77.05844056290393,38.86996206506943,100 784 | -77.05788457660967,38.87253259892824,100 785 | 786 | 787 | 788 | 789 | -77.05668055019126,38.87154239798456,100 790 | -77.05542625960818,38.87167890344077,100 791 | -77.05485125901024,38.87076535397792,100 792 | -77.05577677433152,38.87008686581446,100 793 | -77.05691162017543,38.87054446963351,100 794 | -77.05668055019126,38.87154239798456,100 795 | 796 | 797 | 798 | 799 | 800 | 801 | Absolute and Relative 802 | 0 803 | Four structures whose roofs meet exactly. Turn on/off 804 | terrain to see the difference between relative and absolute 805 | positioning. 806 | 807 | -112.3348969157552 808 | 36.14845533214919 809 | 0 810 | -86.91235037566909 811 | 49.30695423894192 812 | 990.6761201087104 813 | 814 | 815 | Absolute 816 | 0 817 | #transBluePoly 818 | 819 | 1 820 | absolute 821 | 822 | 823 | -112.3372510731295,36.14888505105317,1784 824 | -112.3356128688403,36.14781540589019,1784 825 | -112.3368169371048,36.14658677734382,1784 826 | -112.3384408457543,36.14762778914076,1784 827 | -112.3372510731295,36.14888505105317,1784 828 | 829 | 830 | 831 | 832 | 833 | Absolute Extruded 834 | 0 835 | #transRedPoly 836 | 837 | 1 838 | 1 839 | absolute 840 | 841 | 842 | -112.3396586818843,36.14637618647505,1784 843 | -112.3380597654315,36.14531751871353,1784 844 | -112.3368254237788,36.14659596244607,1784 845 | -112.3384555043203,36.14762621763982,1784 846 | -112.3396586818843,36.14637618647505,1784 847 | 848 | 849 | 850 | 851 | 852 | Relative 853 | 0 854 | 855 | -112.3350152490417 856 | 36.14943123077423 857 | 0 858 | -118.9214100848499 859 | 37.92486261093203 860 | 345.5169113679813 861 | 862 | #transGreenPoly 863 | 864 | 1 865 | relativeToGround 866 | 867 | 868 | -112.3349463145932,36.14988705767721,100 869 | -112.3354019540677,36.14941108398372,100 870 | -112.3344428289146,36.14878490381308,100 871 | -112.3331289492913,36.14780840132443,100 872 | -112.3317019516947,36.14680755678357,100 873 | -112.331131440106,36.1474173426228,100 874 | -112.332616324338,36.14845453364654,100 875 | -112.3339876620524,36.14926570522069,100 876 | -112.3349463145932,36.14988705767721,100 877 | 878 | 879 | 880 | 881 | 882 | Relative Extruded 883 | 0 884 | 885 | -112.3351587892382 886 | 36.14979247129029 887 | 0 888 | -55.42811560891606 889 | 56.10280503739589 890 | 401.0997279712519 891 | 892 | #transYellowPoly 893 | 894 | 1 895 | 1 896 | relativeToGround 897 | 898 | 899 | -112.3348783983763,36.1514008468736,100 900 | -112.3372535345629,36.14888517553886,100 901 | -112.3356068927954,36.14781612679284,100 902 | -112.3350034807972,36.14846469024177,100 903 | -112.3358353861232,36.1489624162954,100 904 | -112.3345888301373,36.15026229372507,100 905 | -112.3337937856278,36.14978096026463,100 906 | -112.3331798208424,36.1504472788618,100 907 | -112.3348783983763,36.1514008468736,100 908 | 909 | 910 | 911 | 912 | 913 | 914 |
915 |
916 | -------------------------------------------------------------------------------- /assets/example2.kml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Red Bull X-Alps 2019 Route 5 | https://www.redbullxalps.com/ Created by twpayne@gmail.com 6 | 1 7 | 8 | Route 9 | 10 | 11 | 13.0484,47.79885 13.110917,47.804133 13.305787,47.332295 12.33277,47.784362 11.9549,46.737598 10.98526,47.4211 10.879767,47.401283 9.851879,46.815225 8.424457,46.770918 8.005393,46.577621 5.887857,45.306816 7.090381,44.667312 6.422229,44.120985 7.410751,43.755956 7.454787,43.75875 12 | 1 13 | 14 | 20 | 21 | 26 | 27 | 28 | Turnpoints 29 | 30 | Salzburg 31 | 32 | 33 | 13.0484,47.79885 34 | 35 | 43 | 44 | 49 | 50 | 51 | Gaisberg 52 | signboard 53 | 54 | 55 | 13.110917,47.804133 56 | 57 | 65 | 66 | 71 | 72 | 73 | Wagrain-Kleinarl 74 | signboard 75 | 76 | 77 | 13.305787,47.332295 78 | 79 | 87 | 88 | 93 | 94 | 95 | Aschau-Chiemsee 96 | signboard 97 | 98 | 99 | 12.33277,47.784362 100 | 101 | 109 | 110 | 115 | 116 | 117 | Kronplatz 118 | signboard 119 | 120 | 121 | 11.9549,46.737598 122 | 123 | 131 | 132 | 137 | 138 | 139 | Zugspitz 140 | pass N 141 | 142 | 143 | 10.98526,47.4211 144 | 145 | 152 | 153 | 154 | 155 | 156 | 10.98526,47.4211 10.98526,47.196269598520324 157 | 158 | 165 | 166 | 167 | 172 | 173 | 174 | Lermoos-Tiroler Zugspitz Arena 175 | signboard 176 | 177 | 178 | 10.879767,47.401283 179 | 180 | 188 | 189 | 194 | 195 | 196 | Davos 197 | signboard 198 | 199 | 200 | 9.851879,46.815225 201 | 202 | 210 | 211 | 216 | 217 | 218 | Titlis 219 | signboard 220 | 221 | 222 | 8.424457,46.770918 223 | 224 | 232 | 233 | 238 | 239 | 240 | Eiger 241 | 1500m radius 242 | 243 | 244 | 8.005393,46.577621 245 | 246 | 254 | 255 | 256 | 257 | 8.005393,46.59111082408879 8.007411386004984,46.59103930859754 8.009408360780075,46.590825520768504 8.011362740730094,46.59047172847008 8.013253795087904,46.58998168468399 8.01506146625202,46.58936058760861 8.016766582908044,46.58861502540384 8.018351063653368,46.587752906169705 8.019798108949551,46.586783373908844 8.021092379355597,46.58571671137243 8.022220158146354,46.584564230829145 8.02316949659154,46.58333815392459 8.023930340360643,46.582051481914704 8.024494635724556,46.58071785765729 8.024856414444256,46.57935142083319 8.025011856467065,46.57796665793827 8.024959329790072,46.576578248641624 8.024699407094783,46.57520091014225 8.02423485900483,46.5738492411753 8.023570624066586,46.572537567321 8.022713755798401,46.57127978925356 8.02167334739507,46.57008923553433 8.020460434907957,46.56897852150325 8.019087879945149,46.56795941575718 8.01757023314834,46.5670427156218 8.015923579901438,46.56623813292746 8.014165369908543,46.565554191290495 8.012314232444112,46.56499813597875 8.01038977922428,46.564575857307794 8.00841239697435,46.56429182837157 8.006403031871999,46.5641490577601 8.004382968128002,46.5641490577601 8.002373603025651,46.56429182837157 8.00039622077572,46.564575857307794 7.998471767555888,46.56499813597875 7.996620630091457,46.565554191290495 7.9948624200985625,46.56623813292746 7.99321576685166,46.5670427156218 7.991698120054851,46.56795941575718 7.990325565092044,46.56897852150325 7.989112652604931,46.57008923553433 7.9880722442016,46.57127978925356 7.987215375933413,46.572537567321 7.986551140995171,46.5738492411753 7.986086592905218,46.57520091014225 7.98582667020993,46.576578248641624 7.985774143532935,46.57796665793827 7.985929585555744,46.57935142083319 7.986291364275444,46.58071785765729 7.9868556596393585,46.582051481914704 7.987616503408459,46.58333815392459 7.988565841853647,46.584564230829145 7.989693620644403,46.58571671137243 7.990987891050449,46.586783373908844 7.992434936346632,46.587752906169705 7.994019417091955,46.58861502540384 7.995724533747981,46.58936058760861 7.997532204912097,46.58998168468399 7.999423259269906,46.59047172847008 8.001377639219925,46.590825520768504 8.003374613995016,46.59103930859754 8.005393,46.59111082408879 258 | 259 | 266 | 267 | 272 | 273 | 274 | Mont Blanc 275 | pass N 276 | 277 | 278 | 6.867674,45.830359 279 | 280 | 288 | 289 | 290 | 291 | 292 | 6.867674,45.830359 6.867674,45.605528598520316 293 | 294 | 301 | 302 | 303 | 308 | 309 | 310 | St. Hilare 311 | signboard 312 | 313 | 314 | 5.887857,45.306816 315 | 316 | 324 | 325 | 330 | 331 | 332 | Monte Viso 333 | 2250m radius 334 | 335 | 336 | 7.090381,44.667312 337 | 338 | 346 | 347 | 348 | 349 | 7.090381,44.68754673613318 7.092762589980537,44.6874757453242 7.095127457411984,44.687263271366724 7.09745899753014,44.686910806157954 7.099740840300694,44.68642082451503 7.101956965690705,44.68579676674505 7.104091816445464,44.685043014417296 7.106130407568226,44.68416485951042 7.108058431724881,44.68316846715423 7.109862359825947,44.6820608322314 7.111529536074018,44.680849730147806 7.113048266805791,44.67954366212132 7.114407902503551,44.678151795378 7.115598912401194,44.67668389867965 7.1166129511641305,44.675150273640085 7.117442917180201,44.673561682316134 7.118083002059652,44.67192927158581 7.118528731005785,44.67026449484756 7.118776993783513,44.668579031593154 7.11882606608039,44.666884705420784 7.118675621123042,44.66519340106522 7.118326731480924,44.663516981028 7.1177818610584405,44.661867202392706 7.117044847345161,44.66025563440796 7.116120874061689,44.65869357741505 7.115016434405281,44.65719198368645 7.113739285164013,44.65576138072787 7.1122983920308585,44.65441179757801 7.110703866508997,44.653152694619315 7.108966894856653,44.65199289738741 7.1070996595734846,44.650940534838895 7.105115253980594,44.65000298250571 7.103027590492422,44.64918681092998 7.1008513032207565,44.64849773973612 7.098601645588721,44.64794059765821 7.096294383665553,44.64751928879869 7.093945685961249,44.64723676535147 7.091572010443376,44.64709500697793 7.0891899895566235,44.64709500697793 7.08681631403875,44.64723676535147 7.084467616334447,44.64751928879869 7.08216035441128,44.64794059765821 7.079910696779244,44.64849773973612 7.0777344095075785,44.64918681092998 7.075646746019405,44.65000298250571 7.073662340426515,44.650940534838895 7.071795105143346,44.65199289738741 7.070058133491003,44.653152694619315 7.068463607969141,44.65441179757801 7.0670227148359865,44.65576138072787 7.065745565594718,44.65719198368645 7.06464112593831,44.65869357741505 7.063717152654839,44.66025563440796 7.062980138941559,44.661867202392706 7.062435268519076,44.663516981028 7.062086378876957,44.66519340106522 7.061935933919609,44.666884705420784 7.061985006216487,44.668579031593154 7.062233268994214,44.67026449484756 7.062678997940347,44.67192927158581 7.063319082819799,44.673561682316134 7.064149048835869,44.675150273640085 7.065163087598806,44.67668389867965 7.06635409749645,44.678151795378 7.067713733194209,44.67954366212132 7.0692324639259825,44.680849730147806 7.070899640174052,44.6820608322314 7.072703568275118,44.68316846715423 7.074631592431774,44.68416485951042 7.076670183554536,44.685043014417296 7.078805034309295,44.68579676674505 7.081021159699306,44.68642082451503 7.08330300246986,44.686910806157954 7.085634542588016,44.687263271366724 7.087999410019463,44.6874757453242 7.090381,44.68754673613318 350 | 351 | 358 | 359 | 364 | 365 | 366 | Cheval Blanc 367 | pass W 368 | 369 | 370 | 6.422229,44.120985 371 | 372 | 380 | 381 | 382 | 383 | 384 | 6.422229,44.120985 6.7354178618529215,44.12055721299625 385 | 386 | 393 | 394 | 395 | 400 | 401 | 402 | Peille 403 | signboard 404 | 405 | 406 | 7.410751,43.755956 407 | 408 | 416 | 417 | 422 | 423 | 424 | Monaco 425 | 426 | 427 | 7.454787,43.75875 428 | 429 | 437 | 438 | 443 | 444 | 445 | 446 | -------------------------------------------------------------------------------- /assets/screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/windycom/leaflet-kml/216223e905744b2313f9fc7aae3bb85c354a7e5d/assets/screenshot.jpg -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leaflet-kml", 3 | "version": "1.1.0", 4 | "description": "Leaflet KML layer plugin", 5 | "main": "L.KML.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/windycom/leaflet-kml.git" 12 | }, 13 | "author": "Pavel Shramov, Bruno Bergot", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/windycom/leaflet-kml/issues" 17 | }, 18 | "homepage": "https://github.com/windycom/leaflet-kml#readme" 19 | } 20 | --------------------------------------------------------------------------------