Merge branch 'gh-pages' into master-docs

This commit is contained in:
Iván Sánchez Ortega 2016-08-18 11:27:28 +02:00
commit ffb9a636ca
103 changed files with 39062 additions and 1 deletions

3
.gitignore vendored
View File

@ -4,6 +4,7 @@ tmp/**/*
.idea
.idea/**/*
*.iml
_site
*.sublime-*
_site
dist/*.js
@ -11,8 +12,8 @@ dist/*.map
dist/reference.html
coverage/
*.js.html
index.html
.mailmap
bower.json
component.json
debug/local/
Gemfile.lock

1
docs/CNAME Normal file
View File

@ -0,0 +1 @@
leafletjs.com

3
docs/Gemfile Normal file
View File

@ -0,0 +1,3 @@
source 'https://rubygems.org'
gem 'github-pages'

6
docs/_config.yml Normal file
View File

@ -0,0 +1,6 @@
exclude: [build, debug, node_modules, spec, src, CNAME, Jakefile.js, reference-tpl.html, CHANGELOG.md, README.md, LICENSE, DOCS-TODO.md]
markdown: kramdown
kramdown:
entity_output: as_input

View File

@ -0,0 +1,7 @@
<table>
<tr><td style='text-align: center; border: none'>
<iframe src='{{ include.url }}' width='616' height='416'></iframe>
</td></tr>
<tr><td style='text-align: center; border: none'>
<small><a href='{{ include.url }}'>See this example stand-alone.</a></small>
</td></tr></table>

30
docs/_layouts/post.html Normal file
View File

@ -0,0 +1,30 @@
---
root: "../../../"
layout: v2
post: true
bodyclass: post-page
---
<p><a href="../../../blog.html">&larr; Back to the list of blog posts</a></p>
<h2>{{ page.title }}</h2>
<p class="post-meta">Posted on {{ page.date | date_to_long_string }} by <a href="{{ page.authorsite }}">{{ page.author }}</a></p>
{{ content }}
<div id="disqus_thread"></div>
<script>
var disqus_shortname = 'leafletjs';
// var disqus_developer = 1;
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>

View File

@ -0,0 +1,9 @@
---
root: "../"
layout: v2
tutorial: true
---
<p class="tutorials-back"><a href="../examples.html">&larr; Tutorials</a></p>
{{ content }}

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
{% capture title %}{% if page.title %}{{ page.title }} - {% elsif post.title %}{{ post.title }} - {% endif %}{% endcapture %}
<title>{{ title }}Leaflet</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{% capture root %}{% if page.root %}{{ page.root }}{% else %}{{ layout.root }}{% endif %}{% endcapture %}
<link rel="shortcut icon" type="image/x-icon" href="{{ root }}docs/images/favicon.ico" />
<link rel="stylesheet" href="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.css" />
<script src="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.js"></script>
<style>
#map {
width:600px;
height: 400px;
}
</style>
{% if page.css %}<style>{{ page.css }}</style>{% endif %}
</head>
<body{% if page.bodyclass %} class="{{ page.bodyclass }}"{% endif %}>
<div id='map'></div>
{{ content }}
</body>
</html>

View File

@ -0,0 +1,9 @@
---
root: "../../"
layout: v2
tutorial: true
---
<p class="tutorials-back"><a href="../../examples.html">&larr; Tutorials</a></p>
{{ content }}

159
docs/_layouts/v2.html Normal file
View File

@ -0,0 +1,159 @@
<!DOCTYPE html>
<html>
<head>
{% capture title %}{% if page.title %}{{ page.title }} - {% elsif post.title %}{{ post.title }} - {% endif %}{% endcapture %}
<title>{{ title }}Leaflet - a JavaScript library for interactive maps</title>
<meta charset="utf-8" />
{% if title == '' %}
<meta property="og:title" content="Leaflet — an open-source JavaScript library for interactive maps" />
<meta property="og:description" content="Leaflet is a modern, lightweight open-source JavaScript library for mobile-friendly interactive maps." />
<meta property="og:image" content="http://leafletjs.com/docs/images/logo.png" />
<meta itemprop="name" content="Leaflet">
<meta itemprop="description" content="Leaflet — a modern, lightweight open-source JavaScript library for mobile-friendly interactive maps.">
<meta itemprop="image" content="http://leafletjs.com/docs/images/logo.png">
{% endif %}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{% capture root %}{% if page.root %}{{ page.root }}{% else %}{{ layout.root }}{% endif %}{% endcapture %}
<link rel="shortcut icon" type="image/x-icon" href="{{ root }}docs/images/favicon.ico" />
<link href="http://leafletjs.com/atom.xml" type="application/atom+xml" rel="alternate" title="Leaflet Dev Blog Atom Feed" />
<link rel="stylesheet" href="{{ root }}docs/css/normalize.css" />
<link rel="stylesheet" href="{{ root }}docs/css/main.css" />
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,400italic,700,300' rel='stylesheet' type='text/css'>
<script src="{{ root }}docs/highlight/highlight.pack.js"></script>
<link rel="stylesheet" href="{{ root }}docs/highlight/styles/github-gist.css" />
<!-- Leaflet -->
<link rel="stylesheet" href="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.css" />
<script src="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.js"></script>
{% if page.css %}<style>{{ page.css }}</style>{% endif %}
<script>
ACCESS_TOKEN = 'pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpandmbXliNDBjZWd2M2x6bDk3c2ZtOTkifQ._QA7i5Mpkd_m30IGElHziw';
MB_ATTR = 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
'Imagery © <a href="http://mapbox.com">Mapbox</a>';
MB_URL = 'https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=' + ACCESS_TOKEN;
OSM_URL = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
OSM_ATTRIB = '&copy; <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors';
</script>
</head>
<body{% if page.bodyclass %} class="{{ page.bodyclass }}"{% endif %}>
<h1><a href="http://leafletjs.com"><img src="{{ root }}docs/images/logo.png" alt="Leaflet" width="300" /></a></h1>
<h3 class="tagline">an open-source JavaScript library<br> for mobile-friendly interactive maps</h3>
<ul class="nav">
<li>
{% if page.title == nil %}
<span>Overview</span>
{% else %}
<a href="{{ root }}index.html">Overview</a>
{% endif %}
</li>
<li>
{% if page.title == 'Tutorials' %}
<span>Tutorials</span>
{% else %}
<a href="{{ root }}examples.html"{% if page.tutorial == true %} class="active"{% endif %}>Tutorials</a>
{% endif %}
</li>
<li>
{% if page.title == 'Documentation' %}
<span>Docs</span>
{% else %}
<a href="{{ root }}reference.html">Docs</a>
{% endif %}
</li>
<li>
{% if page.title == 'Download' %}
<span>Download</span>
{% else %}
<a href="{{ root }}download.html">Download</a>
{% endif %}
</li>
<li>
{% if page.title == 'Plugins' %}
<span>Plugins</span>
{% else %}
<a href="{{ root }}plugins.html">Plugins</a>
{% endif %}
</li>
<li>
{% if page.title == 'Blog' %}
<span>Blog</span>
{% else %}
<a href="{{ root }}blog.html"{% if page.post == true %} class="active"{% endif %}>Blog</a>
{% endif %}
</li>
</ul>
<div class="container">
{{ content }}
<div class="footer">
<p>&copy; 2015 <a href="http://agafonkin.com/en">Vladimir Agafonkin</a>. Maps &copy; <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors.</p>
</div>
</div>
<nav class="ext-links">
<a class="ext-link twitter" href="http://twitter.com/LeafletJS" title="Follow LeafletJS on Twitter"><img alt="Follow LeafletJS on Twitter" src="{{root}}docs/images/twitter-round.png" width="46" /></a>
<a class="ext-link github" href="http://github.com/Leaflet/Leaflet" title="View Source on GitHub"><img alt="View Source on GitHub" src="{{root}}docs/images/github-round.png" width="46" /></a>
<a class="ext-link forum" href="https://stackoverflow.com/questions/tagged/leaflet" title="Ask for help on Stack Overflow"><img alt="Leaflet questions on Stack Overflow" src="{{root}}docs/images/forum-round.png" width="46" /></a>
</nav>
<script>
hljs.configure({tabReplace: ' '});
hljs.initHighlighting();
(function () {
if (document.body.className.indexOf('api-page') !== -1) {
var headers = document.getElementsByTagName('h2');
for (var i = 0, len = headers.length; i < len; i++) {
if (headers[i].id) {
headers[i].onclick = function(e) {
if (e.offsetX < 0) {
window.location.hash = '#' + this.id;
}
};
}
}
}
})();
</script>
<script>
var _gaq = _gaq || [];
_gaq.push([ '_setAccount', 'UA-4147697-4' ]);
_gaq.push([ '_trackPageview' ]);
(function() {
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl'
: 'http://www')
+ '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();
</script>
<script type="text/javascript" src="{{ root }}docs/js/docs.js"></script>
</body>
</html>

View File

@ -0,0 +1,240 @@
---
layout: post
title: Leaflet 0.4 Released
description: After 5.5 months of development with 33 contributors involved, I'm proud to announce the release of Leaflet 0.4! It comes with a simpler API and <em>lots</em> of great improvements, along with a major update to documentation, a plugins page and the launch of the developer blog.
author: Vladimir Agafonkin
authorsite: http://agafonkin.com/en
---
After 5.5 months of development with [33 contributors](https://github.com/Leaflet/Leaflet/graphs/contributors?from=2012-02-15&to=2012-07-30&type=c) involved since the previous stable release, I'm proud to announce the release of Leaflet 0.4! It comes with a simpler API and *lots* of great improvements and important bugfixes, along with a major update to documentation, an official plugins page and the launch of this developer blog. Lets take a look at the improvements one by one.
### Simpler API
Leaflet 0.4 contains several API improvements that allow you to write simpler, terser code ([jQuery](http://jquery.com)-like), while being backwards compatible with the previous approach (so that you can use both styles).
L.marker([51.5, -0.09])
.addTo(map)
.bindPopup('Hello world!')
.openPopup();
First, Leaflet methods now accept [LatLng][], [LatLngBounds][], [Point][] and [Bounds][] objects in a simple array form, so you don't need to always create them explicitly:
map.panTo([50, 30]); // the same as:
map.panTo(new L.LatLng(50, 30));
Second, Map methods like [addLayer][], [addControl][], [openPopup][] got their counterparts from the other side:
marker.addTo(map); // same as map.addLayer(marker)
control.addTo(map); // map.addControl(control)
popup.openOn(map); // map.openPopup(popup)
Along with the fact that all Leaflet methods that don't explicitly return a value return the object itself, this allows for convenient method chaining.
Third, Leaflet classes now come with lowercase shortcuts (class factories) that allow you to create objects without the <code>new</code> keyword, which makes chained code look nicer:
L.map('map').fitWorld(); // same as
(new L.Map('map')).fitWorld();
### Notable New Features
<div id="map" class="map" style="height: 250px"></div>
#### Improved Zoom Animation
Markers, popups, vector layers and image overlays were hidden during zoom in the previous version, but now (thanks to [Dave Leaver][]) they all have beautiful, smooth zoom animation unlike any other existing mapping libraries. Try zooming on the map above to see how it looks! If you have thousands of markers on a map though, you can turn off the marker animation if it gets slow with the Map's `markerZoomAnimation` option.
In addition, now tiles won't disappear if you zoom in or out more than once quickly.
#### Keyboard Navigation
Leaflet maps got a nice accessibility boost in 0.4 with the new keyboard handler (contributed by [Eric Martinez](https://github.com/ericmmartinez)), enabled by default. It allows users to navigate the map by using arrow keys for panning and <code>+/-</code> keys for zooming (after making the map focused either by tabbing to it or clicking on it). Try it on the map above, it feels very nice!
#### Panning Inertia
Another nice improvement comes to the panning experience --- now it has an inertial movement effect, where the map smoothly continues to move after a quick pan. Feels especially natural on touch devices --- and it's enabled by default too, try it now! It's also highly configurable, allowing you to set the maximum speed of the effect, decceleration, and time threshold under which it triggers.
#### Pinch-Zoom on Android 4
In the previous Leaflet version, pinch-zoom only worked on iOS devices, but now it finally comes to Android! Works for Android 4+ not only in the stock browser, but also on Chrome and Firefox for Android.
#### Scale Control
A simple, lightweight control that indicates the scale of the current map view in metric and/or imperial systems. As usual, you can customize its appearance with CSS. Take a look at the bottom left corner of the map above!
L.control.scale().addTo(map);
#### Polyline and Polygon Editing
Allows users to edit polylines and polygons with a simple, intuitive interface. Note that this feature will eventually be merged into [Leaflet.draw][] --- an awesome plugin for drawing shapes by Jacob Toye.
polygon.editing.enable();
#### Div-based Icons
In addition to the image-based [Icon][] class, Leaflet 0.4 gets a [DivIcon][] class for creating lightweight div-based markers (that can contain custom HTML and can be styled with CSS). For example, you can see them in action when editing polylines (the square handles), or in the [Leaflet.markercluster][] plugin I'll talk about later (the colored clusters).
L.marker([50.505, 30.57], {
icon: L.divIcon({className: 'my-div-icon'})
}).addTo(map);
#### Rectangle Layer
Rectangle is a convenient shortcut for creating rectangular area layers. You could do this earlier with polygons, but this is easier:
L.rectangle([[51.505, -0.03], [51.5, -0.045]]).addTo(map);
### API improvements
#### GeoJSON API
[GeoJSON][] API was improved to be simpler and much more flexible. [Jason Sanford][] wrote a [great tutorial](../../../examples/geojson.html) that showcases the new API. The changes are not backwards-compatible though, so be sure to update your old code.
#### Icon API
[Icon][] API was improved to be simpler and more flexible, and the changes are not backwards-compatible too (the old code can be updated very quickly though). Check out the updated [Custom Icons tutorial](../../../examples/custom-icons.html), or head straigt to the [API docs](../../../reference.html#icon).
#### Control API
Custom Controls are much easier to create now --- checkout the [API docs](../../../reference.html#icontrol) that also have a simple example.
#### Better Events API
[Aaron King][] brough some improvements to [event methods](../../../reference.html#events). `on` and `off` methods can now accept multiple event types at once as a string space-separated types:
map.on('click dblclick moveend', doStuff);
Also, they can accept an object with types and listener functions as key/value pairs, like this:
marker.on({
click: onMarkerClick,
dragend: onMarkerDragEnd
});
Moreover, now if you only specify an event type to the `off` method, it will remove all listeners tied to this event.
map.off('click');
#### Other API Improvements
Leaflet 0.4 features more than 30 new methods, options and events across different Leaflet classes that make the API more complete and powerful. Check out the [full changelog](https://github.com/Leaflet/Leaflet/blob/master/CHANGELOG.md#other-api-improvements) for the complete list.
### Performance and Usability Improvements
You may think that Leaflet is unbelievably fast already, but this version brings several performance improvements that make it even faster.
* Panning, map resizing and pinch-zoom performance was improved (some tricks behind this will be explained in a future blog post).
* Updating and removing vector layers on the canvas backend (e.g. on Android 2) works many times faster.
* Box shadows on controls were replaced with simple borders on mobile devices to improve performance.
* Vector layers won't flicker after each panning on iOS now.
In addition, there are several usability improvents not already mentioned:
* Panning now works even if there are markers under the cursor (helps on crowded maps).
* Popup appearance is slightly improved.
* Tile layer now has <code>detectRetina</code> option that, when enabled, doubles the tile resolution for retina displays (contributed by [Mithgol][]) .
### Bugfixes
Leaflet 0.4 brings around 45 bugfixes that make it more stable and reliable across all browsers and platforms. Notable bugfixes include the dreaded iOS bug that caused the map to completely disappear after pinch-zooming in some rare cases, broken zooming on IE10 beta, broken Leaflet maps on pages served with an XHTML content type, and incorrect zooming on maps inside a fixed-position element.
Here's [a full list of bugfixes](https://github.com/Leaflet/Leaflet/blob/master/CHANGELOG.md#bug-fixes) in the changelog.
### Upgrading from older versions
Besides the GeoJSON and Icon changes mentioned above, here's a [list of potentially breaking changes](https://github.com/Leaflet/Leaflet/blob/master/CHANGELOG.md#other-breaking-api-changes) --- read it carefully when updating your code (shouldn't take much time though).
Download options for Leaflet 0.4 (including the actual download, the CDN-hosted version, and intructions for building manually) are listed on the [download page](../../../download.html).
### Code Stats
I'm still commited to keeping Leaflet as small and lightweight as possible. Here's a breakdown of the current size of the library:
* JavaScript: **27 KB** minified and gzipped (102 KB minified, 176 KB in source, 7578 lines of code)
* CSS: **1.8 KB** gzipped (8 KB, 377 lines of code)
* Images: **10 KB** (5 PNG images)
### Documentation Update
Until now, Leaflet API reference was incomplete. But for this release, enourmous effort was put into making it 100% complete, up-to-date and generally the best API reference page you've ever seen. All remaining classes, methods, options, events and properties were carefully documented and more code examples added, and the docs will always be kept up-to-date from now on.
Besides, the design of the page was significantly improved --- with better colors, font, spacing, hyphenation, manually adjusted column widths, etc. --- lots of detail to make it beautiful and easy to read.
### Plugins Page
Leaflet website now has an official [plugins page](../../../plugins.html) that lists many Leaflet plugins created by the awesome Leaflet community, adding lots of great features and helping with service integration.
One plugin I'd like to mention is [Leaflet.markercluster][] by [Dave Leaver], currently the best marker clustering plugin I've ever seen among any mapping libraries --- it's fast, beautiful, provides smooth animations for clusters, includes a smart Google Earth-style solution for crowded markers on the last zoom level (by [George MacKerron][]), can highlight the area covered by a cluster on hover, works well on mobile devices, and can be customized easily. I think we'll cover this plugin in more detail in one of the next posts.
Another plugin to note is [Leaflet.draw][] by [Jacob Toye][], inspired by a similar plugin by [Bruno B](https://github.com/brunob). It enables drawing features like polylines, polygons, rectangles, circles and markers through a very nice user-friendly interface with icons and hints. Other editing-related code will probably move into this plugin in future.
Also, thanks to [Proj4Leaflet](https://github.com/kartena/Proj4Leaflet) plugin by [Kartena](http://www.kartena.se/), GIS enthusiasts can now enjoy Leaflet for maps with some quirky and rare projections.
One more Leaflet-based creation everyone needs to check out is [OSM Buildings](http://flyjs.com/buildings/) by [Jan Marsch](http://flyjs.com/buildings/about.php), an amazing JS library for visualizing 3D OSM building data on top of Leaflet maps. Incredibly cool stuff.
### Developer Blog
This is the first post of the official Leaflet developer blog, that will become the main place for all important Leaflet-related news, tutorials, tips and development notes.
### Big Players Using Leaflet
Since the previous release, Leaflet got adopted by many great companies, including [Flickr](http://flickr.com/map), [foursquare](http://foursquare.com) and [Wikimedia Foundation](http://blog.wikimedia.org/2012/04/05/new-wikipedia-app-for-ios-and-an-update-for-our-android-app/) (featured on [frontpage](../../../index.html) now). This is a really exciting time for Leaflet and open source maps, and I look forward to see many other companies follow this awesome trend in future.
### Thank You
I'd like to thank all the awesome people that helped Leaflet becoming what it is now --- contributed code, reported bugs, used Leaflet on their websites, told collegues about it, talked about it on conferences, etc. Keep up the great work!
Special thanks go to [Dave Leaver][] for his inspiring contributions including improved zoom animation and the state-of-the-art clustering plugin, and [Jason Sanford][] for his friendly support (and setting up the Leaflet CDN among other things).
And, of course, thanks to my amazing company, [CloudMade](http://cloudmade.com), for embracing open source and supporting this development.
Sincerely, <br />
Vladimir Agafonkin, Leaflet maintainer.
[LatLng]: ../../../reference.html#latlng
[LatLngBounds]: ../../../reference.html#latlngbounds
[Point]: ../../../reference.html#point
[Bounds]: ../../../reference.html#bounds
[Icon]: ../../../reference.html#icon
[DivIcon]: ../../../reference.html#divicon
[GeoJSON]: ../../../reference.html#geojson
[addControl]: ../../../reference.html#map-addcontrol
[addLayer]: ../../../reference.html#map-addlayer
[openPopup]: ../../../reference.html#map-openpopup
[Leaflet.draw]: https://github.com/jacobtoye/Leaflet.draw
[Leaflet.markercluster]: https://github.com/danzel/Leaflet.markercluster
[Dave Leaver]: https://github.com/danzel
[Jason Sanford]: https://github.com/JasonSanford
[Aaron King]: https://github.com/Guiswa
[Mithgol]: https://github.com/Mithgol
[George MacKerron]: https://github.com/jawj/
[Jacob Toye]: https://github.com/jacobtoye
<script>
var map = L.map('map').setView([51.503, -0.09], 13);
L.tileLayer(MB_URL, {attribution: MB_ATTR, id: 'examples.map-i875mjb7'}).addTo(map);
var polygon = L.polygon([
[51.509, -0.08],
[51.503, -0.06],
[51.51, -0.047]
], {color: 'red'}).addTo(map).bindPopup('I am an editable polygon.');
polygon.editing.enable();
L.control.scale().addTo(map);
L.marker([51.5, -0.095]).addTo(map)
.bindPopup("<b>Hello world!</b><br />I am a popup.").openPopup();
L.marker([51.505, -0.115]).addTo(map).bindPopup("I am a second popup.");
L.marker([51.496, -0.13]).addTo(map).bindPopup("I am a third popup.");
L.rectangle([
[51.505, -0.03],
[51.5, -0.045]
], {weight: 1, opacity: 0.8}).addTo(map).bindPopup('I am a rectangle.');
</script>

View File

@ -0,0 +1,47 @@
---
layout: post
title: Leaflet 0.4.3 and a New Tutorial
description: Leaflet 0.4.3 released with several bugfixes and improvements, and comes with a new tutorial on creating a colorful interactive choropleth map.
author: Vladimir Agafonkin
authorsite: http://agafonkin.com/en
---
Following the [Leaflet 0.4 release](leaflet-0-4-released.html), there were several minor bugfix releases over the past week, with Leaflet 0.4.3 released today. They contain fixes for some bugs that were discovered and also bring some improvements to the new GeoJSON API to make it even more flexible --- see the changelog below.
I've also written [a new tutorial](../../../examples/choropleth.html), inspired by the [Texas Tribune US Senate Runoff Results map](http://www.texastribune.org/library/data/us-senate-runoff-results-map/) by [Ryan Murphy](http://www.texastribune.org/about/staff/ryan-murphy/) (also powered by Leaflet). It will show you step-by-step how to create a beautiful interactive [choropleth map](http://en.wikipedia.org/wiki/Choropleth_map) of US States Population Density with the help of GeoJSON and custom controls, and hopefully convince more major news and government websites to switch to Leaflet. :)
Grab the new Leaflet 0.4.3 at the [download page](../../../download.html). Enjoy!
**update**: IE9 regression was discovered in 0.4.3, so I had to release 0.4.4 with a fix. Sorry!
### 0.4.3 (August 7, 2012)
#### Improvements
* Improved `GeoJSON` `setStyle` to also accept function (like the corresponding option).
* Added `GeoJSON` `resetStyle(layer)`, useful for resetting hover state.
* Added `feature` property to layers created with `GeoJSON` (containing the GeoJSON feature data).
* Added `FeatureGroup` `bringToFront` and `bringToBack` methods (so that they would work for multipolys).
* Added optional `animate` argument to `Map` `invalidateSize` (by [@ajbeaven](https://github.com/ajbeaven)). [#857](https://github.com/Leaflet/Leaflet/pull/857)
#### Bugfixes
* Fixed a bug where tiles sometimes disappeared on initial map load on Android 2/3 (by [@danzel](https://github.com/danzel)). [#868](https://github.com/Leaflet/Leaflet/pull/868)
* Fixed a bug where map would occasionally flicker near the border on zoom or pan on Chrome.
* Fixed a bug where `Path` `bringToFront` and `bringToBack` didn't return `this`.
* Removed zoom out on Win/Meta key binding (since it interferes with global keyboard shortcuts). [#869](https://github.com/Leaflet/Leaflet/issues/869)
### 0.4.2 (August 1, 2012)
* Fixed a bug where layers control radio buttons would not work correctly in IE7 (by [@danzel](https://github.com/danzel)). [#862](https://github.com/Leaflet/Leaflet/pull/862)
* Fixed a bug where `FeatureGroup` `removeLayer` would unbind popups of removed layers even if the popups were not put by the group (affected [Leaflet.markercluster](https://github.com/danzel/Leaflet.markercluster) plugin) (by [@danzel](https://github.com/danzel)). [#861](https://github.com/Leaflet/Leaflet/pull/861)
### 0.4.1 (July 31, 2012)
* Fixed a bug that caused marker shadows appear as opaque black in IE6-8. [#850](https://github.com/Leaflet/Leaflet/issues/850)
* Fixed a bug with incorrect calculation of scale by the scale control. [#852](https://github.com/Leaflet/Leaflet/issues/852)
* Fixed broken L.tileLayer.wms class factory (by [@mattcurrie](https://github.com/mattcurrie)). [#856](https://github.com/Leaflet/Leaflet/issues/856)
* Improved retina detection for `TileLayer` `detectRetina` option (by [@sxua](https://github.com/sxua)). [#854](https://github.com/Leaflet/Leaflet/issues/854)
Sincerely, <br />
Vladimir Agafonkin, Leaflet maintainer.

View File

@ -0,0 +1,112 @@
---
layout: post
title: Leaflet.MarkerCluster 0.1 Released
description: Introducing Leaflet.MarkerCluster, a beautiful, fast, customizable plugin to reduce the visual clutter on crowded maps.
author: Dave Leaver
authorsite: https://github.com/danzel/
---
_This is a guest post from Dave Leaver, an active Leaflet contributor (particularly, he implemented 0.4 zoom animation improvements) and also the author of the best marker clustering plugin out there, which is presented in this post._
Almost anyone who has a map with markers on it will eventually end up having those markers overlap. At my day job at <a href="http://www.smartrak.co.nz/" title="Smartrak GPS Fleet Tracking">Smartrak</a> we regularly have customers with thousands of points on the map. When you zoom it out, these markers all overlap and make the map look messy and crowded. There are also cases where the markers overlap even on the maximum zoom level, which makes interacting with them impossible. Also, having a large amount of markers on the map usually ends up lowering performance to an unacceptable level.
To improve this, many sites use marker clustering, a technique of grouping markers that are close to each other together on each zom level. One good example of this is <a href="http://www.redfin.com/homes-for-sale">Redfin</a>. We needed something like this, but in Leaflet. In the spirit of open source we developed and released our solution so that everyone can take advantage of it. So we proudly present <a href="https://github.com/leaflet/Leaflet.markercluster">Leaflet.MarkerCluster</a>.
<div id="map" class="map" style="height: 320px"></div>
{:#plugin-features}
### Features
The clusterer has all sorts of great built in behaviour:
* Everything is brilliantly animated. As you zoom in and out you can logically see which clusters have become which markers.
* It is very fast, so for example [clustering 50,000 points](https://leaflet.github.com/Leaflet.markercluster/example/marker-clustering-realworld.50000.html) isn't a problem. Also, all the heavy calculation happens on initial page load, and after this the map works smoothly.
* Markers that don't need clustering aren't and will be visible at the relevant zoom levels.
* When you mouse over a cluster the bounds of the marker within that cluster are shown.
* Clicking a cluster will zoom you in to the bounds of its children.
* At the bottom zoom level if there are still clusters you can click on them to "spiderfy" them, which makes interaction with individual markers within the cluster possible (based on <a href="https://github.com/jawj/OverlappingMarkerSpiderfier-Leaflet">jawj's Overlapping MarkerSpidifer</a>).
* Cluster and markers that are further than a screen width from the view port are removed from the map to increase performance.
* As with core Leaflet, everything works on both mobile and desktop browsers and is tested all the way back to IE6.
* Supports adding and removing markers after being added to the map (see Best Practices below!).
* It is highly customizable, allowing you to easily change the appearance of clusters, disable certain features and add custom behavior on cluster interaction.
### Usage
Using the Marker Clusterer is easy, just replace your existing [LayerGroup](../../../examples/layers-control.html) usage with an `L.MarkerClusterGroup`:
var markers = new L.MarkerClusterGroup();
markers.addLayer(L.marker([175.3107, -37.7784]));
// add more markers here...
map.addLayer(markers);
You can also use all of the [FeatureGroup events](../../../reference.html#featuregroup) (and additionally `clusterclick`) for both individual markers and clusters.
markers.on('clusterclick', function (a) { alert('Cluster Clicked'); });
markers.on('click', function (a) { alert('Marker Clicked'); });
### Best Practices
* To get the best performance from the clusterer, you should add all of your markers to it before adding it to the map (like we did in the example).
* If you are going to move a marker that is in a L.MarkerClusterGroup you must remove it first, then move it, then re-add it. If you move it while it is in the MarkerClusterGroup we can't track it and that marker will become lost.
* Although the clusterer supports having markers added and removed from it while it is on the map it does not perform as well as when they are added while it is not on the map. If you need to do a large update to the markers in a `MarkerClusterGroup` you may want to remove it from the map, change the markers then re-add it.
### Get It
You can download the latest release on the <a href="https://github.com/leaflet/Leaflet.markercluster/downloads">github download page</a>.
### The Technical Bits
The underlying clustering algorithm (`MarkerClusterGroup._cluster`) is plain greedy clustering.
{: .no-highlight}
foreach marker
if there is a cluster within the clustering distance, join it.
else if there is an unclustered marker within the clustering distance, form a cluster with it.
The first clustering step we do for the maximum (bottom most) zoom level, we then cluster all of the resulting markers and clusters to generate the next zoom level up and so on until we have reached the top.
These clusters are stored in a tree (A cluster contains its child clusters) with good geospatial qualities. We use this tree to optimise identifying what markers and clusters are on screen at any particular zoom level.
#### L.DistanceGrid
`L.DistanceGrid` provides some nice optimization when clustering (contributed by [Vladimir](http://agafonkin.com/en/), Leaflet maintainer).
To cluster the markers, we need to compare every marker with every other marker to try form a cluster.
To make this quicker, we need reduce the set of markers we need to compare with. `DistanceGrid` does this by putting all markers on a grid sized the same as the distance we need to search. Then, when looking for a marker to cluster with, we only need to look at markers in the grid square we are in and its immediate neighbours. This can be quite a big performance win as we only look at markers that we are likely to form a cluster with. (<a href="https://github.com/leaflet/Leaflet.markercluster/pull/29">check out the initial PR for numbers</a>)
### Closing Words
I hope you enjoy using the clusterer and get everything you want out of it. If you do use it in a public site please <a href="mailto:danzel@localhost.geek.nz">throw me an email</a> so I can check it out and potentially link it on the github site.
If you have any issues also please log a bug on <a href="https://github.com/leaflet/Leaflet.markercluster">the github page</a>.
Enjoy!<br />
Dave Leaver.
<link rel="stylesheet" href="http://leaflet.github.io/Leaflet.markercluster/dist/MarkerCluster.css" />
<link rel="stylesheet" href="http://leaflet.github.io/Leaflet.markercluster/dist/MarkerCluster.Default.css" />
<!--[if lte IE 8]><link rel="stylesheet" href="http://leaflet.github.io/Leaflet.markercluster/dist/MarkerCluster.Default.ie.css" /><![endif]-->
<script src="http://leaflet.github.io/Leaflet.markercluster/dist/leaflet.markercluster-src.js"></script>
<script src="http://leaflet.github.io/Leaflet.markercluster/example/realworld.388.js"></script>
<script>
var mapbox = new L.TileLayer(MB_URL, {maxZoom: 18, attribution: MB_ATTR, id: 'examples.map-i875mjb7'}),
latlng = new L.LatLng(-37.820, 175.217);
var map = new L.Map('map', {center: latlng, zoom: 15, layers: [mapbox]});
map.attributionControl.addAttribution("Points &copy 2012 LINZ");
var markers = new L.MarkerClusterGroup();
for (var i = 0; i < addressPoints.length; i++) {
var a = addressPoints[i];
var title = a[2];
var marker = new L.Marker(new L.LatLng(a[0], a[1]), { title: title });
marker.bindPopup(title);
markers.addLayer(marker);
}
map.addLayer(markers);
</script>

View File

@ -0,0 +1,36 @@
---
layout: post
title: Leaflet 0.4.5 Bugfix Release and Plans for 0.5
description: Leaflet 0.4.5 released, containing a small but important zoom animation bugfix for upcoming Chrome 23+ (currently beta) and IE10. Work on future 0.5 release goes on!
author: Vladimir Agafonkin
authorsite: http://agafonkin.com/en
---
### 0.4.5 release
While we contrinue working on the next major release (0.5), today we decided to release **Leaflet 0.4.5**. It contains only one small but important bugfix for **wonky zoom animation** on upcoming **Chrome 23** (currently in beta and to be released in a couple of weeks) and **Internet Explorer 10** (that will eventually hit Windows 7 in addition to Windows 8).
Everyone is encouraged to upgrade (before Chrome 23 turns stable). As always, you can find CDN links and downloads for the new release on the [download page](../../../download.html).
### Plans for 0.5
As Leaflet approaches feature-complete state and API stabilization, we naturally shift our focus from new features towards performance and usability improvements, better browser and device support, bugfixes and internal refactoring to make certain parts of Leaflet (like projections and vector rendering) easier to extend and customize for plugin developers and advanced users.
Highlights of things already implemented in the `master` branch include touch interaction support for **IE10 touch devices and Metro apps** and a more smooth and responsive panning inertia. Follow the [full changelog](https://github.com/Leaflet/Leaflet/blob/master/CHANGELOG.md) for more details.
We're also in the process of a major refactoring of vector rendering code to allow much simpler extension of base functionality with custom shapes, additional rendering systems (like WebGL in addition to existing SVG/VML and Canvas renderers), easy switching between renderers, also making the code simpler and easier to understand.
The same goes for projection-related code to make using Leaflet with non-standard projections easier, inluding plain projections for game and indoor maps. Thanks to these changes, in addition to making advanced GIS folks happier, we'll see much more awesome Leaflet projects like [interactive Skyrim map on IGN](http://www.ign.com/wikis/the-elder-scrolls-5-skyrim/interactive-maps/Skyrim) or [World of Warcraft map on Wowhead](http://www.wowhead.com/map).
Another important task for upcoming weeks is working more closely with plugin developers. In particular, one of the areas of focus will be the [Leaflet.draw](https://github.com/jacobtoye/Leaflet.draw) plugin that will soon become a state-of-the-art map vector drawing/editing solution, just as Dave's [Leaflet.markercluster](https://github.com/danzel/Leaflet.markercluster) became the best marker clustering solution among all mapping platforms out there.
The current plan is to release 0.5 stable sometime in mid-November. Stay tuned!
### Contributing to Leaflet
Leaflet is a true open source project, so we're always happy to meet new contributors, accept patches and bugreports. To help others become involved with Leaflet development and make managing contributions easier, I've put up a [Contributing to Leaflet](https://github.com/Leaflet/Leaflet/blob/master/CONTRIBUTING.md) guide with best practices and advices &mdash; check it out!
Thanks to everyone! Leaflet has got quite an amazing community which makes me really proud. Keep it up!
Cheers,<br />
Vladimir, Leaflet author and maintainer.

View File

@ -0,0 +1,24 @@
---
layout: post
title: Leaflet 0.5 Released
description: Leaflet 0.5 released &mdash; with IE10 touch support, retina-enabled markers, better panning inertia, new zoom control and about a hundred of other improvements and bugfixes!
author: Vladimir Agafonkin
authorsite: http://agafonkin.com/en
---
Rejoice, everyone &mdash; after 4.5 months of development with [26 contributors involved](https://github.com/Leaflet/Leaflet/graphs/contributors?from=2012-08-30&to=2013-01-17&type=c) since the previous major release, I'm happy to announce the release of Leaflet 0.5 stable, hooray!
0.5 highlights include IE10 touch devices and Metro apps support, retina-enabled markers, a much better panning inertia implementation, hand cursors for dragging and a new zoom control design. But the real power of this release comes with about a hundred of subtle improvements and bugfixes, improving usability, performance and overall "feel" of browsing the map even further.
As always, you can find CDN links and downloads for the new release on the [download page](../../../download.html).
The huge detailed list of changes is documented in the [changelog](https://github.com/Leaflet/Leaflet/blob/master/CHANGELOG.md). Be sure to read the "Breaking Changes" part of it before upgrading to avoid any issues! The [API reference](../../../reference.html) was updated to accomodate all the changes too.
In other news, [Leaflet repository](https://github.com/Leaflet/Leaflet) has moved to [its own GitHub organization](https://github.com/Leaflet), along with the two of the most important plugins &mdash; [Leaflet.markercluster](https://github.com/Leaflet/Leaflet.markercluster) and [Leaflet.draw](https://github.com/Leaflet/Leaflet.draw). As some of you have noticed, this is one of the clues to a really nice upcoming announcement about Leaflet future &mdash; stay tuned. :)
Thanks to everyone! It's absolutely breathtaking to see what the Leaflet community has achieved over the last months with all the contributions, amazing projects and demos, and I'm honestly proud to be a part of it.
P.S. I also heard in a dream that everyone who tweets about the new Leaflet release will get an incredible luck boost for the next month. Sounds like true to me.
Cheers,<br />
Vladimir, Leaflet creator and maintainer.

View File

@ -0,0 +1,146 @@
---
layout: post
title: Leaflet.draw 0.2 Released
description: Leaflet.draw 0.2 released &mdash; brings vector drawing and editing tools to your Leaflet map.
author: Jacob Toye
authorsite: https://github.com/jacobtoye/
---
_This is a guest post from Jacob Toye, an active Leaflet contributor and also the author of the most sophisticated vector drawing and editing plugin out there, which is presented in this post._
[Leaflet.draw](https://github.com/Leaflet/Leaflet.draw/) was born from the need to provide users with the ability draw polygons on the map. Leaflet already provided a very nice way of editing existing polylines and polygons. The logical next step was to expand on this functionality to allow the creation of these layers, and ultimately the other vector layers.
Upon release the immediate response from the Leaflet community was very positive. It became clear that the next step would be progressing this tool to a state where users could edit and delete shapes in addition to creating them. This is ultimately what Leaflet.draw 0.2 set out to do.
After a few months of off and on development, with most of this spare time kindy sponsored by my employer <a href="http://www.smartrak.co.nz" title="GPS Fleet Management solutions" target="_blank">Smartrak</a>, we proudly present Leaflet.draw 0.2 -- your one stop plugin for drawing, editing and deleting vectors and markers on Leaflet maps. :)
_Note from Vladimir: the polyline/polygon editing functionality from Leaflet core has been moved into this plugin where it fits much better. The plugin in turn has moved into [Leaflet organization on GitHub](https://github.com/Leaflet) and is now officially supported by the Leaflet development team. Note that version 0.2 currently depends on Leaflet master (in-progress development version) to work._
You can download the latest version from the <a href="https://github.com/Leaflet/Leaflet.draw/" target="_blank">github repo</a>. Please report any bugs you come across on the <a href="https://github.com/Leaflet/Leaflet.draw/issues" target="_blank">issues page</a>.
<div id="map" class="map" style="height: 288px"></div>
{:#plugin-features}
### Features
Leaflet.draw is designed to not only be easy for end users to use, but also for developers to integrate.
* Draw shapes on your map with easy to use drawing tools.
* Edit and delete vectors and markers.
* Super customizable:
* Customize the styles of each shape to fit in with your maps theme.
* Pick and choose the which tools you want to use.
* Roll your own by simply using the drawing and editing handlers.
* Event based system allows you to perform any necessary actions when shapes are created, edited or deleted.
### How to use
Leaflet.draw is very simple to drop into you Leaflet application. The following example will add both the draw and edit toolbars to a map:
// create a map in the "map" div, set the view to a given place and zoom
var map = L.map('map').setView([175.30867, -37.77914], 13);
// add an OpenStreetMap tile layer
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
// Initialize the FeatureGroup to store editable layers
var drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
// Initialize the draw control and pass it the FeatureGroup of editable layers
var drawControl = new L.Control.Draw({
edit: {
featureGroup: drawnItems
}
});
map.addControl(drawControl);
#### Handling newly created layers
Once you have successfully added the Leaflet.draw plugin your map you will want to respond to the different actions users can trigger.
map.on('draw:created', function (e) {
var type = e.layerType,
layer = e.layer;
if (type === 'marker') {
// Do marker specific actions
}
// Do whatever else you need to. (save to db, add to map etc)
drawnItems.addLayer(layer);
});
map.on('draw:edited', function () {
// Update db to save latest changes.
});
map.on('draw:deleted', function () {
// Update db to save latest changes.
});
See the <a href="https://github.com/Leaflet/Leaflet.draw" target="_blank">Leaflet.draw README</a> for more details on how to configure the plugin.
### Thanks
First and foremost I would like to thank my employer <a href="http://www.smartrak.co.nz" title="GPS Fleet Management solutions" target="_blank">Smartrak</a>. Without their attitude to open source software I would not have had the time to complete this plugin.
The Leaflet developer community have been great in supporting this plugin through inspiration, pull requests and issue reports. Special thanks to: <a href="https://github.com/mourner" title="@mourner" target="_blank">@mourner</a>, <a href="https://github.com/danzel" title="@danzel" target="_blank">@danzel</a>, <a href="https://github.com/brunob" title="@brunob" target="_blank">@brunob</a>, <a href="https://github.com/tnightingale" title="@tnightingale" target="_blank">@tnightingale</a>, <a href="https://github.com/Starefossen" title="@Starefossen" target="_blank">@Starefossen</a>, and <a href="https://github.com/shramov" title="@shramov" target="_blank">@shramov</a>.
### Closing
I've had a great time implementing this plugin. I hope you enjoy using it. If you have a question or just want to say hi, send me an email at <a href="mailto:jacob.toye@gmail.com">jacob.toye@gmail.com</a>.
Cheers,
Jacob Toye
<link rel="stylesheet" href="http://leaflet.github.com/Leaflet.draw/lib/leaflet/leaflet.css" />
<link rel="stylesheet" href="http://leaflet.github.com/Leaflet.draw/leaflet.draw.css" />
<!--[if lte IE 8]>
<link rel="stylesheet" href="http://leaflet.github.com/Leaflet.draw/lib/leaflet/leaflet.ie.css" />
<link rel="stylesheet" href="http://leaflet.github.com/Leaflet.draw/leaflet.draw.ie.css" />
<![endif]-->
<script src="http://leaflet.github.com/Leaflet.draw/libs/leaflet/leaflet.js"></script>
<script src="http://leaflet.github.com/Leaflet.draw/leaflet.draw.js"></script>
<style>
.leaflet-bar {
border: none;
}
</style>
<script>
// create a map in the "map" div, set the view to a given place and zoom
var map = L.map('map').setView([-37.77914, 175.30867], 16);
// add an OpenStreetMap tile layer
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
// Initialize the FeatureGroup to store editable layers
var drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
// Initialize the draw control and pass it the FeatureGroup of editable layers
var drawControl = new L.Control.Draw({
edit: {
featureGroup: drawnItems
}
});
map.addControl(drawControl);
map.on('draw:created', function (e) {
var type = e.layerType,
layer = e.layer;
if (type === 'marker') {
layer.bindPopup('A popup!');
}
// Do whatever else you need to. (save to db, add to map etc)
drawnItems.addLayer(layer);
});
</script>

View File

@ -0,0 +1,31 @@
---
layout: post
title: Leaflet 0.6 Released, Code Sprint in DC with MapBox
description: Leaflet 0.6 released &mdash; with nicer controls, better usability and tons of API improvements and various bugfixes &mdash; more than 120 changes! The first ever Leaflet Code Sprint happening in Washington, DC with the MapBox team
author: Vladimir Agafonkin
authorsite: http://agafonkin.com/en
---
_Leaflet 0.6 released &mdash; with nicer controls, better usability and tons of API improvements and various bugfixes &mdash; more than 120 changes! The first ever Leaflet Code Sprint happening in Washington, DC with the MapBox team..._
After 5 months of active development with [36 contributors involved](https://github.com/Leaflet/Leaflet/graphs/contributors?from=2013-01-18&to=2013-06-26&type=c) since the previous major version, today I'm excited to finally announce the **release of Leaflet 0.6** stable.
0.6 highlights include nicer controls, lots of interaction usability improvements, many new API methods, events and options, ability to save layers as [GeoJSON](http://en.wikipedia.org/wiki/GeoJSON), much better test infrastructure and TONS of bugfixes that made Leaflet significantly more reliable. Checkout the huge detailed list of changes (**120+ total**!) [in the changelog](https://github.com/Leaflet/Leaflet/blob/master/CHANGELOG.md). The [API reference](../../../reference.html) was also updated to reflect all these changes.
The final push for the release (last 2 days) was a part of the first ever **Leaflet Code Sprint**, organized in Washington DC by the amazing [MapBox](http://mapbox.com), a company responsible for perhaps the greatest innovations and awesome tools in the geospatial world of recent years, now [using Leaflet for its JS API](mapbox.com/blog/mapbox-js-with-leaflet/) too. The sprint will go on for a week and there are many more awesome improvements to come in upcoming days (and lots of partying as well).
On a related note, even GitHub itself is now [using Leaflet for GeoJSON visualizations](https://github.com/blog/1541-geojson-rendering-improvements), along with [Leaflet.markercluster](github.com/Leaflet/Leaflet.markercluster) & MapBox tiles! How cool is that?
Special thanks go to [Universal Mind](http://universalmind.com/), my awesome employer and sponsor of Leaflet development for the past 5 months, to the most active contributors &mdash; [John Firebaugh](https://github.com/jfirebaugh) and [Tom MacWright](https://github.com/tmcw) of [MapBox](http://mapbox.com), [Dave Leaver](https://github.com/danzel) and [Jacob Toye](https://github.com/jacobtoye) of [Smartrak](http://www.smartrak.co.nz/), [Steve Kashishian](https://github.com/snkashis) of [First Mile Geo](http://www.firstmilegeo.com/), and to everyone else involved in contributions, bug reports, mailing list, Twitter, making awesome apps, etc. You're such an amazing community! I'm really happy to be a part of it.
Grab the CDN links or downloads for the new release on the [download page](../../../download.html) as always. Enjoy! And be sure try it out and report any regressions in your apps so that we can patch them up immediately.
**update** (June 27): 0.6.1 hotfix released with a couple of regressions fixed (particularly the one with FF scroll-zooming too fast).<br>
**update** (June 28): 0.6.2 hotfix released with a couple more minor issues fixed.<br>
**update** (July 17): 0.6.3 released with lots of regressions and bugs fixed.<br>
**update** (July 25): 0.6.4 released with a fix to 0.6.3 regression.
P.S. Everyone who tweets/posts about the new Leaflet release or why he loves Leaflet over the next few days will get a karma boost of over 9000 points. I heard that from a passing monk in Georgetown yesterday, true story!
Cheers,<br />
Vladimir, Leaflet creator and maintainer.

View File

@ -0,0 +1,111 @@
---
layout: post
title: Leaflet Plugin Authoring Guide
description: A number of best practices and tips for publishing your own perfect Leaflet plugin
author: Vladimir Agafonkin
authorsite: http://agafonkin.com/en
---
One of the greatest things about Leaflet is its powerful plugin ecosystem.
The [Leaflet plugins page](http://leafletjs.com/plugins.html) lists dozens of awesome plugins, and more are being added every week.
This guide lists a number of best practices for publishing a Leaflet plugin that meets the quality standards of Leaflet itself. Also available [in the repo](https://github.com/Leaflet/Leaflet/blob/master/PLUGIN-GUIDE.md).
### Presentation
#### Repository
The best place to put your Leaflet plugin to is a separate [GitHub](http://github.com) repository.
If you create a collection of plugins for different uses,
don't put them in one repo &mdash;
it's usually easier to work with small, self-contained plugins in individual repositories.
#### Demo
The most essential thing to do when publishing a plugin is to include a demo that showcases what the plugin does &mdash;
it's usually the first thing people will look for.
The easiest way to put up a demo is using [GitHub Pages](http://pages.github.com/).
A good [starting point](https://help.github.com/articles/creating-project-pages-manually) is creating a `gh-pages` branch in your repo and adding an `index.html` page to it &mdash;
after pushing, it'll be published as `http://<user>.github.io/<repo>`.
#### Readme
The next thing you need to have is a descriptive `README.md` in the root of the repo (or a link to a website with a similar content).
At a minimum it should contain the following items:
- name of the plugin
- a simple, concise description of what it does
- requirements
- Leaflet version
- other external dependencies (if any)
- browser / device compatibility
- links to demos
- instructions for including the plugin
- simple usage code example
- API reference (methods, options, events)
#### License
Every open source repository should include a license.
If you don't know what open source license to choose for your code,
[MIT License](http://opensource.org/licenses/MIT) and [BSD 2-Clause License](http://opensource.org/licenses/BSD-2-Clause) are both good choices.
You can either put it in the repo as a `LICENSE` file or just link to the license from the Readme.
### Code
#### File Structure
Keep the file structure clean and simple,
don't pile up lots of files in one place &mdash;
make it easy for a new person to find their way in your repo.
A barebones repo for a simple plugin would look like this:
my-plugin.js
README.md
An example of a file structure for a more sophisticated plugin:
/src JS source files
/dist minified plugin JS, CSS, images
/spec test files
/examples HTML examples of plugin usage
README.md
LICENSE
package.json
#### Code Conventions
Everyone's tastes are different, but it's important to be consistent with whatever conventions you choose for your plugin.
For a good starting point, check out [Airbnb JavaScript Guide](https://github.com/airbnb/javascript).
Leaflet follows pretty much the same conventions
except for using smart tabs (hard tabs for indentation, spaces for alignment)
and putting a space after the `function` keyword.
#### Plugin API
Never expose global variables in your plugin.<br>
If you have a new class, put it directly in the `L` namespace (`L.MyPlugin`).<br>
If you inherit one of the existing classes, make it a sub-property (`L.TileLayer.Banana`).<br>
If you want to add new methods to existing Leaflet classes, you can do it like this: `L.Marker.include({myPlugin: …})`.
Function, method and property names should be in `camelCase`.<br>
Class names should be in `CapitalizedCamelCase`.
If you have a lot of arguments in your function, consider accepting an options object instead (putting default values where possible so that users don't need specify all of them):
// bad
marker.myPlugin('bla', 'foo', null, {}, 5, 0);
// good
marker.myPlugin('bla', {
optionOne: 'foo',
optionThree: 5
});
And most importantly, keep it simple. Leaflet is all about *simplicity*.
Cheers,<br>
Vladimir.

View File

@ -0,0 +1,56 @@
---
layout: post
title: Leaflet 0.7 Release, MapBox and Plans for Future
description: Leaflet 0.7 Released &mdash; with IE11 touch support, upscaling tiles and tons of other improvements and bugfixes! Meanwhile, I've joined the MapBox team full-time.
author: Vladimir Agafonkin
authorsite: http://agafonkin.com/en
---
_Leaflet 0.7 Released &mdash; with IE11 touch support, upscaling tiles and tons of other improvements and bugfixes! Meanwhile, I've joined the MapBox team full-time..._
After another 5 months of active development with [lots of contributors involved](https://github.com/Leaflet/Leaflet/graphs/contributors?from=2013-06-27&to=2013-11-18&type=c), I'm happy to announce the **release of Leaflet 0.7** stable.
This is a bugfix-heavy release &mdash; as Leaflet becomes more and more stable feature-wise, the focus shifts towards stability, usability and API improvements over new features. I've also been holding back some of the planned deep refactorings (which I'll talk about later in the post) until 0.7 is released, so that the heavy risky stuff is done at the beginning of the release cycle, leaving plenty of room to catch bugs and incompatible changes that can unintentionally break existing apps.
### Joining MapBox
In other news, I [joined the MapBox team full-time](https://www.mapbox.com/blog/vladimir-agafonkin-joins-mapbox/). This is extremely exciting for me, as this was my dream job for quite a while &mdash; [MapBox](https://www.mapbox.com) have changed the world of interactive mapping forever with all their amazing work, having some of the greatest geomapping engineers and designers of the world working together, pushing the boundaries of what's possible and inspiring others every day.
For Leaflet, this can only mean very good things &mdash; much more time on Leaflet development, more enthusiasm, more play, more crazy experiments with maps (like [this one](https://www.mapbox.com/blog/dynamic-hill-shading/)), and lots of learning. I'm now one of the happiest map geeks ever. Stay tuned for tons of awesome!
### 0.7 changes
You can check out the [detailed changelog](https://github.com/Leaflet/Leaflet/blob/master/CHANGELOG.md#07-dev-master) of what's already done over the recent months for 0.7 (about 90 improvements and bugfixes), but I'd like to mention some highlights:
* Added the ability to **upscale tiles** to higher zoom levels (e.g. have zoom 19-20 when the source has 18 max).
* Added support for **IE11 touch devices**. MS unexpectedly broke their pointer API compatibility between Developer Preview and final IE11 release, and we eventually rewrote quite a bit of code to make everything work smoothly across all IE versions (both dekstop & mobile), fixing a bunch of IE10 bugs along the way as well.
* Officially **dropped IE6 support** (nobody cares anyway) and cleaned up/fixed IE7-8 styles.
* Dropped the need for **IE conditional comment** when including Leaflet, making the snippet much simpler &mdash; all IE7/8-specific styles got simplified and moved to the main `leaflet.css` file.
* Fixed an **obscure iOS7 memory leak** that crashed Safari when you tried to create several thousands of layers (e.g. markers for clustering). I still don't understand why it happens, but we managed to fix it with a bit of trickery.
* Fixed a critical **Chrome for Android** bug that made the tiles disappear after zooming on some devices.
* Removed some **Earth-related hardcode** in TileLayer implementation to make it easier for plugins like Proj4Leaflet to handle complex projections without horrible hacks. Some other work in this direction to follow in 0.8.
* Improved **panning performance** on complex pages with significant number of elements &mdash; we found out that simple things like setting a different cursor to `document` (for a "grabbing" hand) caused noticeable performance hit on some browsers (Chrome in particular).
* **Changed the way maxBounds works**, not enforcing a derived `minZoom` from it but restricting panning across lower zoom levels, along with some tricks to make it play better with panning inertia or offset zooming, etc.
### Plans for 0.8
There are several big undertakings in refactoring Leaflet that I'd want to switch to immediately after releasing 0.7 &mdash; I've been holding them off for too long, and they'll be extremely beneficial for plugin and Leaflet-based API authors. Some of them are already in progress.
* Refactoring the **layers** architecture. Currently there's a lot of duplication of logic across implementation of different layers (map, markers, vector layers, etc.), specifically event handling, zoom animation logic, zIndex and pane handling (what appears on top of what etc.). Making the code consistent, more universal and shared across different layers will make it much easier to customize layers and make your own (e.g. integrate d3, etc.)
* Splitting the huge TileLayer implementation into **GridLayer and TileLayer**, separating image tiles-related logic and grid-logic that will make other grid-like layer implementations (e.g. UTFGrid interaction or tiled GeoJSON) much simpler.
* Refactoring **zoom animation logic** to make the long-awaited Easey-style animations (zoom-panning between points) possible.
* Refactoring **projections** code to make it easier to set up flat maps and weird projections and customize how Leaflet handles them.
* Refactoring the **vector layers** code to make it possible to use different rendering backends (Canvas, SVG, etc.) for different layers on the same map and switch between them easily. This will also open it up for interesting extensions, like indexing layers with [RBush](https://github.com/mourner/rbush) for fast interaction features.
While it's an ambitious plan and it may take more than one stable release, finishing all those refactorings will mean that Leaflet is getting ready for a 1.0 release.
Another direction I'd like to focus on after releasing 0.7 is **website and documentation improvements**. First, Leaflet is begging for **more step-by-step tutorials** (with more advanced features like custom layers, custom controls, etc.), and I'd love to do a docs/tutorials sprint some time in future. Second, the presentation could be significantly improved &mdash; adding a prominent visual **showcase** or app gallery, making Leaflet users more prominent with some logos and quotes/testimonials, and updating the layout/design for a more stylish, clean look, etc.
Hope that gives a good glimpse of the stuff to expect from Leafet in near future, and don't hesitate to ask any questions in comments &mdash; I'll be happy to answer!
Grab the CDN links or downloads for the new release on the [download page](../../../download.html) as always. Be sure to try it out on your apps and report any regressions so that we can patch them up immediately. And lets make some nice Twitter buzz about the release as usual!
To all the people wo've been involved in Leaflet contributions, bug reports, mailing list, Twitter buzz, making awesome apps and spreading the word about Leaflet &mdash; thank you! You are the most awesome community ever.
Cheers,<br />
Vladimir.

View File

@ -0,0 +1,21 @@
---
layout: post
title: Leaflet is Alive and Kicking, Stay Tuned for 1.0!
description: We're on the finishing line of releasing Leaflet 1.0 &mdash; the biggest and greatest Leaflet release ever. Meanwhile, I'm happy to present you the new redesigned Leaflet website!
author: Vladimir Agafonkin
authorsite: http://agafonkin.com/en
---
I know this blog hasn't been updated for a long time &mdash; 1.5 years actually! But that's just because I'm a lazy blogger, and there has been _a lot_ going on with Leaflet during this time despite the lack of blog posts and major releases.
We're on the finishing line of releasing Leaflet 1.0 &mdash; the biggest and greatest Leaflet release _ever_. The latest stable version, 0.7.3, is already perfect, so you won't believe how much awesome stuff we've managed to pack into the upcoming release &mdash; 914 commits later! But I'll leave that for a separate `1.0-beta1` blog post after we fix [that one last issue](https://github.com/Leaflet/Leaflet/pull/3307).
Meanwhile, I'm happy to present you the new redesigned [Leaflet website](http://leafletjs.com/)! Now finally mobile-friendly, simple, clean, minimal and modern, just like the library itself. Also notice the floating menu when scrolling down the [Docs](/reference.html) and [Plugins](/plugins.html) pages, a highly requested feature that'll make navigation much easier. Big thanks to [Rowan Hogan](https://github.com/rowanhogan) for the help with the new design!
P.S. I recently made a quirky 13-minute video for the [Geospatial World Forum](http://www.geospatialworldforum.org/), sharing the fun story behind Leaflet and how it became what it is today. Watch it and share it with your geofriends so that we can make the GIS world fun again!
Love,<br />
Vladimir.
<iframe width="640" height="480" src="https://www.youtube.com/embed/NLbyHffKQuU" frameborder="0" allowfullscreen></iframe>

View File

@ -0,0 +1,60 @@
---
layout: post
title: Announcing Leaflet 1.0 beta 1
description: Leaflet 1.0 beta 1 released. It's the biggest Leaflet release ever, with tons of improvements and bugfixes. We're starting a short beta release cycle, and need your help testing the release.
author: Vladimir Agafonkin
authorsite: http://agafonkin.com/en
---
Over the past year, we set out on an ambitious quest to implement pretty much all the features Leaflet users have been asking for years, while heavily focusing on performance, code cleanup and stabilizing the API. It was an extremely challenging road with many bumps, but now we're finally approaching the finish line.
Today, I'm happy and proud to announce the release of *Leaflet 1.0 beta 1*, our first formal release after more than a year of work and a thousand commits by 36 contributors.
### What's new
1.0 will be the best Leaflet release ever, bringing a _huge_ amount of improvements and bugfixes. Highlights of the release include:
- _huge_ performance improvements, especially for vector layers
- flyover animations (zooming and panning in a curve with `map.flyTo`)
- fractional zoom level support (`map.setZoom(12.34)`)
- much nicer tile loading with less flickering
- custom pane management (including multiple vector layer panes)
- better support for non-standard projections
- more accessibility features
- lots of bugfixes and stability improvements
A much more detailed list of changes can be found [in the changelog](https://github.com/Leaflet/Leaflet/blob/master/CHANGELOG.md) (beware, it's a long read).
![](https://camo.githubusercontent.com/07c492b230f1a3762118eaf457f0cc182fb0a98d/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f32353339352f313936353934392f32613934343166342d383263312d313165332d393836372d6230343033663266643966372e676966)
### Beta cycle and upgrading
The release sports a number of minor breaking API changes, and some of the plugins will have to be updated. To make the upgrade less painful, we're doing a short beta cycle before the final 1.0 to allow users and plugin developers to catch up to the changes while we find and fix remaining issues.
A lot of effort since the last stable release has been put into refactoring. Many changes that we made are not visible to users, but make the source code much simpler and easier to understand and also open up many new possibilities for our wonderful community of plugin developers. Basically, half of Leaflet code was fully rewritten under the hood, and now the codebase is ready for some pretty extreme extensions (who just said "rotation" and "WebGL"?).
We plan to write a comprehensive 1.0 upgrade guide before the release. Meanwhile, if something breaks after you upgrade to 1.0-beta, please look through the changelog. If you can't find the corresponding breaking change, please file a GitHub issue.
The API reference for 1.0 is temporarily [available here](http://mourner.github.io/Leaflet/reference.html). It's built from Leaflet `gh-pages-master` branch &mdash; fixes and additions are welcome!
### Get the new release
Test out the new release on your app, and help us catch remaining issues to bring the final 1.0 close to perfection!
You can use our CDN:
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-1.0.0-b1/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-1.0.0-b1/leaflet.js"></script>
The release is also available through NPM, Bower, and [GitHub download](https://github.com/Leaflet/Leaflet/archive/v1.0.0-beta.1.zip).
### Thank you
I'm incredibly thankful to everyone who made this release possible &mdash; by using the library, spreading the word about it, reporting issues and sending your contributions. Your help is invaluable!
Special thanks to [Iván Sánchez](https://github.com/IvanSanchez), [Yohan Boniface](https://github.com/yohanboniface), [John Firebaugh](https://github.com/jfirebaugh), [Dave Leaver](https://github.com/danzel), [Patrick Arlt](https://github.com/patrickarlt), [Per Liedman](https://github.com/perliedman), [Jake Wilson](https://github.com/Jakobud) and [Steve Kashishian](https://github.com/snkashis) for lots of amazing contributions and support throughout the last year. All these people are now a part of the core Leaflet team. Keep'em coming!
![](http://www.reactiongifs.com/r/msy.gif)
Love,<br />
Vladimir.

View File

@ -0,0 +1,29 @@
---
layout: post
title: Leaflet 0.7.5 Release
description: Leaflet 0.7.5 released, containing bugfixes and backports.
author: Iván Sánchez Ortega
---
While the Leaflet development team is busy with the 1.0 betas, there have been a few bugs affecting 0.7.3, important enough to spend some effort in porting a fix back. They are not much, though:
- Workarounds for issues derived from new browsers (touch-capable browsers, tile loading in recent Chrome)
- Backport fixes for styling and events for canvas-based vector layers
- Fix edge cases involving `maxZoom`, `minZoom`, `maxNativeZoom` on tile layers and popup events
- Revert a regression bug in 0.7.4 which conflicted with marker clusters
The detailed list of changes can be found [in the changelog](https://github.com/Leaflet/Leaflet/blob/master/CHANGELOG.md#074-sep-01-2015)
The fact that it has been over *a year and half* since the last stable release should be a testament of the quality and stability of the Leaflet API. If you think that development of Leaflet 1.0 is taking a long time, remember that we want to keep the same level of quality for the final 1.0 release.
The 0.7.x releases will not implement new features. Stay tuned for more news on the 1.0 beta releases instead!
### Get the update
Developers using Leaflet 0.7.3 are advised to upgrade to 0.7.5 to prevent problems arising from modern browers.
The release is also available through NPM, Bower, [direct download](http://cdn.leafletjs.com/downloads/leaflet-0.7.5.zip), or through our CDN:
<link rel="stylesheet" href="cdn.leafletjs.com/leaflet-0.7.5/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7.5/leaflet.js"></script>

View File

@ -0,0 +1,35 @@
---
layout: post
title: Announcing Leaflet 1.0 beta 2
description: Leaflet 1.0 beta 2 released, fixing over 50 bugs over the previous beta.
author: Iván Sánchez
authorsite: http://ivan.sanchezortega.es
---
Since the 1.0.0-beta1 release a couple months ago, the Leaflet team has been busy fixing bugs reported by users of beta1, plus a few small changes to the API that were overlooked previously. You can find the complete list of fixes and changes in the [1.0.0-beta2 changelog](https://github.com/Leaflet/Leaflet/blob/master/CHANGELOG.md#10-beta2-october-14-2015).
### Get the new release
As with previous releases, you can use our CDN:
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v1.0.0-beta.2/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet/v1.0.0-beta.2/leaflet.js"></script>
The release is also available through NPM (`npm install leaflet@beta`), Bower, and [GitHub download](https://github.com/Leaflet/Leaflet/archive/v1.0.0-beta.2.zip).
The API reference for 1.0 is still temporarily [available here](http://mourner.github.io/Leaflet/reference.html).
### The future
Work is not yet done, though. There will probably be a beta3, sporting bugfixes in the tile loading algorithm, API methods for fractional zoom and documentation improvements, among other pending items.
We hope to have fixed the most problematic bugs in the previous beta, but maybe there is a bug that we are not aware of. We encourage users of 1.0.0-beta1 to upgrade to beta2 and keep reporting problems.
Help us help you by taking a minute to learn [how to write a good bug report](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html), and check if a [similar issue](https://github.com/Leaflet/Leaflet/issues) has already been reported. Or better even, dive into the Leaflet code if you can!
Last but not least, huge thanks to everybody using Leaflet. Keep creating great maps!
**Note to plugin developers**: we encourage you to upgrade your plugins to be compatible with the latest beta release. The 1.0 API is pretty stable at this point and many users are starting to use the beta version in production. Additionally, as 1.0 final release approaches, we want to get more serious about the quality of plugins that get [on the official list](http://leafletjs.com/plugins.html), making sure they're maintained and compatible with recent Leaflet releases.
Best,
Iván & Vladimir & Yohan.

View File

@ -0,0 +1,101 @@
---
layout: post
title: Debugging touch interactions
description: To debug Leaflet, sometimes you need to create a new tool.
author: Iván Sánchez
authorsite: http://ivan.sanchezortega.es
---
Most of the time, fixing bugs in the Leaflet code is a breeze. The code is simple, easy to read (for the most part) and well structured. Code conventions and unit tests make it easy for newcomers to try some modifications to the core code. During the past few months we've sent a few simple bug reports to the folks at [Your First PR](https://yourfirstpr.github.io/) - we love to see first-timers contributing fixes to Leaflet!
Some of the difficulties of maintaining/developing a javascript library like Leaflet is making sure that everything works on every major browser out there. A technique that works on Firefox on a Ubuntu desktop might result in glitches in Safari on a Macbook; something that works in Edge on Windows 10 might break completely in Chrome on Android.
Fortunately, all of the browser-specific hacks in Leaflet can be easily seen by looking at the [references to `L.Browser`](https://github.com/search?q=Browser+repo%3ALeaflet%2FLeaflet+language%3AJavaScript+extension%3Ajs+path%3A%2Fsrc&ref=searchresults&type=Code&utf8=%E2%9C%93) in the code.
This can lead to somewhat [undesirable code](https://github.com/Leaflet/Leaflet/blob/master/src/dom/DomEvent.DoubleTap.js#L65) sometimes:
<pre><code class="javascript"> // On some platforms (notably, chrome on win10 + touchscreen + mouse),
// the browser doesn't fire touchend/pointerup events but does fire
// native dblclicks. See #4127.
if (!L.Browser.edge) {
obj.addEventListener('dblclick', handler, false);
}
</code></pre>
I've been told more than a few times by browser developers that browser sniffing is wrong, and that feature detection is right. I mean, detecting 3D CSS transforms and HTML5 `<video>` support is easy, but there is no (sane) way to detect if a browser fires a `dblclick` event by itself when double-tapping a touchscreen.
Debugging touch interactions is particularly tricky. Sometimes the conditions to reproduce a touch-interaction bug is simple (double-tap the touchscreen in the same spot), but sometimes they are more specific. In [#3798](https://github.com/Leaflet/Leaflet/issues/3798) and [#3814](https://github.com/Leaflet/Leaflet/issues/3814) the conditions are "drag with one finger, then put down another finger and pinch", and in [#3530](https://github.com/Leaflet/Leaflet/issues/3530) it's "pinch in until `maxZoom` is reached, then do a two-finger drag".
The problem with this kind of bugs is that they're **frustrating** and **time-consuming** to reproduce under controlled conditions. Imagine having a code editor and a browser debugger when at the same time using two hands to perform a very specific touch gesture while watching the debugger. Then you want to inspect a variable in the debugger but you cannot move your fingers even a pixel because that will run more code and change the state.
And then, for the fifth time in the last hour, the wobbly phone charger connector wobbles again, and the debugger disconnects, and you have to start all over again.
<table class="image">
<!-- <caption align="bottom"><small></small></caption> -->
<tr><td style='text-align:center'><img src="https://i.chzbgr.com/full/4896152320/h3FAAE99E/" alt="rage quit"/></td></tr>
</table>
If I had an extra hand or two, debugging touch interactions would be much simpler, but biotechnology is still far away from allowing me to grow an extra hand.
Fortunately, we can leverage [dispatching custom events to the browser](https://developer.mozilla.org/docs/Web/API/EventTarget/dispatchEvent). Normally, when we use a mouse (or a touchpad, or a touchscreen, or a digitizer tablet), the web browser will generate a [`MouseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent) (or a [`TouchEvent`](https://developer.mozilla.org/docs/Web/API/TouchEvent) or a [`PointerEvent`](https://developer.mozilla.org/docs/Web/API/PointerEvent)). But instead of that, we javascript programmers can create a synthetic (i.e. fake) event, then throw it to the browser so it can dispatch it to whatever code is listening for an event.
Unfortunately creating and dispatching such events is cumbersome. A touch gesture involves *at least* 4 to 8 events in a particular order, with particular data, with a particular timing. There have been a few attempts to automate this (the best I could find was the [hammer.js simulator](https://github.com/hammerjs/simulator)), but there is no good way of emulating complex custom touch gestures.
Until now.
I'm proud to introduce [**prosthetic-hand**](https://github.com/Leaflet/prosthetic-hand), for all you javascript debugging needs that require you to have an extra hand.
With prosthetic-hand, I can now automate a pinch-zoom gesture in a Leaflet webpage:
<table class="image">
<caption align="bottom"><small>You get to see my disembodied fingers as a bonus</small></caption>
<tr><td style='text-align:center'><img src="/docs/images/2016-03-20-prosthetic-hand-zooming.gif" alt="Animated screenshot of prosthetic-hand zooming in and out"/></td></tr>
</table>
With this library loaded, just ask for an extra hand (with a specific timing mode):
<pre><code class="javascript">var h = new Hand({ timing: 'frame' });
</code></pre>
Then grow some fingers:
<pre><code class="javascript">var f1 = h.growFinger('touch');
var f2 = h.growFinger('touch');
</code></pre>
Then move the fingers around (using pixel coordinates and milliseconds):
<pre><code class="javascript">f1.wait(100).moveTo(250, 200, 0)
.down().wait(500).moveBy(-200, 0, 1000).wait(500).up().wait(500)
.down().wait(500).moveBy( 200, 0, 1000).wait(500).up().wait(500);
f2.wait(100).moveTo(350, 200, 0)
.down().wait(500).moveBy( 200, 0, 1000).wait(500).up().wait(500)
.down().wait(500).moveBy(-200, 0, 1000).wait(500).up().wait(500);
</code></pre>
You can check this in the [live prosthetic-hand demos](http://leaflet.github.io/prosthetic-hand/demos/).
The prosthetic-hand library is not perfect, and some types of events only work in some browsers, but it can help trigger mouse/touch/pointer events in a repeatable way, with adjustable timing, allowing developers to keep both hands at the debugger. The timing modes allow granular control of the events fired, allowing to run less iterations of the code for the same gesture, which in turn means a simpler, better understanding of what's going on.
---
A famous quote (often [misattributed to Abraham Lincoln](http://quoteinvestigator.com/2014/03/29/sharp-axe/)) says:
<blockquote>A woodsman was once asked, “What would you do if you had just five minutes to chop down a tree?” He answered, “I would spend the first two and a half minutes sharpening my axe.”</blockquote>
Web development is no different - having the right tools will make your task so much easier.
It's not just a matter of time. Maybe writing a tool from scratch was time-consuming, but the best gain is that debugging **stops being frustrating**. Before, it was "use a hand on the touchscreen, look closely at the debugger, don't use breakpoints because you don't have enough hands". Now it's "change the timing on the prosthetic-hand events, set a breakpoint, *boom*".
And what's even better, having an automated tool means that Leaflet now has [**unit tests for touch interactions**](https://github.com/Leaflet/Leaflet/blob/master/spec/suites/map/handler/Map.TouchZoomSpec.js). The PhantomJS headless web browser can understand the `TouchEvent`s that prosthetic-hand generates, and can check if a map behaves as expected when that gesture is performed.
The amount of time and headaches we'll save in Leaflet by having automated touch tests is going to be huge. We can only hope more projects will benefit from similar automated testing.
---
Don't just write open-source code. Make better tools for everybody.
Yours,
Iván

View File

@ -0,0 +1,78 @@
---
layout: post
title: Announcing Leaflet 1.0-rc1
description: Leaflet 1.0 Release Candidate 1 ready
author: Iván Sánchez
authorsite: http://ivan.sanchezortega.es
---
The road to Leaflet 1.0 continues - we're proud to get the first release candidate for 1.0 into the wild.
Leaflet 1.0-rc1 closes down on edge cases and API inconsistencies that were present in beta2. The full list of changes is in the [1.0.0-rc1 changelog](https://github.com/Leaflet/Leaflet/blob/master/CHANGELOG.md#10-rc1-april-18-2016)) as usual, with about 50 bugfixes and a dozen improvements and minor API changes.
### Notable changes
* Fractional zoom controls: In beta2, developers could set a fractional zoom level only by code, running e.g. `map.setZoom(8.5)`. Now the map has options (`zoomSnap` and `zoomDelta`) to let the user navigate through fractional zoom levels.
* Better handling of vector layers when using the `<canvas>` renderer, when layers are non-interactive and lines are dashed.
* The first ever Microsoft Edge hack (handle inconsistent `dblclick` behaviour on Win10 touchscreens)
* Unit tests with `prosthetic-hand`, letting us be sure that touch interactions behave consistently. This has its [own blog post](http://leafletjs.com/2016/03/20/debugging-touch-interactions.html).
### Changes in the API documentation
The API documentation is now generated from docstrings, thanks to a new tool dubbed [🍂doc](https://github.com/Leaflet/Leafdoc) (or "leafdoc").
Previously, the API documentation was edited manually. This involved a lot of copy-pasting and - over time - bits of code started not to match the documentation.
Most complex software projects use some form of [docstrings](https://en.wikipedia.org/wiki/Docstring) and tools like [JavaDoc](https://en.wikipedia.org/wiki/Javadoc), [NaturalDocs](http://www.naturaldocs.org/) or [JSdoc](http://usejsdoc.org/) to convert the docstrings into webpages.
But the documentation for Leaflet requires a few special bits - docstrings cover methods and properties, but they do not cover options nor events, and we wanted to maintain the current look and feel of the documentation. 🍂doc was then born to overcome these limitations.
Leaflet uses class inheritance quite extensively, and the old documentation was sometimes not clear about it. Some users struggled to find the available methods for some of the classes, and inherited options were sometimes mentioned, sometimes not. 🍂doc fixes this by including the documentation of all inherited methods/options/events/properties, collapsed by default:
![Collapsed inheritances for L.Polygon](/docs/images/2016-04-18-inheritances.gif)
The [build system](https://github.com/Leaflet/Leaflet/blob/master/CONTRIBUTING.md#setting-up-the-build-system) now builds a HTML file with the API docs alongside the minified `leaflet.js` file. Documentation will be updated on every release based on that file, and pull requests to the `gh-pages` branch to fix the documentation will be automatically rejected.
### Get the release candidate
As with previous releases, you can use our CDN:
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v1.0.0-rc.1/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet/v1.0.0-rc.1/leaflet.js"></script>
A non-minified version of the javascript file is also available as:
<script src="http://cdn.leafletjs.com/leaflet/v1.0.0-rc.1/leaflet-src.js"></script>
The release is also available through NPM (`npm install leaflet@rc`), [GitHub download](https://github.com/Leaflet/Leaflet/archive/v1.0.0-rc.1.zip), and [CDN download](http://cdn.leafletjs.com/leaflet/v1.0.0-rc.1/leaflet.zip). We discourage using Bower.
### The team in person
This Release Candidate leapt forward when most of the Leaflet team met in Madrid for a weekend to fix bugs and discuss architectural decisions, and whether some big features should make it to 1.0 or be postponed.
<table class="image">
<caption align="bottom"><small>This photograph <em>might</em> have been digitally altered to include somebody who couldn't come to Madrid that weekend.</small></caption>
<tr><td style='text-align:center'><img src="/docs/images/2016-04-18-madrid-leaflet-864px.jpg" alt="The Leaflet team in Madrid"/></td></tr>
</table>
<table class="image">
<caption align="bottom"><small>Iván and Yohan want to extend a special thanks to the roll of toilet paper.</small></caption>
<tr><td style='text-align:center'><img src="/docs/images/2016-04-18-leaflet-toilet-paper.jpeg" alt="The Leaflet team in Madrid" width="864"/></td></tr>
</table>
We enjoyed meeting in person and fighting bugs together. It proved to be a very productive thing to do, as about 20 issues were closed that day. Hopefully another in-person meeting will happen soon, with another release!
We hope you enjoy Leaflet 1.0-rc1 as much as we did coding it!
Best,
Iván & Vladimir & Yohan & Per & Zsolt.

View File

@ -0,0 +1,60 @@
---
layout: post
title: Announcing Leaflet 1.0-rc2
description: Leaflet 1.0 Release Candidate 2 is out
author: Yohan Boniface
authorsite: http://yohanboniface.me
---
Here comes the second release candidate for Leaflet 1.0, the most stable Leaflet version ever!
Leaflet 1.0-rc2 is mainly bug fixing, with two notable exceptions. The full list of changes is in the [1.0.0-rc2 changelog](https://github.com/Leaflet/Leaflet/blob/master/CHANGELOG.md#10-rc2-july-18-2016) as usual.
### Notable changes
* Event refactoring: thanks to an initial work from [@fab1an](https://github.com/fab1an), coordinated by [@perliedman](https://github.com/perliedman), the events are greatly optimized: they are faster, and consume less memory.
* New `L.Tooltip` class: started as a port of Leaflet.Label plugin to Leaflet core, and then reworked, this new class allows to display small tooltips attached to map features. The API is very similar to what Leaflet.Label was (with some exceptions in [options naming and default values](https://github.com/Leaflet/Leaflet.label#upgrade-path-to-ltooltip)), so the upgrade path from Leaflet.Label to `L.Tooltip` should be straightforward, and we encourage you to do so while upgrading your Leaflet to 1.0.
![L.Tooltip](/docs/images/2016-07-18-tooltip.png)
More in the [1.0.0-rc2 changelog](https://github.com/Leaflet/Leaflet/blob/master/CHANGELOG.md#10-rc2-july-18-2016).
## What's left for 1.0.0-final
The Leaflet team is very happy about the progress from rc1 to rc2, but not all features were tackled.
Notably, the scroll zoom with an Apple Magic Mouse has proven to be very tricky to debug (especially since not all members of the team have access to one). Getting a good experience when scroll-zooming with this particular device had been planned for rc2 but ultimately it was pushed back for 1.0.0-final.
While there are no big features planned, a few but [mischievous and tricky bugs are left](https://github.com/Leaflet/Leaflet/milestone/21) - such as subpixel offset, CSS trickery, zoom vibration.
### Leafdays
The core team being spread all over Europe, we are doing so called "Leafdays" from time to time to remotely work together during one full day. Here is a debug session with [@perliedman](https://github.com/perliedman) screen sharing:
![Remote session](/docs/images/2016-07-18-remote-session.png)
Next face-to-face session will be during [FOSS4G](http://2016.foss4g.org/) in Bonn, in August, and we hope to see you there. Will this be the final 1.0 release session?
### Get the release candidate
As with previous releases, you can use the CDN:
<link rel="stylesheet" href="https://npmcdn.com/leaflet@1.0.0-rc.2/dist/leaflet.css" />
<script src="https://npmcdn.com/leaflet@1.0.0-rc.2/dist/leaflet.js"></script>
A non-minified version of the javascript file is also available as:
<script src="https://npmcdn.com/leaflet@1.0.0-rc.2/dist/leaflet-src.js"></script>
The release is also available through NPM (`npm install leaflet@rc`), [GitHub download](https://github.com/Leaflet/Leaflet/archive/v1.0.0-rc.2.zip), and [CDN download](http://cdn.leafletjs.com/leaflet/v1.0.0-rc.2/leaflet.zip). We discourage using Bower.
Use it, enjoy it, and please report any [issue](https://github.com/Leaflet/Leaflet/issues) to help preparing the final Leaflet 1.0 release!
Best,
The "Leafteam"

View File

@ -0,0 +1,53 @@
---
layout: post
title: Announcing Leaflet 1.0-rc3
description: Leaflet 1.0 Release Candidate 3 is out
author: Yohan Boniface
authorsite: http://yohanboniface.me
---
A regression in the way event listeners were called pushed the Leaflet team to freeze a new release candidate, so here is the third one.
### Bug fixing, bug fixing, bug fixing!
The previous release candidate landed an event refactoring and the new `L.Tooltip` class, and, how bizarre,
almost all the fixes in this release are related to those two changes!
The main regression affected the way Leaflet was calling the event listeners: the order we were calling the listeners was not the same they have been registered.
Before the rc2, Leaflet was handling differently listeners with and without explicit context. The former were always called before the later, no matter the order they were registered, but their order was unpredictable. In the meantime, listeners without explicit context, while always called after the other ones, were called in registration order.
While in the task of refactoring events for rc2, in order to make them faster, we also factorized those pieces of code. But we did it the wrong way!
This third release is then about making all the listeners behave in a predictable way. While this is a clear improvement, it may have side effects in corner cases. So be warry when upgrading!
Nothing more to highlight about this quick fixup release, check the [1.0.0-rc3 changelog](https://github.com/Leaflet/Leaflet/blob/master/CHANGELOG.md#10-rc3-august-3-2016) for the full list of changes.
### Summer hacking
Releasing during summer, while all the team is having a break, has some funny side effects. This release was mainly done while traveling, by train and airplane.
And partly in some small village in Iraq under 53° Celsius!
![Iraq hacking](/docs/images/2016-08-03-iraq-hacking.jpg)
### Get the release candidate
As with previous releases, you can use the CDN:
<link rel="stylesheet" href="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.css" />
<script src="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.js"></script>
A non-minified version of the javascript file is also available at:
<script src="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet-src.js"></script>
The release is also available through NPM (`npm install leaflet@rc`), [GitHub download](https://github.com/Leaflet/Leaflet/archive/v1.0.0-rc.3.zip), and [CDN download](http://cdn.leafletjs.com/leaflet/v1.0.0-rc.3/leaflet.zip). We discourage using Bower.
Use it, enjoy it, and please report any [issue](https://github.com/Leaflet/Leaflet/issues) to help preparing the final Leaflet 1.0 release!
Best,
The "Leafteam"

29
docs/atom.xml Normal file
View File

@ -0,0 +1,29 @@
---
title: Leaflet Developer Blog Atom Feed
---
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Leaflet Dev Blog</title>
<link href="http://leafletjs.com/atom.xml" rel="self"/>
<link href="http://leafletjs.com"/>
<updated>{{ site.time | date_to_xmlschema }}</updated>
<id>http://leafletjs.com/</id>
<author>
<name>Vladimir Agafonkin</name>
</author>
{% for post in site.posts %}
<entry>
<title>{{ post.title }}</title>
<link href="http://leafletjs.com{{ post.url }}"/>
<updated>{{ post.date | date_to_xmlschema }}</updated>
<id>http://leafletjs.com{{ post.id }}</id>
<content type="html">{{ post.content | xml_escape }}</content>
</entry>
{% endfor %}
</feed>

24
docs/blog.md Normal file
View File

@ -0,0 +1,24 @@
---
layout: v2
title: Blog
bodyclass: blog-page
---
## Leaflet Developer Blog
The main place for all important Leaflet-related news, tutorials, tips and development notes. [Subscribe to Atom feed](atom.xml)
---
{% for post in site.posts %}
<div class="clearfix">
<div class="post-date">
{{ post.date | date_to_string }}
</div>
<div class="post-info">
<h3 class="post-title"><a href="{{ post.url | replace_first: '/', '' }}">{{ post.title }}</a></h3>
<p>{{ post.description }} <span class="quiet">&hellip;</span></p>
</div>
</div>
{% unless forloop.last %}<hr />{% endunless %}
{% endfor %}

1082
docs/docs/css/main.css Normal file

File diff suppressed because it is too large Load Diff

426
docs/docs/css/normalize.css vendored Normal file
View File

@ -0,0 +1,426 @@
/*! normalize.css v3.0.1 | MIT License | git.io/normalize */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS text size adjust after orientation change, without disabling
* user zoom.
*/
html {
font-family: sans-serif; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined for any HTML5 element in IE 8/9.
* Correct `block` display not defined for `details` or `summary` in IE 10/11 and Firefox.
* Correct `block` display not defined for `main` in IE 11.
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section,
summary {
display: block;
}
/**
* 1. Correct `inline-block` display not defined in IE 8/9.
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
*/
audio,
canvas,
progress,
video {
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
}
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Address `[hidden]` styling not present in IE 8/9/10.
* Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
*/
[hidden],
template {
display: none;
}
/* Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background: transparent;
}
/**
* Improve readability when focused and also mouse hovered in all browsers.
*/
a:active,
a:hover {
outline: 0;
}
/* Text-level semantics
========================================================================== */
/**
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted;
text-decoration: none;
}
/**
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
*/
b,
strong {
font-weight: bold;
}
/**
* Address styling not present in Safari and Chrome.
*/
dfn {
font-style: italic;
}
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Address styling not present in IE 8/9.
*/
mark {
background: #ff0;
color: #000;
}
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* Embedded content
========================================================================== */
/**
* Remove border when inside `a` element in IE 8/9/10.
*/
img {
border: 0;
}
/**
* Correct overflow not hidden in IE 9/10/11.
*/
svg:not(:root) {
overflow: hidden;
}
/* Grouping content
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari.
*/
figure {
margin: 1em 40px;
}
/**
* Address differences between Firefox and other browsers.
*/
hr {
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0;
}
/**
* Contain overflow in all browsers.
*/
pre {
overflow: auto;
}
/**
* Address odd `em`-unit font size rendering in all browsers.
*/
code,
kbd,
pre,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
/* Forms
========================================================================== */
/**
* Known limitation: by default, Chrome and Safari on OS X allow very limited
* styling of `select`, unless a `border` property is set.
*/
/**
* 1. Correct color not being inherited.
* Known issue: affects color of disabled elements.
* 2. Correct font properties not being inherited.
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
*/
button,
input,
optgroup,
select,
textarea {
color: inherit; /* 1 */
font: inherit; /* 2 */
margin: 0; /* 3 */
}
/**
* Address `overflow` set to `hidden` in IE 8/9/10/11.
*/
button {
overflow: visible;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
* Correct `select` style inheritance in Firefox.
*/
button,
select {
text-transform: none;
}
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; /* 2 */
cursor: pointer; /* 3 */
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
input {
line-height: normal;
}
/**
* It's recommended that you don't attempt to style these elements.
* Firefox's implementation doesn't respect box-sizing, padding, or width.
*
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
* `font-size` values of the `input`, it causes the cursor style of the
* decrement button to change from `default` to `text`.
*/
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome
* (include `-moz` to future-proof).
*/
input[type="search"] {
-webkit-appearance: textfield; /* 1 */
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box; /* 2 */
box-sizing: content-box;
}
/**
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
* Safari (but not Chrome) clips the cancel button when the search input has
* padding (and `textfield` appearance).
*/
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* Define consistent border, margin, and padding.
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/**
* 1. Correct `color` not being inherited in IE 8/9/10/11.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
}
/**
* Remove default vertical scrollbar in IE 8/9/10/11.
*/
textarea {
overflow: auto;
}
/**
* Don't inherit the `font-weight` (applied by a rule above).
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
*/
optgroup {
font-weight: bold;
}
/* Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}
td,
th {
padding: 0;
}

View File

@ -0,0 +1,24 @@
Copyright (c) 2006, Ivan Sagalaev
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of highlight.js nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,211 @@
/**
* GitHub Gist Theme
* Author : Louis Barranqueiro - https://github.com/LouisBarranqueiro
*/
.hljs {
display: block;
background:#f8f8f8;
padding: 0.5em;
color: #333333;
overflow-x: auto;
-webkit-text-size-adjust: none;
}
.hljs-comment,
.bash .hljs-shebang,
.java .hljs-javadoc,
.javascript .hljs-javadoc {
color: #969896;
}
.hljs-string,
.apache .hljs-sqbracket,
.coffeescript .hljs-subst,
.coffeescript .hljs-regexp,
.cpp .hljs-preprocessor,
.c .hljs-preprocessor,
.javascript .hljs-regexp,
.json .hljs-attribute,
.makefile .hljs-variable,
.markdown .hljs-value,
.markdown .hljs-link_label,
.markdown .hljs-strong,
.markdown .hljs-emphasis,
.markdown .hljs-blockquote,
.nginx .hljs-regexp,
.nginx .hljs-number,
.objectivec .hljs-preprocessor .hljs-title,
.perl .hljs-regexp,
.php .hljs-regexp,
.xml .hljs-value,
.less .hljs-built_in,
.scss .hljs-built_in {
color: #df5000;
}
.hljs-keyword,
.css .hljs-at_rule,
.css .hljs-important,
.http .hljs-request,
.ini .hljs-setting,
.java .hljs-javadoctag,
.javascript .hljs-tag,
.javascript .hljs-javadoctag,
.nginx .hljs-title,
.objectivec .hljs-preprocessor,
.php .hljs-phpdoc,
.sql .hljs-built_in,
.less .hljs-tag,
.less .hljs-at_rule,
.scss .hljs-tag,
.scss .hljs-at_rule,
.scss .hljs-important,
.stylus .hljs-at_rule,
.go .hljs-typename,
.swift .hljs-preprocessor {
color: #a71d5d;
}
.apache .hljs-common,
.apache .hljs-cbracket,
.apache .hljs-keyword,
.bash .hljs-literal,
.bash .hljs-built_in,
.coffeescript .hljs-literal,
.coffeescript .hljs-built_in,
.coffeescript .hljs-number,
.cpp .hljs-number,
.cpp .hljs-built_in,
.c .hljs-number,
.c .hljs-built_in,
.cs .hljs-number,
.cs .hljs-built_in,
.css .hljs-attribute,
.css .hljs-hexcolor,
.css .hljs-number,
.css .hljs-function,
.http .hljs-literal,
.http .hljs-attribute,
.java .hljs-number,
.javascript .hljs-built_in,
.javascript .hljs-literal,
.javascript .hljs-number,
.json .hljs-number,
.makefile .hljs-keyword,
.markdown .hljs-link_reference,
.nginx .hljs-built_in,
.objectivec .hljs-literal,
.objectivec .hljs-number,
.objectivec .hljs-built_in,
.php .hljs-literal,
.php .hljs-number,
.python .hljs-number,
.ruby .hljs-prompt,
.ruby .hljs-constant,
.ruby .hljs-number,
.ruby .hljs-subst .hljs-keyword,
.ruby .hljs-symbol,
.sql .hljs-number,
.puppet .hljs-function,
.less .hljs-number,
.less .hljs-hexcolor,
.less .hljs-function,
.less .hljs-attribute,
.scss .hljs-preprocessor,
.scss .hljs-number,
.scss .hljs-hexcolor,
.scss .hljs-function,
.scss .hljs-attribute,
.stylus .hljs-number,
.stylus .hljs-hexcolor,
.stylus .hljs-attribute,
.stylus .hljs-params,
.go .hljs-built_in,
.go .hljs-constant,
.swift .hljs-built_in,
.swift .hljs-number {
color: #0086b3;
}
.apache .hljs-tag,
.cs .hljs-xmlDocTag,
.css .hljs-tag,
.xml .hljs-title,
.stylus .hljs-tag {
color: #63a35c;
}
.bash .hljs-variable,
.cs .hljs-preprocessor,
.cs .hljs-preprocessor .hljs-keyword,
.css .hljs-attr_selector,
.css .hljs-value,
.ini .hljs-value,
.ini .hljs-keyword,
.javascript .hljs-tag .hljs-title,
.makefile .hljs-constant,
.nginx .hljs-variable,
.xml .hljs-tag,
.scss .hljs-variable {
color: #333333;
}
.bash .hljs-title,
.coffeescript .hljs-title,
.cpp .hljs-title,
.c .hljs-title,
.cs .hljs-title,
.css .hljs-id,
.css .hljs-class,
.css .hljs-pseudo,
.ini .hljs-title,
.java .hljs-title,
.javascript .hljs-title,
.makefile .hljs-title,
.objectivec .hljs-title,
.perl .hljs-sub,
.php .hljs-title,
.python .hljs-decorator,
.python .hljs-title,
.ruby .hljs-parent,
.ruby .hljs-title,
.xml .hljs-attribute,
.puppet .hljs-title,
.less .hljs-id,
.less .hljs-pseudo,
.less .hljs-class,
.scss .hljs-id,
.scss .hljs-pseudo,
.scss .hljs-class,
.stylus .hljs-class,
.stylus .hljs-id,
.stylus .hljs-pseudo,
.stylus .hljs-title,
.swift .hljs-title,
.diff .hljs-chunk {
color: #795da3;
}
.coffeescript .hljs-reserved,
.coffeescript .hljs-attribute {
color: #1d3e81;
}
.diff .hljs-chunk {
font-weight: bold;
}
.diff .hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.diff .hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.markdown .hljs-link_url {
text-decoration: underline;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
docs/docs/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
docs/docs/images/logos.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

BIN
docs/docs/images/mobile.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 KiB

BIN
docs/docs/images/sprite.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="400"
height="200"
id="svg3550"
version="1.1"
inkscape:version="0.48.2 r9819"
sodipodi:docname="New document 9">
<defs
id="defs3552" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="8.9263916"
inkscape:cx="14.748401"
inkscape:cy="150.23988"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:snap-global="false">
<inkscape:grid
type="xygrid"
id="grid3558"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata3555">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-852.36218)">
<path
style="color:#000000;fill:#4e4e4e;fill-opacity:0.94117647;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 14,857.36218 c -0.51124,0 -1.01451,0.20201 -1.40625,0.59375 L 11,859.54968 c 0.70051,0 1.3332,0.25386 1.84375,0.65625 l 0.4375,-0.4375 c 0.19587,-0.19587 0.46313,-0.3125 0.71875,-0.3125 0.25562,0 0.52288,0.11663 0.71875,0.3125 l 1.0625,1.0625 c 0.39174,0.39174 0.39174,1.04576 0,1.4375 l -1.0625,1.0625 -1.5,1.5 c -0.39174,0.39174 -1.04576,0.39174 -1.4375,0 l -1.0625,-1.0625 c -0.0772,-0.0772 -0.10948,-0.1877 -0.15625,-0.28125 l -1.3125,1.3125 1.84375,1.84375 c 0.78347,0.78347 2.02903,0.78347 2.8125,0 l 3.6875,-3.6875 c 0.783469,-0.78347 0.783469,-2.02903 0,-2.8125 l -2.1875,-2.1875 C 15.01451,857.56419 14.51124,857.36218 14,857.36218 z m -3,3 c -0.51124,0 -1.01451,0.20201 -1.40625,0.59375 l -3.6875,3.6875 c -0.78347,0.78347 -0.78347,2.02903 0,2.8125 l 2.1875,2.1875 c 0.78347,0.78347 2.02903,0.78347 2.8125,0 L 12.5,868.04968 c -0.70051,0 -1.3332,-0.25386 -1.84375,-0.65625 l -0.4375,0.4375 c -0.39174,0.39174 -1.04576,0.39174 -1.4375,0 l -1.0625,-1.0625 c -0.39174,-0.39174 -0.39174,-1.04576 0,-1.4375 l 1.0625,-1.0625 1.5,-1.5 c 0.19587,-0.19587 0.46313,-0.3125 0.71875,-0.3125 0.25562,0 0.52288,0.11663 0.71875,0.3125 l 1.0625,1.0625 c 0.0772,0.0772 0.10948,0.1877 0.15625,0.28125 l 1.3125,-1.3125 -1.84375,-1.84375 C 12.01451,860.56419 11.51124,860.36218 11,860.36218 z"
id="rect4010"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4044"
d="m 14,877.36218 c -0.51124,0 -1.01451,0.20201 -1.40625,0.59375 L 11,879.54968 c 0.70051,0 1.3332,0.25386 1.84375,0.65625 l 0.4375,-0.4375 c 0.19587,-0.19587 0.46313,-0.3125 0.71875,-0.3125 0.25562,0 0.52288,0.11663 0.71875,0.3125 l 1.0625,1.0625 c 0.39174,0.39174 0.39174,1.04576 0,1.4375 l -1.0625,1.0625 -1.5,1.5 c -0.39174,0.39174 -1.04576,0.39174 -1.4375,0 l -1.0625,-1.0625 c -0.0772,-0.0772 -0.10948,-0.1877 -0.15625,-0.28125 l -1.3125,1.3125 1.84375,1.84375 c 0.78347,0.78347 2.02903,0.78347 2.8125,0 l 3.6875,-3.6875 c 0.783469,-0.78347 0.783469,-2.02903 0,-2.8125 l -2.1875,-2.1875 C 15.01451,877.56419 14.51124,877.36218 14,877.36218 z m -3,3 c -0.51124,0 -1.01451,0.20201 -1.40625,0.59375 l -3.6875,3.6875 c -0.78347,0.78347 -0.78347,2.02903 0,2.8125 l 2.1875,2.1875 c 0.78347,0.78347 2.02903,0.78347 2.8125,0 L 12.5,888.04968 c -0.70051,0 -1.3332,-0.25386 -1.84375,-0.65625 l -0.4375,0.4375 c -0.39174,0.39174 -1.04576,0.39174 -1.4375,0 l -1.0625,-1.0625 c -0.39174,-0.39174 -0.39174,-1.04576 0,-1.4375 l 1.0625,-1.0625 1.5,-1.5 c 0.19587,-0.19587 0.46313,-0.3125 0.71875,-0.3125 0.25562,0 0.52288,0.11663 0.71875,0.3125 l 1.0625,1.0625 c 0.0772,0.0772 0.10948,0.1877 0.15625,0.28125 l 1.3125,-1.3125 -1.84375,-1.84375 C 12.01451,880.56419 11.51124,880.36218 11,880.36218 z"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
inkscape:connector-curvature="0"
id="path6649"
d="m 14,897.36218 c -0.51124,0 -1.01451,0.20201 -1.40625,0.59375 L 11,899.54968 c 0.70051,0 1.3332,0.25386 1.84375,0.65625 l 0.4375,-0.4375 c 0.19587,-0.19587 0.46313,-0.3125 0.71875,-0.3125 0.25562,0 0.52288,0.11663 0.71875,0.3125 l 1.0625,1.0625 c 0.39174,0.39174 0.39174,1.04576 0,1.4375 l -1.0625,1.0625 -1.5,1.5 c -0.39174,0.39174 -1.04576,0.39174 -1.4375,0 l -1.0625,-1.0625 c -0.0772,-0.0772 -0.10948,-0.1877 -0.15625,-0.28125 l -1.3125,1.3125 1.84375,1.84375 c 0.78347,0.78347 2.02903,0.78347 2.8125,0 l 3.6875,-3.6875 c 0.783469,-0.78347 0.783469,-2.02903 0,-2.8125 l -2.1875,-2.1875 C 15.01451,897.56419 14.51124,897.36218 14,897.36218 z m -3,3 c -0.51124,0 -1.01451,0.20201 -1.40625,0.59375 l -3.6875,3.6875 c -0.78347,0.78347 -0.78347,2.02903 0,2.8125 l 2.1875,2.1875 c 0.78347,0.78347 2.02903,0.78347 2.8125,0 L 12.5,908.04968 c -0.70051,0 -1.3332,-0.25386 -1.84375,-0.65625 l -0.4375,0.4375 c -0.39174,0.39174 -1.04576,0.39174 -1.4375,0 l -1.0625,-1.0625 c -0.39174,-0.39174 -0.39174,-1.04576 0,-1.4375 l 1.0625,-1.0625 1.5,-1.5 c 0.19587,-0.19587 0.46313,-0.3125 0.71875,-0.3125 0.25562,0 0.52288,0.11663 0.71875,0.3125 l 1.0625,1.0625 c 0.0772,0.0772 0.10948,0.1877 0.15625,0.28125 l 1.3125,-1.3125 -1.84375,-1.84375 C 12.01451,900.56419 11.51124,900.36218 11,900.36218 z"
style="color:#000000;fill:#7b7b7b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

52
docs/docs/js/docs.js Normal file
View File

@ -0,0 +1,52 @@
var tocCopy = document.createElement('div');
tocCopy.id = 'toc-copy';
var toc = document.querySelector('#toc');
if (toc) {
tocCopy.innerHTML = toc.innerHTML;
document.getElementsByClassName('container')[0].appendChild(tocCopy);
var menus = document.querySelectorAll('#toc-copy ul');
for (var i = 0; i < menus.length; i++) {
menus[i].addEventListener('mouseover', function() {
this.previousElementSibling.classList.add('hover')
});
menus[i].addEventListener('mouseout', function() {
this.previousElementSibling.classList.remove('hover')
});
}
var labels = document.querySelectorAll('#toc-copy h4');
for (var i = 0; i < labels.length; i++) {
labels[i].addEventListener('click', function() {
this.classList.toggle('active')
});
}
tocCopy.addEventListener('click', function(e) {
if (e.target.nodeName != 'H4') {
this.classList.toggle('active');
}
});
var scrollPos = function scrollPos () {
var scroll = window.scrollY;
if (scroll >= (toc.offsetHeight + toc.offsetTop)) {
document.body.classList.add('scrolled');
} else {
document.body.classList.remove('scrolled');
}
}
scrollPos();
window.addEventListener('scroll', function(e) {
scrollPos();
});
}

86
docs/download.md Normal file
View File

@ -0,0 +1,86 @@
---
layout: v2
title: Download
bodyclass: download-page
---
## Download Leaflet
<table>
<tr>
<th>Version</th>
<th>Description</th>
</tr>
<tr>
<td class="width100"><a href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.zip">Leaflet 0.7.7</a></td>
<td>Stable version, released on November 18, 2013 and last updated on October 26, 2015.</td>
</tr>
<tr>
<td><a href="http://cdn.leafletjs.com/leaflet/v1.0.0-rc.3/leaflet.zip">Leaflet 1.0.0-rc3</a></td>
<td>Last 1.0 release candidate, released on August 5, 2016.</td>
</tr>
<tr>
<td><a href="https://leafletjs-cdn.s3.amazonaws.com/content/leaflet/master/leaflet.zip">Leaflet 1.0-dev</a></td>
<td>In-progress version, developed on the <code>master</code> branch.</td>
</tr>
</table>
[View Changelog](https://github.com/Leaflet/Leaflet/blob/master/CHANGELOG.md)
Note that the master version can contain incompatible changes,
so please read the changelog carefully when upgrading to it.
### Using a Hosted Version of Leaflet
The latest stable Leaflet release is hosted on a CDN &mdash; to start using
it straight away, place this in the `head` of your HTML code:
<link rel="stylesheet" href="https://npmcdn.com/leaflet@0.7.7/dist/leaflet.css" />
<script src="https://npmcdn.com/leaflet@0.7.7/dist/leaflet.js"></script>
or
<link rel="stylesheet" href="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.css" />
<script src="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.js"></script>
### Using a Downloaded Version of Leaflet
Inside the archives downloaded from the above links, you will see four things:
- `leaflet.js` - This is the minified Leaflet JavaScript code.
- `leaflet-src.js` - This is the readable, unminified Leaflet JavaScript, which is sometimes helpful for debugging.
- `leaflet.css` - This is the stylesheet for Leaflet.
- `images` - This is a folder that contains images referenced by `leaflet.css`. It must be in the same directory as `leaflet.css`.
Unzip the downloaded archive to your website's directory and add this to the `head` of your HTML code:
<link rel="stylesheet" href="/path/to/leaflet.css" />
<script src="/path/to/leaflet.js"></script> <!-- or use leaflet-src.js --!>
### Leaflet Source Code
These download packages above only contain the library itself.
If you want to download the full source code, including unit tests, files for debugging, build scripts, etc.,
you can <a href="https://github.com/Leaflet/Leaflet/releases">download it</a>
from the <a href="https://github.com/Leaflet/Leaflet">GitHub repository</a>.
### Building Leaflet from the Source
Leaflet build system is powered by the [Node.js](http://nodejs.org) platform,
which installs easily and works well across all major platforms.
Here are the steps to set it up:
1. [Download and install Node](http://nodejs.org)
2. Run the following commands in the command line:
<pre><code>npm install -g jake
npm install</code></pre>
Now that you have everything installed, run `jake build` inside the Leaflet directory.
This will combine and compress the Leaflet source files, saving the build to the `dist` folder.
### Building a Custom Version of Leaflet
To make a custom build of the library with only the things you need,
open `build/build.html` page of the Leaflet source code contents, choose the components
(it figures out dependencies for you) and then run the command generated with it.

103
docs/examples.md Normal file
View File

@ -0,0 +1,103 @@
---
layout: v2
title: Tutorials
bodyclass: examples
---
## Leaflet Tutorials
Every tutorial here comes with step-by-step code explanation and is easy enough even for beginner JavaScript developers.
***
[<img src="docs/images/quick-start.png" class="example-img bordered-img" />][1]
### [Leaflet Quick Start Guide][1]
A simple step-by-step guide that will quickly get you started with Leaflet basics, including setting up a Leaflet map (with Mapbox tiles) on your page, working with markers, polylines and popups, and dealing with events.
***
[<img src="docs/images/mobile.png" class="example-img" />][2]
### [Leaflet on Mobile][2]
In this tutorial, you'll learn how to create a fullscreen map tuned for mobile devices like iPhone, iPad or Android phones, and how to easily detect and use the current user location.
***
[<img src="docs/images/custom-icons.png" class="example-img bordered-img" />][3]
### [Markers with Custom Icons][3]
In this pretty tutorial, you'll learn how to easily define your own icons for use by the markers you put on the map.
***
[<img src="docs/images/geojson.png" class="example-img bordered-img" />][4]
### [Using GeoJSON with Leaflet][4]
In this tutorial, you'll learn how to create and interact with map vectors created from [GeoJSON][5] objects.
***
[<img src="docs/images/choropleth.png" class="example-img bordered-img" />][7]
### [Interactive Choropleth Map][7]
A case study of creating a colorful interactive [choropleth map](http://en.wikipedia.org/wiki/Choropleth_map) of US States Population Density with GeoJSON and some custom controls. News websites will love this.
***
[<img src="docs/images/layers-control.png" class="example-img bordered-img" />][6]
### [Layer Groups and Layers Control][6]
A tutorial on how to manage groups of layers and use the layer switching control.
***
[<img src="examples/crs-simple/thumbnail.png" class="example-img bordered-img" />][9]
### [Non-geographical maps][9]
A primer on `L.CRS.Simple`, how to make maps with no concept of "latitude" or "longitude".
***
[<img src="examples/wms/thumbnail.png" class="example-img bordered-img" />][10]
### [WMS and TMS][10]
How to integrate with WMS and TMS services from professional GIS software.
***
The following tutorials use features available **only in Leaflet 1.0**:
***
[<img src="docs/images/labels-pane.png" class="example-img bordered-img" />][8]
### [Working with map panes][8]
How the default map panes work to display overlays on top of tiles, and how to override that.
<!--***
<h3><a class="noimpl" href="#">Custom Controls</a></h3>
A brief tutorial on implementing custom map controls.
***
<h3><a class="noimpl" href="#">Custom Overlays</a></h3>
If markers, popups and vectors are not enough for you, here's a guide for creating your own map overlays (things to put on a map).
-->
***
If you find that an important tutorial is missing here, let us know!
[1]: examples/quick-start.html
[2]: examples/mobile.html
[3]: examples/custom-icons.html
[4]: examples/geojson.html
[5]: http://geojson.org/
[6]: examples/layers-control.html
[7]: examples/choropleth.html
[8]: examples/map-panes.html
[9]: examples/crs-simple/crs-simple.html
[10]: examples/wms/wms.html

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,174 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet Layers Control Example</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.css" />
<style>
#map {
width: 800px;
height: 500px;
}
.info {
padding: 6px 8px;
font: 14px/16px Arial, Helvetica, sans-serif;
background: white;
background: rgba(255,255,255,0.8);
box-shadow: 0 0 15px rgba(0,0,0,0.2);
border-radius: 5px;
}
.info h4 {
margin: 0 0 5px;
color: #777;
}
.legend {
text-align: left;
line-height: 18px;
color: #555;
}
.legend i {
width: 18px;
height: 18px;
float: left;
margin-right: 8px;
opacity: 0.7;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.js"></script>
<script type="text/javascript" src="us-states.js"></script>
<script type="text/javascript">
var map = L.map('map').setView([37.8, -96], 4);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpandmbXliNDBjZWd2M2x6bDk3c2ZtOTkifQ._QA7i5Mpkd_m30IGElHziw', {
maxZoom: 18,
attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
'Imagery © <a href="http://mapbox.com">Mapbox</a>',
id: 'mapbox.light'
}).addTo(map);
// control that shows state info on hover
var info = L.control();
info.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'info');
this.update();
return this._div;
};
info.update = function (props) {
this._div.innerHTML = '<h4>US Population Density</h4>' + (props ?
'<b>' + props.name + '</b><br />' + props.density + ' people / mi<sup>2</sup>'
: 'Hover over a state');
};
info.addTo(map);
// get color depending on population density value
function getColor(d) {
return d > 1000 ? '#800026' :
d > 500 ? '#BD0026' :
d > 200 ? '#E31A1C' :
d > 100 ? '#FC4E2A' :
d > 50 ? '#FD8D3C' :
d > 20 ? '#FEB24C' :
d > 10 ? '#FED976' :
'#FFEDA0';
}
function style(feature) {
return {
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7,
fillColor: getColor(feature.properties.density)
};
}
function highlightFeature(e) {
var layer = e.target;
layer.setStyle({
weight: 5,
color: '#666',
dashArray: '',
fillOpacity: 0.7
});
if (!L.Browser.ie && !L.Browser.opera) {
layer.bringToFront();
}
info.update(layer.feature.properties);
}
var geojson;
function resetHighlight(e) {
geojson.resetStyle(e.target);
info.update();
}
function zoomToFeature(e) {
map.fitBounds(e.target.getBounds());
}
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
click: zoomToFeature
});
}
geojson = L.geoJson(statesData, {
style: style,
onEachFeature: onEachFeature
}).addTo(map);
map.attributionControl.addAttribution('Population data &copy; <a href="http://census.gov/">US Census Bureau</a>');
var legend = L.control({position: 'bottomright'});
legend.onAdd = function (map) {
var div = L.DomUtil.create('div', 'info legend'),
grades = [0, 10, 20, 50, 100, 200, 500, 1000],
labels = [],
from, to;
for (var i = 0; i < grades.length; i++) {
from = grades[i];
to = grades[i + 1];
labels.push(
'<i style="background:' + getColor(from + 1) + '"></i> ' +
from + (to ? '&ndash;' + to : '+'));
}
div.innerHTML = labels.join('<br>');
return div;
};
legend.addTo(map);
</script>
</body>
</html>

391
docs/examples/choropleth.md Normal file
View File

@ -0,0 +1,391 @@
---
layout: tutorial
title: Interactive Choropleth Map
css: "#map {
height: 420px;
}
.info {
padding: 6px 8px;
font: 14px/18px Arial, Helvetica, sans-serif;
background: white;
background: rgba(255,255,255,0.8);
box-shadow: 0 0 15px rgba(0,0,0,0.2);
border-radius: 5px;
}
.info h4 {
margin: 0 0 5px;
color: #777;
}
.legend {
text-align: left;
line-height: 18px;
color: #555;
}
.legend i {
width: 18px;
height: 18px;
float: left;
margin-right: 8px;
opacity: 0.7;
}"
---
## Interactive Choropleth Map
This is a case study of creating a colorful interactive [choropleth map](http://en.wikipedia.org/wiki/Choropleth_map) of US States Population Density with the help of [GeoJSON](geojson.html) and some [custom controls](../reference.html#icontrol) (that will hopefully convince all the remaining major news and government websites that do not use Leaflet yet to start doing so).
The tutorial was inspired by the [Texas Tribune US Senate Runoff Results map](http://www.texastribune.org/library/data/us-senate-runoff-results-map/) (also powered by Leaflet), created by [Ryan Murphy](http://www.texastribune.org/about/staff/ryan-murphy/).
<div id="map" class="map"></div>
[View example on a separate page &rarr;](choropleth-example.html)
### Data Source
We'll be creating a visualization of population density per US state. As the amount of data (state shapes and the density value for each state) is not very big, the most convenient and simple way to store and then display it is [GeoJSON](geojson.html).
Each feature of our GeoJSON data ([us-states.js](us-states.js)) will look like this:
{
"type": "Feature",
"properties": {
"name": "Alabama",
"density": 94.65
},
"geometry": ...
...
}
The GeoJSON with state shapes was kindly shared by [Mike Bostock](http://bost.ocks.org/mike) of [D3](http://d3js.org/) fame, extended with density values from [this Wikipedia article](http://en.wikipedia.org/wiki/List_of_U.S._states_by_population_density) based on July 1st 2011 data from [US Census Bureau](http://www.census.gov/) and assigned to `statesData` JS variable.
### Basic States Map
Let's display our states data on a map with a custom Mapbox style for nice grayscale tiles that look perfect as a background for visualizations:
var mapboxAccessToken = {your access token here};
var map = L.map('map').setView([37.8, -96], 4);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=' + mapboxAccessToken, {
id: 'mapbox.light',
attribution: ...
}).addTo(map);
L.geoJson(statesData).addTo(map);
<div id="map2" style="height: 300px"></div>
### Adding Some Color
Now we need to color the states according to their population density. Choosing nice colors for a map can be tricky, but there's a great tool that can help with it --- [ColorBrewer](http://colorbrewer2.org/). Using the values we got from it, we create a function that returns a color based on population density:
function getColor(d) {
return d > 1000 ? '#800026' :
d > 500 ? '#BD0026' :
d > 200 ? '#E31A1C' :
d > 100 ? '#FC4E2A' :
d > 50 ? '#FD8D3C' :
d > 20 ? '#FEB24C' :
d > 10 ? '#FED976' :
'#FFEDA0';
}
Next we define a styling function for our GeoJSON layer so that its `fillColor` depends on `feature.properties.density` property, also adjusting the appearance a bit and adding a nice touch with dashed stroke.
function style(feature) {
return {
fillColor: getColor(feature.properties.density),
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7
};
}
L.geoJson(statesData, {style: style}).addTo(map);
Looks much better now!
<div id="map3" style="height: 300px"></div>
### Adding Interaction
Now let's make the states highlighted visually in some way when they are hovered with a mouse. First we'll define an event listener for layer `mouseover` event:
function highlightFeature(e) {
var layer = e.target;
layer.setStyle({
weight: 5,
color: '#666',
dashArray: '',
fillOpacity: 0.7
});
if (!L.Browser.ie && !L.Browser.opera) {
layer.bringToFront();
}
}
Here we get access to the layer that was hovered through `e.target`, set a thick grey border on the layer as our highlight effect, also bringing it to the front so that the border doesn't clash with nearby states (but not for IE or Opera, since they have problems doing `bringToFront` on `mouseover`).
Next we'll define what happens on `mouseout`:
function resetHighlight(e) {
geojson.resetStyle(e.target);
}
The handy `geojson.resetStyle` method will reset the layer style to its default state (defined by our `style` function). For this to work, make sure our GeoJSON layer is accessible through the `geojson` variable by defining it before our listeners and assigning the layer to it later:
var geojson;
// ... our listeners
geojson = L.geoJson(...);
As an additional touch, let's define a `click` listener that zooms to the state:
function zoomToFeature(e) {
map.fitBounds(e.target.getBounds());
}
Now we'll use the `onEachFeature` option to add the listeners on our state layers:
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
click: zoomToFeature
});
}
geojson = L.geoJson(statesData, {
style: style,
onEachFeature: onEachFeature
}).addTo(map);
This makes the states highlight nicely on hover and gives us the ability to add other interactions inside our listeners.
### Custom Info Control
We could use the usual popups on click to show information about different states, but we'll choose a different route --- showing it on state hover inside a [custom control](../reference.html#icontrol).
Here's the code for our control:
var info = L.control();
info.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
this.update();
return this._div;
};
// method that we will use to update the control based on feature properties passed
info.update = function (props) {
this._div.innerHTML = '<h4>US Population Density</h4>' + (props ?
'<b>' + props.name + '</b><br />' + props.density + ' people / mi<sup>2</sup>'
: 'Hover over a state');
};
info.addTo(map);
We need to update the control when the user hovers over a state, so we'll also modify our listeners as follows:
function highlightFeature(e) {
...
info.update(layer.feature.properties);
}
function resetHighlight(e) {
...
info.update();
}
The control also needs some CSS styles to look nice:
{: .css}
.info {
padding: 6px 8px;
font: 14px/16px Arial, Helvetica, sans-serif;
background: white;
background: rgba(255,255,255,0.8);
box-shadow: 0 0 15px rgba(0,0,0,0.2);
border-radius: 5px;
}
.info h4 {
margin: 0 0 5px;
color: #777;
}
### Custom Legend Control
Creating a control with a legend is easier, since it is static and doesn't change on state hover. JavaScript code:
var legend = L.control({position: 'bottomright'});
legend.onAdd = function (map) {
var div = L.DomUtil.create('div', 'info legend'),
grades = [0, 10, 20, 50, 100, 200, 500, 1000],
labels = [];
// loop through our density intervals and generate a label with a colored square for each interval
for (var i = 0; i < grades.length; i++) {
div.innerHTML +=
'<i style="background:' + getColor(grades[i] + 1) + '"></i> ' +
grades[i] + (grades[i + 1] ? '&ndash;' + grades[i + 1] + '<br>' : '+');
}
return div;
};
legend.addTo(map);
CSS styles for the control (we also reuse the `info` class defined earlier):
{: .css}
.legend {
line-height: 18px;
color: #555;
}
.legend i {
width: 18px;
height: 18px;
float: left;
margin-right: 8px;
opacity: 0.7;
}
Enjoy the result on [the top of this page](#map) or on a [separate page](choropleth-example.html).
<script src="us-states.js"></script>
<script>
var map2 = L.map('map2').setView([37.8, -96], 4);
L.tileLayer(MB_URL, {attribution: MB_ATTR, id: 'mapbox.light'}).addTo(map2);
L.geoJson(statesData).addTo(map2);
var map3 = L.map('map3').setView([37.8, -96], 4);
L.tileLayer(MB_URL, {attribution: MB_ATTR, id: 'mapbox.light'}).addTo(map3);
L.geoJson(statesData, {style: style}).addTo(map3);
var map = L.map('map').setView([37.8, -96], 4);
L.tileLayer(MB_URL, {attribution: MB_ATTR, id: 'mapbox.light'}).addTo(map);
// control that shows state info on hover
var InfoControl = L.Control.extend({
onAdd: function (map) {
this._div = L.DomUtil.create('div', 'info');
this.update();
return this._div;
},
update: function (props) {
this._div.innerHTML = '<h4>US Population Density</h4>' + (props ?
'<b>' + props.name + '</b><br />' + props.density + ' people / mi<sup>2</sup>'
: 'Hover over a state');
}
});
var info = new InfoControl();
info.addTo(map);
// get color depending on population density value
function getColor(d) {
return d > 1000 ? '#800026' :
d > 500 ? '#BD0026' :
d > 200 ? '#E31A1C' :
d > 100 ? '#FC4E2A' :
d > 50 ? '#FD8D3C' :
d > 20 ? '#FEB24C' :
d > 10 ? '#FED976' :
'#FFEDA0';
}
function style(feature) {
return {
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7,
fillColor: getColor(feature.properties.density)
};
}
function highlightFeature(e) {
var layer = e.target;
layer.setStyle({
weight: 5,
color: '#666',
dashArray: '',
fillOpacity: 0.7
});
if (!L.Browser.ie && !L.Browser.opera) {
layer.bringToFront();
}
info.update(layer.feature.properties);
}
var geojson;
function resetHighlight(e) {
geojson.resetStyle(e.target);
info.update();
}
function zoomToFeature(e) {
map.fitBounds(e.target.getBounds());
}
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
click: zoomToFeature
});
}
geojson = L.geoJson(statesData, {
style: style,
onEachFeature: onEachFeature
}).addTo(map);
map.attributionControl.addAttribution('Population data &copy; <a href="http://census.gov/">US Census Bureau</a>');
var legend = L.control({position: 'bottomright'});
legend.onAdd = function (map) {
var div = L.DomUtil.create('div', 'info legend'),
grades = [0, 10, 20, 50, 100, 200, 500, 1000],
labels = [],
from, to;
for (var i = 0; i < grades.length; i++) {
from = grades[i];
to = grades[i + 1];
labels.push(
'<i style="background:' + getColor(from + 1) + '"></i> ' +
from + (to ? '&ndash;' + to : '+'));
}
div.innerHTML = labels.join('<br>');
return div;
};
legend.addTo(map);
</script>

View File

@ -0,0 +1,16 @@
---
layout: tutorial_frame
title: CRS.Simple example
---
<script>
var map = L.map('map', {
crs: L.CRS.Simple
});
var bounds = [[0,0], [1000,1000]];
var image = L.imageOverlay('uqm_map_full.png', bounds).addTo(map);
map.fitBounds(bounds);
</script>

View File

@ -0,0 +1,20 @@
---
layout: tutorial_frame
title: CRS.Simple example
---
<script>
var map = L.map('map', {
crs: L.CRS.Simple,
minZoom: -3
});
var bounds = [[-26.5,-25], [1021.5,1023]];
var image = L.imageOverlay('uqm_map_full.png', bounds).addTo(map);
var sol = L.latLng([ 145, 175 ]);
L.marker(sol).addTo(map);
map.setView( [70, 120], 1);
</script>

View File

@ -0,0 +1,38 @@
---
layout: tutorial_frame
title: CRS.Simple example
---
<script>
var map = L.map('map', {
crs: L.CRS.Simple,
minZoom: -3
});
var yx = L.latLng;
var xy = function(x, y) {
if (L.Util.isArray(x)) { // When doing xy([x, y]);
return yx(x[1], x[0]);
}
return yx(y, x); // When doing xy(x, y);
};
var bounds = [xy(-25, -26.5), xy(1023, 1021.5)];
var image = L.imageOverlay('uqm_map_full.png', bounds).addTo(map);
var sol = xy(175.2, 145.0);
var mizar = xy( 41.6, 130.1);
var kruegerZ = xy( 13.4, 56.5);
var deneb = xy(218.7, 8.3);
L.marker( sol).addTo(map).bindPopup( 'Sol');
L.marker( mizar).addTo(map).bindPopup( 'Mizar');
L.marker(kruegerZ).addTo(map).bindPopup('Krueger-Z');
L.marker( deneb).addTo(map).bindPopup( 'Deneb');
var travel = L.polyline([sol, deneb]).addTo(map);
map.setView(xy(120, 70), 1);
</script>

View File

@ -0,0 +1,117 @@
---
layout: tutorial_v2
title: Non-geographical maps
---
<style>
iframe {
border: 1px solid #ccc;
border-radius: 5px;
}
</style>
## Not of this earth
Sometimes, maps do not represent things on the surface of the earth and, as such, do not have a concept of geographical latitude and geographical longitude. Most times this refers to big scanned images, such as game maps.
For this tutorial we've picked a starmap from Star Control II, a game that is now available as the [open-source project The Ur-Quan Masters](https://en.wikipedia.org/wiki/Star_Control_II#The_Ur-Quan_Masters). These maps were made with a [tool to read the open-source data files](http://www.highprogrammer.com/alan/games/video/uqm/index.html) of the game, and look like this:
<center>
<img src="uqm_map_400px.png" style="border: 1px solid #ccc; border-radius: 5px" /><br/>
</center>
The game has a built-in square coordinate system, as can be seen in the corners. This will allow us to establish a coordinate system.
<center>
<img src="uqm_map_detail.png" style="border: 1px solid #ccc; border-radius: 5px" /><br/>
</center>
## CRS.Simple
**CRS** stands for [coordinate reference system](https://en.wikipedia.org/wiki/Spatial_reference_system), a term used by geographers to explain what the coordinates mean in a coordinate vector. For example, `[15, 60]` represents a point in the Indian Ocean if using latitude-longitude on the earth, or the solar system Krueger-Z in our starmap.
A Leaflet map has one CRS (and *one* CRS *only*), that can be changed when creating the map. For our game map we'll use `CRS.Simple`, which represents a square grid:
var map = L.map('map', {
crs: L.CRS.Simple
});
Then we can just add a `L.ImageOverlay` with the starmap image and its *approximate* bounds:
var bounds = [[0,0], [1000,1000]];
var image = L.imageOverlay('uqm_map_full.png', bounds).addTo(map);
And show the whole map:
map.fitBounds(bounds);
{% include frame.html url="crs-simple-example1.html" %}
This example doesn't quite work, as we cannot see the whole map after doing a `fitBounds()`.
## Common gotchas in CRS.Simple maps
In the default Leaflet CRS, `CRS.Earth`, 360 degrees of longitude are mapped to 256 horizontal pixels (at zoom level 0) and approximately 170 degrees of latitude are mapped to 256 vertical pixels (at zoom level 0).
In a `CRS.Simple`, one horizontal map unit is mapped to one horizontal pixel, and *idem* with vertical. This means that the whole map is about 1000x1000 pixels big and won't fit in our HTML container. Luckily, we can set `minZoom` to values lower than zero:
var map = L.map('map', {
crs: L.CRS.Simple,
minZoom: -5
});
### Pixels vs. map units
One common mistake when using `CRS.Simple` is assuming that the map units equal image pixels. In this case, the map covers 1000x1000 units, but the image is 2315x2315 pixels big. Different cases will call for one pixel = one map unit, or 64 pixels = one map unit, or anything. **Think in map units** in a grid, and then add your layers (`L.ImageOverlay`s, `L.Marker`s and so on) accordingly.
In fact, the image we're using covers more than 1000 map units - there is a sizable margin. Measuring how many pixels there are between the 0 and 1000 coordinates, and extrapolating, we can have the right coordinate bounds for this image:
var bounds = [[-26.5,-25], [1021.5,1023]];
var image = L.imageOverlay('uqm_map_full.png', bounds).addTo(map);
While we're at it, let's add some markers:
var sol = L.latLng([ 145, 175.2 ]);
L.marker(sol).addTo(map);
map.setView( [70, 120], 1);
{% include frame.html url="crs-simple-example2.html" %}
### This is not the `LatLng` you're looking for
You'll notice that Sol is at coordinates `[145,175]` instead of `[175,145]`, and the same happens with the map center. Coordinates in `CRS.Simple` take the form of `[y, x]` instead of `[x, y]`, in the same way Leaflet uses `[lat, lng]` instead of `[lng, lat]`.
<small>(In technical terms, Leaflet prefers to use [`[northing, easting]`](https://en.wikipedia.org/wiki/Easting_and_northing) over `[easting, northing]` - the first coordinate in a coordinate pair points "north" and the second points "east")</small>
The debate about whether `[lng, lat]` or `[lat, lng]` or `[y, x]` or `[x, y]` [is not new, and there is no clear consensus](http://www.macwright.org/lonlat/). This lack of consensus is why Leaflet has a class named `L.LatLng` instead of the more confusion-prone `L.Coordinate`.
If working with `[y, x]` coordinates with something named `L.LatLng` doesn't make much sense to you, you can easily create wrappers for them:
var yx = L.latLng;
var xy = function(x, y) {
if (L.Util.isArray(x)) { // When doing xy([x, y]);
return yx(x[1], x[0]);
}
return yx(y, x); // When doing xy(x, y);
};
Now we can add a few stars and even a navigation line with `[x, y]` coordinates:
var sol = xy(175.2, 145.0);
var mizar = xy( 41.6, 130.1);
var kruegerZ = xy( 13.4, 56.5);
var deneb = xy(218.7, 8.3);
L.marker( sol).addTo(map).bindPopup( 'Sol');
L.marker( mizar).addTo(map).bindPopup( 'Mizar');
L.marker(kruegerZ).addTo(map).bindPopup('Krueger-Z');
L.marker( deneb).addTo(map).bindPopup( 'Deneb');
var travel = L.polyline([sol, deneb]).addTo(map);
The map looks pretty much the same, but the code is a bit more readable:
{% include frame.html url="crs-simple-example3.html" %}

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 KiB

View File

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet Quick Start Guide Example</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.css" />
</head>
<body>
<div id="map" style="width: 600px; height: 400px"></div>
<script src="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.js"></script>
<script>
var map = L.map('map').setView([51.5, -0.09], 13);
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
var LeafIcon = L.Icon.extend({
options: {
shadowUrl: '../docs/images/leaf-shadow.png',
iconSize: [38, 95],
shadowSize: [50, 64],
iconAnchor: [22, 94],
shadowAnchor: [4, 62],
popupAnchor: [-3, -76]
}
});
var greenIcon = new LeafIcon({iconUrl: '../docs/images/leaf-green.png'}),
redIcon = new LeafIcon({iconUrl: '../docs/images/leaf-red.png'}),
orangeIcon = new LeafIcon({iconUrl: '../docs/images/leaf-orange.png'});
L.marker([51.5, -0.09], {icon: greenIcon}).bindPopup("I am a green leaf.").addTo(map);
L.marker([51.495, -0.083], {icon: redIcon}).bindPopup("I am a red leaf.").addTo(map);
L.marker([51.49, -0.1], {icon: orangeIcon}).bindPopup("I am an orange leaf.").addTo(map);
</script>
</body>
</html>

View File

@ -0,0 +1,133 @@
---
layout: tutorial
title: Markers With Custom Icons
---
## Markers With Custom Icons
In this tutorial, you'll learn how to easily define your own icons for use by the markers you put on the map.
<div id="map" class="map" style="height: 220px"></div>
[View example on a separate page &rarr;](custom-icons-example.html)
### Preparing the images
To make a custom icon, we usually need two images --- the actual icon image and the image of its shadow. For this tutorial, we took the Leaflet logo and created four images out of it --- 3 leaf images of different colors and one shadow image for the three:
<p>
<img style="border: 1px solid #ccc" src="../docs/images/leaf-green.png" />
<img style="border: 1px solid #ccc" src="../docs/images/leaf-red.png" />
<img style="border: 1px solid #ccc" src="../docs/images/leaf-orange.png" />
<img style="border: 1px solid #ccc" src="../docs/images/leaf-shadow.png" />
</p>
Note that the white area in the images is actually transparent.
### Creating an icon
Marker icons in Leaflet are defined by [L.Icon](../reference.html#icon) objects, which are passed as an option when creating markers. Let's create a green leaf icon:
var greenIcon = L.icon({
iconUrl: 'leaf-green.png',
shadowUrl: 'leaf-shadow.png',
iconSize: [38, 95], // size of the icon
shadowSize: [50, 64], // size of the shadow
iconAnchor: [22, 94], // point of the icon which will correspond to marker's location
shadowAnchor: [4, 62], // the same for the shadow
popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor
});
Now putting a marker with this icon on a map is easy:
L.marker([51.5, -0.09], {icon: greenIcon}).addTo(map);
<div id="map2" class="map" style="height: 220px"></div>
### Defining an icon class
What if we need to create several icons that have lots in common? Let's define our own icon class containing the shared options, inheriting from `L.Icon`! It's really easy in Leaflet:
var LeafIcon = L.Icon.extend({
options: {
shadowUrl: 'leaf-shadow.png',
iconSize: [38, 95],
shadowSize: [50, 64],
iconAnchor: [22, 94],
shadowAnchor: [4, 62],
popupAnchor: [-3, -76]
}
});
Now we can create all three of our leaf icons from this class and use them:
var greenIcon = new LeafIcon({iconUrl: 'leaf-green.png'}),
redIcon = new LeafIcon({iconUrl: 'leaf-red.png'}),
orangeIcon = new LeafIcon({iconUrl: 'leaf-orange.png'});
You may have noticed that we used the `new` keyword for creating LeafIcon instances. So why do all Leaflet classes get created without it? The answer is simple: the real Leaflet classes are named with a capital letter (e.g. `L.Icon`), and they also need to be created with `new`, but there are also shortcuts with lowercase names (`L.icon`), created for convenience like this:
L.icon = function (options) {
return new L.Icon(options);
};
You can do the same with your classes too. OK, lets finally put some markers with these icons on the map:
L.marker([51.5, -0.09], {icon: greenIcon}).addTo(map).bindPopup("I am a green leaf.");
L.marker([51.495, -0.083], {icon: redIcon}).addTo(map).bindPopup("I am a red leaf.");
L.marker([51.49, -0.1], {icon: orangeIcon}).addTo(map).bindPopup("I am an orange leaf.");
That's it. Now take a look at the [full example](custom-icons-example.html), the [L.Icon docs](../reference.html#icon), or browse [other examples](../examples.html).
<script>
var map = L.map('map').setView([51.5, -0.09], 13);
L.tileLayer(MB_URL, {attribution: MB_ATTR, id: 'mapbox.light'}).addTo(map);
var LeafIcon = L.Icon.extend({
options: {
iconUrl: '../docs/images/leaf-green.png',
shadowUrl: '../docs/images/leaf-shadow.png',
iconSize: [38, 95],
shadowSize: [50, 64],
iconAnchor: [22, 94],
shadowAnchor: [4, 62],
popupAnchor: [-3, -76]
}
});
var greenIcon = new LeafIcon(),
redIcon = new LeafIcon({iconUrl: '../docs/images/leaf-red.png'}),
orangeIcon = new LeafIcon({iconUrl: '../docs/images/leaf-orange.png'});
var marker1 = new L.Marker(new L.LatLng(51.5, -0.09), {icon: greenIcon}),
marker2 = new L.Marker(new L.LatLng(51.495, -0.083), {icon: redIcon}),
marker3 = new L.Marker(new L.LatLng(51.49, -0.1), {icon: orangeIcon});
marker1.bindPopup("I am a green leaf.");
marker2.bindPopup("I am a red leaf.");
marker3.bindPopup("I am an orange leaf.");
map.addLayer(marker1).addLayer(marker2).addLayer(marker3);
var map2 = L.map('map2').setView([51.505, -0.09], 13);
L.tileLayer(MB_URL, {attribution: MB_ATTR, id: 'mapbox.light'}).addTo(map2);
var greenIcon2 = L.icon({
iconUrl: '../docs/images/leaf-green.png',
shadowUrl: '../docs/images/leaf-shadow.png',
iconSize: [38, 95],
shadowSize: [50, 64],
iconAnchor: [22, 94],
shadowAnchor: [4, 62],
popupAnchor: [-3, -76]
});
L.marker([51.5, -0.09], {icon: greenIcon2}).addTo(map2);
</script>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,90 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet GeoJSON Example</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.css" />
</head>
<body>
<div id="map" style="width: 600px; height: 400px"></div>
<script src="sample-geojson.js" type="text/javascript"></script>
<script src="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.js"></script>
<script>
var map = L.map('map').setView([39.74739, -105], 13);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpandmbXliNDBjZWd2M2x6bDk3c2ZtOTkifQ._QA7i5Mpkd_m30IGElHziw', {
maxZoom: 18,
attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
'Imagery © <a href="http://mapbox.com">Mapbox</a>',
id: 'mapbox.light'
}).addTo(map);
var baseballIcon = L.icon({
iconUrl: 'baseball-marker.png',
iconSize: [32, 37],
iconAnchor: [16, 37],
popupAnchor: [0, -28]
});
function onEachFeature(feature, layer) {
var popupContent = "<p>I started out as a GeoJSON " +
feature.geometry.type + ", but now I'm a Leaflet vector!</p>";
if (feature.properties && feature.properties.popupContent) {
popupContent += feature.properties.popupContent;
}
layer.bindPopup(popupContent);
}
L.geoJson([bicycleRental, campus], {
style: function (feature) {
return feature.properties && feature.properties.style;
},
onEachFeature: onEachFeature,
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, {
radius: 8,
fillColor: "#ff7800",
color: "#000",
weight: 1,
opacity: 1,
fillOpacity: 0.8
});
}
}).addTo(map);
L.geoJson(freeBus, {
filter: function (feature, layer) {
if (feature.properties) {
// If the property "underConstruction" exists and is true, return false (don't render features under construction)
return feature.properties.underConstruction !== undefined ? !feature.properties.underConstruction : true;
}
return false;
},
onEachFeature: onEachFeature
}).addTo(map);
var coorsLayer = L.geoJson(coorsField, {
pointToLayer: function (feature, latlng) {
return L.marker(latlng, {icon: baseballIcon});
},
onEachFeature: onEachFeature
}).addTo(map);
</script>
</body>
</html>

281
docs/examples/geojson.html Normal file
View File

@ -0,0 +1,281 @@
---
layout: tutorial
title: Using GeoJSON with Leaflet
---
<h3>Using GeoJSON with Leaflet</h3>
<p>GeoJSON is becoming a very popular data format among many GIS technologies and services — it's simple, lightweight, straightforward, and Leaflet is quite good at handling it. In this example, you'll learn how to create and interact with map vectors created from <a href="http://geojson.org/">GeoJSON</a> objects.</p>
<div id="map" class="map" style="height: 250px"></div>
<script src="sample-geojson.js" type="text/javascript"></script>
<script>
var map = L.map('map').setView([39.74739, -105], 13);
L.tileLayer(MB_URL, {
attribution: MB_ATTR,
id: 'mapbox.light'
}).addTo(map);
var baseballIcon = L.icon({
iconUrl: 'baseball-marker.png',
iconSize: [32, 37],
iconAnchor: [16, 37],
popupAnchor: [0, -28]
});
function onEachFeature(feature, layer) {
var popupContent = "<p>I started out as a GeoJSON " +
feature.geometry.type + ", but now I'm a Leaflet vector!</p>";
if (feature.properties && feature.properties.popupContent) {
popupContent += feature.properties.popupContent;
}
layer.bindPopup(popupContent);
}
L.geoJson({features: [bicycleRental, campus]}, {
style: function (feature) {
return feature.properties && feature.properties.style;
},
onEachFeature: onEachFeature,
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, {
radius: 8,
fillColor: "#ff7800",
color: "#000",
weight: 1,
opacity: 1,
fillOpacity: 0.8
});
}
}).addTo(map);
L.geoJson(freeBus, {
filter: function (feature, layer) {
if (feature.properties) {
// If the property "underConstruction" exists and is true, return false (don't render features under construction)
return feature.properties.underConstruction !== undefined ? !feature.properties.underConstruction : true;
}
return false;
},
onEachFeature: onEachFeature
}).addTo(map);
var coorsLayer = L.geoJson(null, {
pointToLayer: function (feature, latlng) {
return L.marker(latlng, {icon: baseballIcon});
},
onEachFeature: onEachFeature
}).addTo(map);
coorsLayer.addData(coorsField);
</script>
<p><a href="geojson-example.html">View example on a separate page &rarr;</a></p>
<h3>About GeoJSON</h3>
<p>According to <a href="http://geojson.org">http://geojson.org</a>:</p>
<blockquote>GeoJSON is a format for encoding a variety of geographic data structures. A GeoJSON object may represent a geometry, a feature, or a collection of features. GeoJSON supports the following geometry types: Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, and GeometryCollection. Features in GeoJSON contain a geometry object and additional properties, and a feature collection represents a list of features.</blockquote>
<p>Leaflet supports all of the GeoJSON types above, but <a href="http://geojson.org/geojson-spec.html#feature-objects">Features</a> and <a href="http://geojson.org/geojson-spec.html#feature-collection-objects">FeatureCollections</a> work best as they allow you to describe features with a set of properties. We can even use these properties to style our Leaflet vectors. Here's an example of a simple GeoJSON feature:</p>
<pre><code>var geojsonFeature = {
"type": "Feature",
"properties": {
"name": "Coors Field",
"amenity": "Baseball Stadium",
"popupContent": "This is where the Rockies play!"
},
"geometry": {
"type": "Point",
"coordinates": [-104.99404, 39.75621]
}
};
</code></pre>
<h3>The GeoJSON layer</h3>
<p>GeoJSON objects are added to the map through a <a href="http://leafletjs.com/reference.html#geojson">GeoJSON layer</a>. To create it and add it to a map, we can use the following code:</p>
<pre><code>L.geoJson(geojsonFeature).addTo(map);</code></pre>
<p>GeoJSON objects may also be passed as an array of valid GeoJSON objects.</p>
<pre><code>var myLines = [{
"type": "LineString",
"coordinates": [[-100, 40], [-105, 45], [-110, 55]]
}, {
"type": "LineString",
"coordinates": [[-105, 40], [-110, 45], [-115, 55]]
}];
</code></pre>
<p>Alternatively, we could create an empty GeoJSON layer and assign it to a variable so that we can add more features to it later.</p>
<pre><code>var myLayer = L.geoJson().addTo(map);
myLayer.addData(geojsonFeature);
</code></pre>
<h3>Options</h3>
<h4>style</h4>
<p>The <code>style</code> option can be used to style features two different ways. First, we can pass a simple object that styles all paths (polylines and polygons) the same way:</p>
<pre><code>var myLines = [{
"type": "LineString",
"coordinates": [[-100, 40], [-105, 45], [-110, 55]]
}, {
"type": "LineString",
"coordinates": [[-105, 40], [-110, 45], [-115, 55]]
}];
var myStyle = {
"color": "#ff7800",
"weight": 5,
"opacity": 0.65
};
L.geoJson(myLines, {
style: myStyle
}).addTo(map);</code></pre>
<p>Alternatively, we can pass a function that styles individual features based on their properties. In the example below we check the "party" property and style our polygons accordingly:</p>
<pre><code>var states = [{
"type": "Feature",
"properties": {"party": "Republican"},
"geometry": {
"type": "Polygon",
"coordinates": [[
[-104.05, 48.99],
[-97.22, 48.98],
[-96.58, 45.94],
[-104.03, 45.94],
[-104.05, 48.99]
]]
}
}, {
"type": "Feature",
"properties": {"party": "Democrat"},
"geometry": {
"type": "Polygon",
"coordinates": [[
[-109.05, 41.00],
[-102.06, 40.99],
[-102.03, 36.99],
[-109.04, 36.99],
[-109.05, 41.00]
]]
}
}];
L.geoJson(states, {
style: function(feature) {
switch (feature.properties.party) {
case 'Republican': return {color: "#ff0000"};
case 'Democrat': return {color: "#0000ff"};
}
}
}).addTo(map);</code></pre>
<h4>pointToLayer</h4>
<p>Points are handled differently than polylines and polygons. By default simple markers are drawn for GeoJSON Points. We can alter this by passing a <code>pointToLayer</code> function in a <a href="http://leafletjs.com/reference.html#geojson-options">GeoJSON options</a> object when creating the GeoJSON layer. This function is passed a <a href="http://leafletjs.com/reference.html#latlng">LatLng</a> and should return an instance of ILayer, in this case likely a <a href="http://leafletjs.com/reference.html#marker">Marker</a> or <a href="http://leafletjs.com/reference.html#circlemarker">CircleMarker</a>.</p>
<p>Here we're using the <code>pointToLayer</code> option to create a CircleMarker:</p>
<pre><code>var geojsonMarkerOptions = {
radius: 8,
fillColor: "#ff7800",
color: "#000",
weight: 1,
opacity: 1,
fillOpacity: 0.8
};
L.geoJson(someGeojsonFeature, {
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, geojsonMarkerOptions);
}
}).addTo(map);</code></pre>
<p>We could also set the <code>style</code> property in this example &mdash; Leaflet is smart enough to apply styles to GeoJSON points if you create a vector layer like circle inside the <code>pointToLayer</code> function.</p>
<h4>onEachFeature</h4>
<p>The <code>onEachFeature</code> option is a function that gets called on each feature before adding it to a GeoJSON layer. A common reason to use this option is to attach a popup to features when they are clicked.</p>
<pre><code>function onEachFeature(feature, layer) {
// does this feature have a property named popupContent?
if (feature.properties &amp;&amp; feature.properties.popupContent) {
layer.bindPopup(feature.properties.popupContent);
}
}
var geojsonFeature = {
"type": "Feature",
"properties": {
"name": "Coors Field",
"amenity": "Baseball Stadium",
"popupContent": "This is where the Rockies play!"
},
"geometry": {
"type": "Point",
"coordinates": [-104.99404, 39.75621]
}
};
L.geoJson(geojsonFeature, {
onEachFeature: onEachFeature
}).addTo(map);</code></pre>
<h4>filter</h4>
<p>The <code>filter</code> option can be used to control the visibility of GeoJSON features. To accomplish this we pass a function as the <code>filter</code> option. This function gets called for each feature in your GeoJSON layer, and gets passed the <code>feature</code> and the <code>layer</code>. You can then utilise the values in the feature's properties to control the visibility by returning <code>true</code> or <code>false</code>.</p>
<p>In the example below "Busch Field" will not be shown on the map.</p>
<pre><code>var someFeatures = [{
"type": "Feature",
"properties": {
"name": "Coors Field",
"show_on_map": true
},
"geometry": {
"type": "Point",
"coordinates": [-104.99404, 39.75621]
}
}, {
"type": "Feature",
"properties": {
"name": "Busch Field",
"show_on_map": false
},
"geometry": {
"type": "Point",
"coordinates": [-104.98404, 39.74621]
}
}];
L.geoJson(someFeatures, {
filter: function(feature, layer) {
return feature.properties.show_on_map;
}
}).addTo(map);</code></pre>
<p>View the <a href="geojson-example.html">example page</a> to see in detail what is possible with the GeoJSON layer.</p>

View File

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet Layers Control Example</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.css" />
</head>
<body>
<div id="map" style="width: 600px; height: 400px"></div>
<script src="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.js"></script>
<script>
var cities = new L.LayerGroup();
L.marker([39.61, -105.02]).bindPopup('This is Littleton, CO.').addTo(cities),
L.marker([39.74, -104.99]).bindPopup('This is Denver, CO.').addTo(cities),
L.marker([39.73, -104.8]).bindPopup('This is Aurora, CO.').addTo(cities),
L.marker([39.77, -105.23]).bindPopup('This is Golden, CO.').addTo(cities);
var mbAttr = 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
'Imagery © <a href="http://mapbox.com">Mapbox</a>',
mbUrl = 'https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpandmbXliNDBjZWd2M2x6bDk3c2ZtOTkifQ._QA7i5Mpkd_m30IGElHziw';
var grayscale = L.tileLayer(mbUrl, {id: 'mapbox.light', attribution: mbAttr}),
streets = L.tileLayer(mbUrl, {id: 'mapbox.streets', attribution: mbAttr});
var map = L.map('map', {
center: [39.73, -104.99],
zoom: 10,
layers: [grayscale, cities]
});
var baseLayers = {
"Grayscale": grayscale,
"Streets": streets
};
var overlays = {
"Cities": cities
};
L.control.layers(baseLayers, overlays).addTo(map);
</script>
</body>
</html>

View File

@ -0,0 +1,93 @@
---
layout: tutorial
title: Layer Groups and Layers Control
---
## Layer Groups and Layers Control
This tutorial will show you how to group several layers into one, and how to use the layers control to allow users to easily switch different layers on your map.
<div id="map" class="map" style="height: 250px"></div>
[View example on a separate page &rarr;](layers-control-example.html)
### Layer Groups
Let's suppose you have a bunch of layers you want to combine into a group to handle them as one in your code:
var littleton = L.marker([39.61, -105.02]).bindPopup('This is Littleton, CO.'),
denver = L.marker([39.74, -104.99]).bindPopup('This is Denver, CO.'),
aurora = L.marker([39.73, -104.8]).bindPopup('This is Aurora, CO.'),
golden = L.marker([39.77, -105.23]).bindPopup('This is Golden, CO.');
Instead of adding them directly to the map, you can do the following, using the <a href="http://leafletjs.com/reference.html#layergroup">LayerGroup</a> class:
var cities = L.layerGroup([littleton, denver, aurora, golden]);
Easy enough! Now you have a `cities` layer that combines your city markers into one layer you can add or remove from the map at once.
### Layers Control
Leaflet has a nice little control that allows your users control what layers they want to see on your map. In addition to showing you how to use it, we'll show another handy use for layer groups.
There are two types of layers --- base layers that are mutually exclusive (only one can be visible on your map), e.g. tile layers, and overlays --- all the other stuff you put over the base layers. In this example, we want to have two base layers (grayscale and night-style base map) to switch between, and an overlay to switch on and off --- city markers (those we created earlier). Let's create those layers and add the default ones to the map:
<pre><code>var grayscale = L.tileLayer(mapboxUrl, {id: '<a href="https://mapbox.com">MapID</a>', attribution: mapboxAttribution}),
streets = L.tileLayer(mapboxUrl, {id: '<a href="https://mapbox.com">MapID</a>', attribution: mapboxAttribution});
var map = L.map('map', {
center: [39.73, -104.99],
zoom: 10,
layers: [grayscale, cities]
});</code></pre>
Next, we'll create two objects. One will contain our base layers and one will contain our overlays. These are just simple objects with key/value pairs. The key is what sets the text for the layer in the control (e.g. "Streets"). The corresponding value is a reference to the layer (e.g. `streets`).
<pre><code>var baseMaps = {
"Grayscale": grayscale,
"Streets": streets
};
var overlayMaps = {
"Cities": cities
};</code></pre>
Now, all that's left to do is to create a [Layers Control](../reference.html#control-layers) and add it to the map. The first argument passed when creating the layers control is the base layers object. The second argument is the overlays object. Both arguments are optional --- for example, you can pass just a base layers object by omitting the second argument, or just an overlays objects by passing `null` as the first argument.
<pre><code>L.control.layers(baseMaps, overlayMaps).addTo(map);</code></pre>
Note that we added `grayscale` and `cities` layers to the map but didn't add `streets`. The layers control is smart enough to detect what layers we've already added and have corresponding checkboxes and radioboxes set.
Also note that when using multiple base layers, only one of them should be added to the map at instantiation, but all of them should be present in the base layers object when creating the layers control.
Now let's [view the result on a separate page &rarr;](layers-control-example.html)
<script>
var cities = new L.LayerGroup();
L.marker([39.61, -105.02]).bindPopup('This is Littleton, CO.').addTo(cities),
L.marker([39.74, -104.99]).bindPopup('This is Denver, CO.').addTo(cities),
L.marker([39.73, -104.8]).bindPopup('This is Aurora, CO.').addTo(cities),
L.marker([39.77, -105.23]).bindPopup('This is Golden, CO.').addTo(cities);
var grayscale = L.tileLayer(MB_URL, {attribution: MB_ATTR, id: 'mapbox.light'}),
streets = L.tileLayer(MB_URL, {attribution: MB_ATTR, id: 'mapbox.streets'});
var map = L.map('map', {
center: [39.73, -104.99],
zoom: 10,
layers: [grayscale, cities]
});
var baseLayers = {
"Grayscale": grayscale,
"Streets": streets
};
var overlays = {
"Cities": cities
};
L.control.layers(baseLayers, overlays).addTo(map);
</script>

View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet Map Panes Example</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.css" />
</head>
<body>
<div id="map" style="width: 600px; height: 400px"></div>
<script src="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.js"></script>
<script type="text/javascript" src="eu-countries.js"></script>
<script>
var map = L.map('map');
map.createPane('labels');
// This pane is above markers but below popups
map.getPane('labels').style.zIndex = 650;
// Layers in this pane are non-interactive and do not obscure mouse/touch events
map.getPane('labels').style.pointerEvents = 'none';
var cartodbAttribution = '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, &copy; <a href="http://cartodb.com/attributions">CartoDB</a>';
var positron = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', {
attribution: cartodbAttribution
}).addTo(map);
var positronLabels = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png', {
attribution: cartodbAttribution,
pane: 'labels'
}).addTo(map);
geojson = L.geoJson(euCountries).addTo(map);
geojson.eachLayer(function (layer) {
layer.bindPopup(layer.feature.properties.name);
});
map.setView({ lat: 47.040182144806664, lng: 9.667968750000002 }, 4);
</script>
</body>
</html>

142
docs/examples/map-panes.md Normal file
View File

@ -0,0 +1,142 @@
---
layout: tutorial
title: Working with map panes
---
## What are panes?
In Leaflet, map panes group layers together implicitly, without the developer knowing about it. This grouping allows web browsers to work with several layers at once in a more efficient way than working with layers individually.
Map panes use the [z-index CSS property](https://developer.mozilla.org/docs/Web/CSS/z-index) to always show some layers on top of others. The [default order](http://leafletjs.com/reference.html#map-panes) is:
* `TileLayer`s and `GridLayer`s
* `Path`s, like lines, polylines, circles, or `GeoJSON` layers.
* `Marker` shadows
* `Marker` icons
* `Popup`s
This is why, in Leaflet maps, popups always show "on top" of other layers, markers always show on top of tile layers, etc.
A new feature of **Leaflet 1.0.0** (not present in 0.7.x) is custom map panes, which allows for customization of this order.
## The default is not always right
In some particular cases, the default order is not the right one for the map. We can demonstrate this with the [CartoDB basemaps](https://cartodb.com/basemaps/) and labels:
<style>
.tiles img {
border: 1px solid #ccc;
border-radius: 5px;
}
</style>
<div class='tiles'>
<div style='display: inline-block'>
<img src="http://a.basemaps.cartocdn.com/light_nolabels/0/0/0.png" class="bordered-img" /><br/>
Basemap tile with no labels
</div>
<div style='display: inline-block'>
<img src="http://a.basemaps.cartocdn.com/light_only_labels/0/0/0.png" class="bordered-img" /><br/>
Transparent labels-only tile
</div>
<div style='display: inline-block; position:relative;'>
<img src="http://a.basemaps.cartocdn.com/light_nolabels/0/0/0.png" class="bordered-img" />
<img src="http://a.basemaps.cartocdn.com/light_only_labels/0/0/0.png" style='position:absolute; left:0; top:0;'/><br/>
Labels on top of basemap
</div>
</div>
If we create a Leaflet map with these two tile layers, any marker or polygon will show on top of both, but having the labels on top [looks much nicer](http://blog.cartodb.com/let-your-labels-shine/). How can we do that?
<div id="map" class="map" style="height: 250px"></div>
<link rel="stylesheet" href="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.css" />
<script src="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.js"></script>
<script type="text/javascript" src="eu-countries.js"></script>
<script>
var map = L.map('map');
map.createPane('labels');
// This pane is above markers but below popups
map.getPane('labels').style.zIndex = 650;
// Layers in this pane are non-interactive and do not obscure mouse/touch events
map.getPane('labels').style.pointerEvents = 'none';
var cartodbAttribution = '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, &copy; <a href="http://cartodb.com/attributions">CartoDB</a>';
var positron = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', {
attribution: cartodbAttribution
}).addTo(map);
var positronLabels = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png', {
attribution: cartodbAttribution,
pane: 'labels'
}).addTo(map);
geojson = L.geoJson(euCountries).addTo(map);
geojson.eachLayer(function (layer) {
layer.bindPopup(layer.feature.properties.name);
});
map.setView({ lat: 47.040182144806664, lng: 9.667968750000002 }, 4);
</script>
## Custom pane
We can use the defaults for the basemap tiles and some overlays like GeoJSON layers, but we have to define a custom pane for the labels, so they show on top of the GeoJSON data.
Custom map panes are created on a per-map basis, so first create an instance of `L.Map` and the pane:
var map = L.map('map');
map.createPane('labels');
The next step is setting the z-index of the pane. Looking at the [defaults](https://github.com/Leaflet/Leaflet/blob/master/dist/leaflet.css#L73), a value of 650 will make the `TileLayer` with the labels show on top of markers but below pop-ups. By using `getPane()`, we have a reference to the [`HTMLElement`](https://developer.mozilla.org/docs/Web/API/HTMLElement) representing the pane, and change its z-index:
map.getPane('labels').style.zIndex = 650;
One of the problems of having image tiles on top of other map layers is that the tiles will capture clicks and touches. If a user clicks anywhere on the map, the web browser will assume she clicked on the labels tiles, and not on the GeoJSON or on the markers. This can be solved using [the `pointer-events` CSS property](https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events):
map.getPane('labels').style.pointerEvents = 'none';
With the pane now ready, we can add the layers, paying attention to use the `pane` option on the labels tiles:
var positron = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', {
attribution: '©OpenStreetMap, ©CartoDB'
}).addTo(map);
var positronLabels = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png', {
attribution: '©OpenStreetMap, ©CartoDB',
pane: 'labels'
}).addTo(map);
var geojson = L.geoJson(GeoJsonData, geoJsonOptions).addTo(map);
Finally, add some interaction to each feature on the GeoJSON layer:
geojson.eachLayer(function (layer) {
layer.bindPopup(layer.feature.properties.name);
});
map.fitBounds(geojson.getBounds());
Now the [example map](map-panes-example.html) is complete!

View File

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet mobile example</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.css" />
<script src="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.js"></script>
<style>
body {
padding: 0;
margin: 0;
}
html, body, #map {
height: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var map = L.map('map');
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpandmbXliNDBjZWd2M2x6bDk3c2ZtOTkifQ._QA7i5Mpkd_m30IGElHziw', {
maxZoom: 18,
attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
'Imagery © <a href="http://mapbox.com">Mapbox</a>',
id: 'mapbox.streets'
}).addTo(map);
function onLocationFound(e) {
var radius = e.accuracy / 2;
L.marker(e.latlng).addTo(map)
.bindPopup("You are within " + radius + " meters from this point").openPopup();
L.circle(e.latlng, radius).addTo(map);
}
function onLocationError(e) {
alert(e.message);
}
map.on('locationfound', onLocationFound);
map.on('locationerror', onLocationError);
map.locate({setView: true, maxZoom: 16});
</script>
</body>
</html>

71
docs/examples/mobile.md Normal file
View File

@ -0,0 +1,71 @@
---
layout: tutorial
title: Leaflet on Mobile
---
## Leaflet on Mobile
In this example, you'll learn how to create a fullscreen map tuned for mobile devices like iPhone, iPad or Android phones, and how to easily detect and use the current user location.
[View example in fullscreen &rarr;](mobile-example.html)
### Preparing the page
First we'll take a look at the HTML &amp; CSS code of the page. To make our map `div` element stretch to all available space (fullscreen), we can use the following CSS code:
{: .css}
body {
padding: 0;
margin: 0;
}
html, body, #map {
height: 100%;
}
Also, we need to tell the mobile browser to disable unwanted scaling of the page and set it to its actual size by placing the following line in the `head` section or our HTML page:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
### Initializing the map
We'll now initialize the map in the JavaScript code exactly like we did in the [quick start guide](quick-start.html), but won't set the map view yet:
<pre><code class="javascript">var map = L.map('map');
L.tileLayer('https://api.tiles.mapbox.com/v4/<a href="https://mapbox.com">MapID</a>/997/256/{z}/{x}/{y}.png?access_token={accessToken}', {
attribution: 'Map data &amp;copy; <span class="text-cut" data-cut="[&hellip;]">&lt;a href="http://openstreetmap.org"&gt;OpenStreetMap&lt;/a&gt; contributors, &lt;a href="http://creativecommons.org/licenses/by-sa/2.0/"&gt;CC-BY-SA&lt;/a&gt;, Imagery &copy; &lt;a href="http://mapbox.com"&gt;Mapbox&lt;/a&gt;</span>',
maxZoom: 18
}).addTo(map);</code></pre>
### Geolocation
Leaflet has a very handy shortcut for zooming the map view to the detected location --- `locate` method with the `setView` option, replacing the usual `setView` method in the code:
map.locate({setView: true, maxZoom: 16});
Here we specify 16 as the maximum zoom when setting the map view automatically. As soon as the user agrees to share its location and it's detected by the browser, the map will set the view to it. Now we have a working fullscreen mobile map! But what if we need to do something after the geolocation completed? Here's what the `locationfound` and `locationerror` events are for. Let's for example add a marker in the detected location, showing accuracy in a popup, by adding an event listener to `locationfound` event before the `locateAndSetView` call:
function onLocationFound(e) {
var radius = e.accuracy / 2;
L.marker(e.latlng).addTo(map)
.bindPopup("You are within " + radius + " meters from this point").openPopup();
L.circle(e.latlng, radius).addTo(map);
}
map.on('locationfound', onLocationFound);
Excellent! But it would also be nice to show an error message if the geolocation failed:
function onLocationError(e) {
alert(e.message);
}
map.on('locationerror', onLocationError);
If you have `setView` option set to true and the geolocation failed, it will set the view to the whole world.
Now the example is complete --- try it on your mobile phone: [View the full example &rarr;](mobile-example.html)
Next steps would be to take a look at the detailed [documentation](../reference.html) and browse [other examples](../examples.html).

View File

@ -0,0 +1,57 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet Quick Start Guide Example</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.css" />
</head>
<body>
<div id="mapid" style="width: 600px; height: 400px"></div>
<script src="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.js"></script>
<script>
var mymap = L.map('mapid').setView([51.505, -0.09], 13);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpandmbXliNDBjZWd2M2x6bDk3c2ZtOTkifQ._QA7i5Mpkd_m30IGElHziw', {
maxZoom: 18,
attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
'Imagery © <a href="http://mapbox.com">Mapbox</a>',
id: 'mapbox.streets'
}).addTo(mymap);
L.marker([51.5, -0.09]).addTo(mymap)
.bindPopup("<b>Hello world!</b><br />I am a popup.").openPopup();
L.circle([51.508, -0.11], 500, {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5
}).addTo(mymap).bindPopup("I am a circle.");
L.polygon([
[51.509, -0.08],
[51.503, -0.06],
[51.51, -0.047]
]).addTo(mymap).bindPopup("I am a polygon.");
var popup = L.popup();
function onMapClick(e) {
popup
.setLatLng(e.latlng)
.setContent("You clicked the map at " + e.latlng.toString())
.openOn(mymap);
}
mymap.on('click', onMapClick);
</script>
</body>
</html>

View File

@ -0,0 +1,219 @@
---
layout: tutorial
title: Quick Start Guide
---
## Leaflet Quick Start Guide
This step-by-step guide will quickly get you started on Leaflet basics, including setting up a Leaflet map, working with markers, polylines and popups, and dealing with events.
<div id="mapid" class="mapclass" style="height: 180px"></div>
[View example on a separate page &rarr;](quick-start-example.html)
### Preparing your page
Before writing any code for the map, you need to do the following preparation steps on your page:
* Include Leaflet CSS file in the head section of your document:
<link rel="stylesheet" href="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.css" />
* Include Leaflet JavaScript file:
<script src="https://npmcdn.com/leaflet@1.0.0-rc.3/dist/leaflet.js"></script>
* Put a `div` element with a certain `id` where you want your map to be:
<div id="mapid"></div>
* Make sure the map container has a defined height, for example by setting it in CSS:
<pre><code class="css">#mapid { height: 180px; }</code></pre>
Now you're ready to initialize the map and do some stuff with it.
### Setting up the map
<div id="mapid1" class="mapclass" style="height: 180px"></div>
Let's create a map of the center of London with pretty Mapbox Streets tiles. First we'll initialize the map and set its view to our chosen geographical coordinates and a zoom level:
var mymap = L.map('mapid').setView([51.505, -0.09], 13);
By default (as we didn't pass any options when creating the map instance), all mouse and touch interactions on the map are enabled, and it has zoom and attribution controls.
Note that `setView` call also returns the map object --- most Leaflet methods act like this when they don't return an explicit value, which allows convenient jQuery-like method chaining.
Next we'll add a tile layer to add to our map, in this case it's a Mapbox Streets tile layer. Creating a tile layer usually involves setting the [URL template](http://leafletjs.com/reference.html#url-template) for the tile images (get yours at [Mapbox](http://mapbox.com)), the attribution text and the maximum zoom level of the layer:
<pre><code class="javascript">L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
attribution: 'Map data &amp;copy; <span class="text-cut" data-cut="[&hellip;]">&lt;a href="http://openstreetmap.org"&gt;OpenStreetMap&lt;/a&gt; contributors, &lt;a href="http://creativecommons.org/licenses/by-sa/2.0/"&gt;CC-BY-SA&lt;/a&gt;, Imagery &copy; &lt;a href="http://mapbox.com"&gt;Mapbox&lt;/a&gt;</span>',
maxZoom: 18,
id: '<a href="https://www.mapbox.com/projects/">your.mapbox.project.id</a>',
accessToken: '<a href="https://www.mapbox.com/account/apps/">your.mapbox.public.access.token</a>'
}).addTo(mymap);</code></pre>
Make sure all the code is called after the `div` and `leaflet.js` inclusion. That's it! You have a working Leaflet map now.
It's worth noting that Leaflet is provider-agnostic, meaning that it doesn't enforce a particular choice of providers for tiles, and it doesn't even contain a single provider-specific line of code, so you're free to use other providers if you need to (we'd recommend Mapbox though, it looks beautiful).
### Markers, circles and polygons
<div id="mapid2" class="mapclass" style="height: 180px"></div>
Besides tile layers, you can easily add other things to your map, including markers, polylines, polygons, circles, and popups. Let's add a marker:
var marker = L.marker([51.5, -0.09]).addTo(mymap);
Adding a circle is the same (except for specifying the radius in meters as a second argument), but lets you control how it looks by passing options as the last argument when creating the object:
var circle = L.circle([51.508, -0.11], 500, {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5
}).addTo(mymap);
Adding a polygon is as easy:
var polygon = L.polygon([
[51.509, -0.08],
[51.503, -0.06],
[51.51, -0.047]
]).addTo(mymap);
### Working with popups
<div id="mapid3" class="mapclass" style="height: 180px"></div>
Popups are usually used when you want to attach some information to a particular object on a map. Leaflet has a very handy shortcut for this:
marker.bindPopup("<b>Hello world!</b><br>I am a popup.").openPopup();
circle.bindPopup("I am a circle.");
polygon.bindPopup("I am a polygon.");
Try clicking on our objects. The `bindPopup` method attaches a popup with the specified HTML content to your marker so the popup appears when you click on the object, and the `openPopup` method (for markers only) immediately opens the attached popup.
You can also use popups as layers (when you need something more than attaching a popup to an object):
var popup = L.popup()
.setLatLng([51.5, -0.09])
.setContent("I am a standalone popup.")
.openOn(mymap);
Here we use `openOn` instead of `addTo` because it handles automatic closing of a previously opened popup when opening a new one which is good for usability.
### Dealing with events
Every time something happens in Leaflet, e.g. user clicks on a marker or map zoom changes, the corresponding object sends an event which you can subscribe to with a function. It allows you to react to user interaction:
function onMapClick(e) {
alert("You clicked the map at " + e.latlng);
}
mymap.on('click', onMapClick);
Each object has its own set of events --- see [documentation](../reference.html) for details. The first argument of the listener function is an event object --- it contains useful information about the event that happened. For example, map click event object (`e` in the example above) has `latlng` property which is a location at which the click occured.
Let's improve our example by using a popup instead of an alert:
var popup = L.popup();
function onMapClick(e) {
popup
.setLatLng(e.latlng)
.setContent("You clicked the map at " + e.latlng.toString())
.openOn(mymap);
}
mymap.on('click', onMapClick);
Try clicking on the map and you will see the coordinates in a popup. <a target="_blank" href="quick-start-example.html">View the full example &rarr;</a>
Now you've learned Leaflet basics and can start building map apps straight away! Don't forget to take a look at the detailed <a href="../reference.html">documentation</a> or <a href="../examples.html">other examples</a>.
<script>
var mymap = L.map('mapid').setView([51.505, -0.09], 13);
L.tileLayer(MB_URL, {attribution: MB_ATTR, id: 'mapbox.streets'}).addTo(mymap);
L.marker([51.5, -0.09]).addTo(mymap)
.bindPopup("<b>Hello world!</b><br />I am a popup.").openPopup();
L.circle([51.508, -0.11], 500, {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5
}).addTo(mymap).bindPopup("I am a circle.");
L.polygon([
[51.509, -0.08],
[51.503, -0.06],
[51.51, -0.047]
]).addTo(mymap).bindPopup("I am a polygon.");
/*var popup = L.popup();
function onMapClick(e) {
popup
.setLatLng(e.latlng)
.setContent("You clicked the map at " + e.latlng.toString())
.openOn(map);
}
map.on('click', onMapClick);*/
var mymap1 = L.map('mapid1').setView([51.505, -0.09], 13);
L.tileLayer(MB_URL, {attribution: MB_ATTR, id: 'mapbox.streets'}).addTo(mymap1);
var mymap2 = L.map('mapid2').setView([51.505, -0.09], 13);
L.tileLayer(MB_URL, {attribution: MB_ATTR, id: 'mapbox.streets'}).addTo(mymap2);
L.marker([51.5, -0.09]).addTo(mymap2);
L.circle([51.508, -0.11], 500, {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5
}).addTo(mymap2);
L.polygon([
[51.509, -0.08],
[51.503, -0.06],
[51.51, -0.047]
]).addTo(mymap2);
var mymap3 = L.map('mapid3').setView([51.505, -0.09], 13);
L.tileLayer(MB_URL, {attribution: MB_ATTR, id: 'mapbox.streets'}).addTo(mymap3);
L.marker([51.5, -0.09]).addTo(mymap3)
.bindPopup("<b>Hello world!</b><br />I am a popup.").openPopup();
L.circle([51.508, -0.11], 500, {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5
}).addTo(mymap3).bindPopup("I am a circle.");
L.polygon([
[51.509, -0.08],
[51.503, -0.06],
[51.51, -0.047]
]).addTo(mymap3).bindPopup("I am a polygon.");
</script>

View File

@ -0,0 +1,248 @@
var freeBus = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[-105.00341892242432, 39.75383843460583],
[-105.0008225440979, 39.751891803969535]
]
},
"properties": {
"popupContent": "This is free bus that will take you across downtown.",
"underConstruction": false
},
"id": 1
},
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[-105.0008225440979, 39.751891803969535],
[-104.99820470809937, 39.74979664004068]
]
},
"properties": {
"popupContent": "This is free bus that will take you across downtown.",
"underConstruction": true
},
"id": 2
},
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[-104.99820470809937, 39.74979664004068],
[-104.98689651489258, 39.741052354709055]
]
},
"properties": {
"popupContent": "This is free bus that will take you across downtown.",
"underConstruction": false
},
"id": 3
}
]
};
var lightRailStop = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"popupContent": "18th & California Light Rail Stop"
},
"geometry": {
"type": "Point",
"coordinates": [-104.98999178409576, 39.74683938093904]
}
},{
"type": "Feature",
"properties": {
"popupContent": "20th & Welton Light Rail Stop"
},
"geometry": {
"type": "Point",
"coordinates": [-104.98689115047453, 39.747924136466565]
}
}
]
};
var bicycleRental = {
"type": "FeatureCollection",
"features": [
{
"geometry": {
"type": "Point",
"coordinates": [
-104.9998241,
39.7471494
]
},
"type": "Feature",
"properties": {
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
},
"id": 51
},
{
"geometry": {
"type": "Point",
"coordinates": [
-104.9983545,
39.7502833
]
},
"type": "Feature",
"properties": {
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
},
"id": 52
},
{
"geometry": {
"type": "Point",
"coordinates": [
-104.9963919,
39.7444271
]
},
"type": "Feature",
"properties": {
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
},
"id": 54
},
{
"geometry": {
"type": "Point",
"coordinates": [
-104.9960754,
39.7498956
]
},
"type": "Feature",
"properties": {
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
},
"id": 55
},
{
"geometry": {
"type": "Point",
"coordinates": [
-104.9933717,
39.7477264
]
},
"type": "Feature",
"properties": {
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
},
"id": 57
},
{
"geometry": {
"type": "Point",
"coordinates": [
-104.9913392,
39.7432392
]
},
"type": "Feature",
"properties": {
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
},
"id": 58
},
{
"geometry": {
"type": "Point",
"coordinates": [
-104.9788452,
39.6933755
]
},
"type": "Feature",
"properties": {
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
},
"id": 74
}
]
};
var campus = {
"type": "Feature",
"properties": {
"popupContent": "This is the Auraria West Campus",
"style": {
weight: 2,
color: "#999",
opacity: 1,
fillColor: "#B0DE5C",
fillOpacity: 0.8
}
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[-105.00432014465332, 39.74732195489861],
[-105.00715255737305, 39.74620006835170],
[-105.00921249389647, 39.74468219277038],
[-105.01067161560059, 39.74362625960105],
[-105.01195907592773, 39.74290029616054],
[-105.00989913940431, 39.74078835902781],
[-105.00758171081543, 39.74059036160317],
[-105.00346183776855, 39.74059036160317],
[-105.00097274780272, 39.74059036160317],
[-105.00062942504881, 39.74072235994946],
[-105.00020027160645, 39.74191033368865],
[-105.00071525573731, 39.74276830198601],
[-105.00097274780272, 39.74369225589818],
[-105.00097274780272, 39.74461619742136],
[-105.00123023986816, 39.74534214278395],
[-105.00183105468751, 39.74613407445653],
[-105.00432014465332, 39.74732195489861]
],[
[-105.00361204147337, 39.74354376414072],
[-105.00301122665405, 39.74278480127163],
[-105.00221729278564, 39.74316428375108],
[-105.00283956527711, 39.74390674342741],
[-105.00361204147337, 39.74354376414072]
]
],[
[
[-105.00942707061768, 39.73989736613708],
[-105.00942707061768, 39.73910536278566],
[-105.00685214996338, 39.73923736397631],
[-105.00384807586671, 39.73910536278566],
[-105.00174522399902, 39.73903936209552],
[-105.00041484832764, 39.73910536278566],
[-105.00041484832764, 39.73979836621592],
[-105.00535011291504, 39.73986436617916],
[-105.00942707061768, 39.73989736613708]
]
]
]
}
};
var coorsField = {
"type": "Feature",
"properties": {
"popupContent": "Coors Field"
},
"geometry": {
"type": "Point",
"coordinates": [-104.99404191970824, 39.756213909328125]
}
};

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

View File

@ -0,0 +1,18 @@
---
layout: tutorial_frame
title: WMS example
---
<script type='text/javascript'>
var map = L.map('map', {
center: [0, 0],
zoom: 1,
crs: L.CRS.EPSG4326
});
var wmsLayer = L.tileLayer.wms('http://demo.opengeo.org/geoserver/ows?', {
layers: 'nasa:bluemarble'
}).addTo(map);
</script>

View File

@ -0,0 +1,16 @@
---
layout: tutorial_frame
title: WMS example
---
<script type='text/javascript'>
var map = L.map('map', {
center: [-17, -67],
zoom: 3
});
var wmsLayer = L.tileLayer.wms('http://demo.opengeo.org/geoserver/ows?', {
layers: 'ne:ne'
}).addTo(map);
</script>

View File

@ -0,0 +1,16 @@
---
layout: tutorial_frame
title: WMS example
---
<script type='text/javascript'>
var map = L.map('map', {
center: [-17, -67],
zoom: 3
});
var wmsLayer = L.tileLayer.wms('http://demo.opengeo.org/geoserver/ows?', {
layers: 'nasa:bluemarble'
}).addTo(map);
</script>

View File

@ -0,0 +1,34 @@
---
layout: tutorial_frame
title: WMS example
---
<script type='text/javascript'>
var map = L.map('map', {
center: [-17, -67],
zoom: 3
});
var basemaps = {
Countries: L.tileLayer.wms('http://demo.opengeo.org/geoserver/ows?', {
layers: 'ne:ne_10m_admin_0_countries'
}),
Boundaries: L.tileLayer.wms('http://demo.opengeo.org/geoserver/ows?', {
layers: 'ne:ne_10m_admin_0_boundary_lines_land'
}),
'Countries, then boundaries': L.tileLayer.wms('http://demo.opengeo.org/geoserver/ows?', {
layers: 'ne:ne_10m_admin_0_countries,ne:ne_10m_admin_0_boundary_lines_land'
}),
'Boundaries, then countries': L.tileLayer.wms('http://demo.opengeo.org/geoserver/ows?', {
layers: 'ne:ne_10m_admin_0_boundary_lines_land,ne:ne_10m_admin_0_countries'
})
};
L.control.layers(basemaps, {}, {collapsed: false}).addTo(map);
basemaps.Countries.addTo(map);
</script>

View File

@ -0,0 +1,29 @@
---
layout: tutorial_frame
title: WMS example
---
<script type='text/javascript'>
var map = L.map('map', {
center: [-17, -67],
zoom: 3
});
var tms_ne = L.tileLayer('http://demo.opengeo.org/geoserver/gwc/service/tms/1.0.0/ne:ne@EPSG:900913@png/{z}/{x}/{y}.png', {
tms: true
}).addTo(map);
var tms_bluemarble = L.tileLayer('http://demo.opengeo.org/geoserver/gwc/service/tms/1.0.0/nasa:bluemarble@EPSG:900913@jpg/{z}/{x}/{y}.jpg', {
tms: true
});
var basemaps = {
'Natural Earth': tms_ne,
'NASA Blue Marble': tms_bluemarble
};
L.control.layers(basemaps, {}, {collapsed: false}).addTo(map);
basemaps.Countries.addTo(map);
</script>

157
docs/examples/wms/wms.md Normal file
View File

@ -0,0 +1,157 @@
---
layout: tutorial_v2
title: Using WMS and TMS services
---
<style>
iframe {
border: 1px solid #ccc;
border-radius: 5px;
}
</style>
<br/>
WMS, short for [*web map service*](https://en.wikipedia.org/wiki/Web_Map_Service), is a popular way of publishing maps by professional GIS software (and seldomly used by non-GISers). This format is similar to map tiles, but more generic and not so well optimized for use in web maps. A WMS image is defined by the coordinates of its corners - a calculation that Leaflet does under the hood.
TMS stands for *tiled map service*, and is a map tiling standard more focused on web maps, very similar to the map tiles that Leaflet expects in a `L.TileLayer`.
## WMS in Leaflet
When somebody publishes a WMS service, most likely they link to something called a `GetCapabilities` document. For this tutorial, we'll use the demo map services from GeoServer, at http://demo.opengeo.org/geoserver/web/. As you can see in that page, "WMS" links to the following URL:
http://demo.opengeo.org/geoserver/ows?service=wms&version=1.3.0&request=GetCapabilities
Leaflet does not understand WMS `GetCapabilities` documents. Instead, you have to create a `L.TileLayer.WMS` layer, provide the base WMS URL, and specify whatever WMS options you need.
The base WMS URL is simply the `GetCapabilities` URL, without any parameters, like so:
http://demo.opengeo.org/geoserver/ows?
And the way to use that in a Leaflet map is simply:
var map = L.map(mapDiv, mapOptions);
var wmsLayer = L.tileLayer.wms('http://demo.opengeo.org/geoserver/ows?', wmsOptions).addTo(map);
An instance of `L.TileLayer.WMS` needs at least one option: `layers`. Be careful, as the concept of "layer" in Leaflet is different from the concept of "layer" in WMS!
WMS servers define a set of *layers* in the service. These are defined in the `GetCapabilities` XML document, which most times is tedious and difficult to understand. Usually it's a good idea to use software such as [QGIS to see what layers are available in a WMS server](http://www.qgistutorials.com/en/docs/working_with_wms.html) to see the layer names available:
![Discovering WMS layers with QGIS](qgis-wms-layers.png)
We can see that the OpenGeo demo WMS has a WMS layer named `ne:ne` with a basemap. Let's see how it looks:
var wmsLayer = L.tileLayer.wms('http://demo.opengeo.org/geoserver/ows?', {
layers: 'ne:ne'
}).addTo(map);
{% include frame.html url="wms-example1.html" %}
Or we can try the `nasa:bluemarble` WMS layer:
var wmsLayer = L.tileLayer.wms('http://demo.opengeo.org/geoserver/ows?', {
layers: 'nasa:bluemarble'
}).addTo(map);
{% include frame.html url="wms-example2.html" %}
The `layers` option is a comma-separated list of layers. If a WMS service has defined several layers, then a request for a map image can refer to more than one layer.
For the example WMS server we're using, there is a `ne:ne_10m_admin_0_countries` WMS layer showing country landmasses and country names, and a `ne:ne_10m_admin_0_boundary_lines_land` WMS layer showing country boundaries. The WMS server will compose both layers in one image if we request both, separated with a comma:
var countriesAndBoundaries = L.tileLayer.wms('http://demo.opengeo.org/geoserver/ows?', {
layers: 'ne:ne_10m_admin_0_countries,ne:ne_10m_admin_0_boundary_lines_land'
}).addTo(map);
Note this will request *one* image to the WMS server. This is different than creating a `L.TileLayer.WMS` for the countries, another one for the boundaries, and adding them both to the map. In the first case, there is one image request and it's the WMS server who decides how to compose (put on top of each other) the image. In the second case, there would be two image requests and it's the Leaflet code running in the web browser who decides how to compose them.
If we combine this with the [layers control](/examples/layers-control.html), then we can build a simple map to see the difference:
var basemaps = {
Countries: L.tileLayer.wms('http://demo.opengeo.org/geoserver/ows?', {
layers: 'ne:ne_10m_admin_0_countries'
}),
Boundaries: L.tileLayer.wms('http://demo.opengeo.org/geoserver/ows?', {
layers: 'ne:ne_10m_admin_0_boundary_lines_land'
}),
'Countries, then boundaries': L.tileLayer.wms('http://demo.opengeo.org/geoserver/ows?', {
layers: 'ne:ne_10m_admin_0_countries,ne:ne_10m_admin_0_boundary_lines_land'
}),
'Boundaries, then countries': L.tileLayer.wms('http://demo.opengeo.org/geoserver/ows?', {
layers: 'ne:ne_10m_admin_0_boundary_lines_land,ne:ne_10m_admin_0_countries'
})
};
L.control.layers(basemaps).addTo(map);
basemaps.Countries.addTo(map);
Change to the "Countries, then boundaries" option, so you can see the boundaries "on top" of the landmasses, but the WMS server is clever enough to display building labels on top of that. It's up to the WMS server how to compose layers when asked for many.
{% include frame.html url="wms-example3.html" %}
### Notes to GIS users of WMS services
From a GIS point of view, WMS handling in Leaflet is quite basic. There's no `GetCapabilities` support, no legend support, and no `GetFeatureInfo` support.
`L.TileLayer.WMS` has extra options, which can be found in [Leaflet's API documentation](http://leafletjs.com/reference.html#tilelayer-wms-options). Any option not described there will be passed to the WMS server in the `getImage` URLs.
Also note that Leaflet supports very few [coordinate systems](https://en.wikipedia.org/wiki/Spatial_reference_system): `CRS:3857`, `CRS:3395` and `CRS:4326` (See the documentation for `L.CRS`). If your WMS service doesn't serve images in those coordinate systems, you might need to use [Proj4Leaflet](https://github.com/kartena/Proj4Leaflet) to use a different coordinate system in Leaflet. Other than that, just use the right CRS when initializing your map, and any WMS layers added will use it:
var map = L.map('map', {
crs: L.CRS.EPSG4326
});
var wmsLayer = L.tileLayer.wms('http://demo.opengeo.org/geoserver/ows?', {
layers: 'nasa:bluemarble'
}).addTo(map);
{% include frame.html url="wms-example-crs.html" %}
## TMS in Leaflet
Leaflet doesn't have explicit support for TMS services, but the tile naming structure is so similar to the common `L.TileLayer` naming scheme, that displaying a TMS service is almost trivial.
Using the same OpenGeo WMS/TMS server demo, we can see there's a TMS endpoint at:
http://demo.opengeo.org/geoserver/gwc/service/tms/1.0.0
Checking the [MapCache help about TMS](http://mapserver.org/mapcache/services.html) and the [TMS specification](https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification) you can see that the URL for a map tile in TMS looks like:
http://base_url/tms/1.0.0/ {tileset} / {z} / {x} / {y} .png
To use the OpenGeo TMS services as a `L.TileLayer`, we can check the capabilities document (the same as the base endpoint, in our case [`http://demo.opengeo.org/geoserver/gwc/service/tms/1.0.0`](http://demo.opengeo.org/geoserver/gwc/service/tms/1.0.0)) to see what `tileset`s are available, and build our base URLs:
http://demo.opengeo.org/geoserver/gwc/service/tms/1.0.0/ne:ne@EPSG:900913@png/{z}/{x}/{y}.png
http://demo.opengeo.org/geoserver/gwc/service/tms/1.0.0/nasa:bluemarble@EPSG:900913@jpg/{z}/{x}/{y}.jpg
And use the `tms:true` option when instantiating the layers, like so:
var tms_ne = L.tileLayer('http://demo.opengeo.org/geoserver/gwc/service/tms/1.0.0/ne:ne@EPSG:900913@png/{z}/{x}/{y}.png', {
tms: true
}).addTo(map);
var tms_bluemarble = L.tileLayer('http://demo.opengeo.org/geoserver/gwc/service/tms/1.0.0/nasa:bluemarble@EPSG:900913@jpg/{z}/{x}/{y}.jpg', {
tms: true
});
{% include frame.html url="wms-example4.html" %}
A new feature in **Leaflet 1.0** is the ability to use `{-y}` in the URL instead of a `tms: true` option, e.g.:
var layer = L.tileLayer('http://base_url/tms/1.0.0/tileset/{z}/{x}/{-y}.png');
The `tms: true` option (in Leaflet 0.7) or `{-y}` (in Leaflet 1.0) are needed because the origin of coordinates of vanilla `L.TileLayer`s is the top left corner, so the Y coordinate goes *down*. In TMS, the origin of coordinates is the *bottom* left corner so the Y coordinate goes *up*.
Besides the difference in the `y` coordinate and the discovery of tilesets, TMS services serve tiles exactly in the way that `L.TileLayer` expects.

216
docs/index.html Normal file
View File

@ -0,0 +1,216 @@
---
layout: v2
---
<p>Leaflet is the leading open-source JavaScript library for mobile-friendly interactive maps.
Weighing just about <abbr title="33 KB gzipped &mdash; that's 123 KB minified and 218 KB in the source form, with 10 KB of CSS (2 KB gzipped) and 11 KB of images.">33 KB of JS</abbr>,
it&nbsp;has all the mapping <a href="#features">features</a> most developers ever need.</p>
<p>Leaflet is designed with <em>simplicity</em>, <em>performance</em> and <em>usability</em> in mind.
It works efficiently across all major desktop and mobile platforms,
can be extended with lots of <a href="plugins.html">plugins</a>,
has a beautiful, easy to use and <a title="Leaflet API reference" href="reference.html">well-documented API</a>
and a simple, readable&nbsp;<a title="Leaflet source code repository on GitHub" href="https://github.com/Leaflet/Leaflet">source code</a> that is a&nbsp;joy to
<a title="A guide to contributing to Leaflet" href="https://github.com/Leaflet/Leaflet/blob/master/CONTRIBUTING.md">contribute</a> to.</p>
<div id="map" class="map map-home" style="height: 300px; margin-top: 50px"></div>
<p>Here we create a map in the <code>'map'</code> div, add <abbr title="Here we use OpenStreetMap tiles, but Leaflet doesn't force you to &mdash; use whatever works for you, it's open source!">tiles of our choice</abbr>, and then add a marker with some text in a popup:</p>
<pre class="basic-code javascript"><code>var map = L.map('map').setView([51.505, -0.09], 13);
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '&amp;copy; &lt;a href="http://osm.org/copyright"&gt;OpenStreetMap&lt;/a&gt; contributors'
}).addTo(map);
L.marker([51.5, -0.09]).addTo(map)
.bindPopup('A pretty CSS3 popup.&lt;br&gt; Easily customizable.')
.openPopup();</code></pre>
<p>Learn more with the <a href="examples/quick-start.html">quick start guide</a>, check out <a href="examples.html">other tutorials</a>,
or head straight to the <a href="reference.html">API documentation</a>.
If you have any questions, take a look at the <a href="https://github.com/Leaflet/Leaflet/blob/master/FAQ.md">FAQ</a> first.</p>
</div>
<h2 class="usedby-title">Trusted by the best</h2>
<div class="usedby">
<div class="container">
<a class="logo logo-github" href="https://github.com">GitHub</a>
<a class="logo logo-foursquare" href="http://foursquare.com">foursquare</a>
<a class="logo logo-pinterest" href="https://www.pinterest.com">Pinterest</a>
<a class="logo logo-facebook" href="https://www.facebook.com/">Facebook</a>
<a class="logo logo-evernote" href="https://evernote.com">Evernote</a>
<a class="logo logo-etsy" href="https://www.etsy.com/">Etsy</a>
<a class="logo logo-flickr" href="https://www.flickr.com/">Flickr</a>
<a class="logo logo-500px" href="https://500px.com">500px</a>
<a class="logo logo-datagov" href="http://www.data.gov/">Data.gov</a>
<a class="logo logo-european-commission" href="http://ec.europa.eu/">European Commission</a>
<a class="logo logo-wpost" href="https://www.washingtonpost.com">The Washington Post</a>
<a class="logo logo-ftimes" href="http://www.ft.com">Financial Times</a>
<a class="logo logo-npr" href="http://www.npr.org">NPR</a>
<a class="logo logo-usatoday" href="http://www.usatoday.com">USA Today</a>
<a class="logo logo-nps" href="http://www.nps.gov/">National Park Service</a>
<a class="logo logo-ign" href="http://ign.com">IGN.com</a>
</div>
</div>
<div class="container">
<h2 id="features">Features</h2>
<p>Leaflet doesn't try to do everything for everyone. Instead it focuses on making <em>the basic things work perfectly</em>.</p>
<div class="features clearfix">
<div class="no-break">
<h3>Layers Out of the Box</h3>
<ul>
<li>Tile layers, WMS</li>
<li>Markers, Popups</li>
<li>Vector layers<span class="quiet">: polylines, polygons, circles, rectangles</span></li>
<li>Image overlays</li>
<li>GeoJSON</li>
</ul>
</div>
<div class="no-break">
<h3>Interaction Features</h3>
<ul>
<li>Drag panning with inertia</li>
<li>Scroll wheel zoom</li>
<li>Pinch-zoom on mobile</li>
<li>Double click zoom</li>
<li>Zoom to area <span class="quiet">(shift-drag)</span></li>
<li>Keyboard navigation</li>
<li>Events<span class="quiet">: click, mouseover, etc.</span></li>
<li>Marker dragging</li>
</ul>
</div>
<div class="no-break">
<h3>Visual Features</h3>
<ul>
<li>Zoom and pan animation</li>
<li>Tile and popup fade animation</li>
<li>Very nice default design <span class="quiet">for markers, popups and map controls</span></li>
<li>Retina resolution support</li>
</ul>
</div>
<div class="no-break">
<h3>Customization Features</h3>
<ul>
<li>Pure CSS3 popups and controls <span class="quiet">for easy restyling</span></li>
<li>Image- and HTML-based markers</li>
<li><span class="quiet">A simple interface for</span> custom map layers and controls</li>
<li>Custom map projections <span class="quiet">(with <code>EPSG:3857/4326/3395</code> out of the box)</span></li>
<li>Powerful OOP facilities <span class="quiet">for extending existing classes</span></li>
</ul>
</div>
<div class="no-break">
<h3>Performance Features</h3>
<ul>
<li>Hardware acceleration on mobile <span class="quiet"> makes it feel as smooth as native apps</span></li>
<li>Utilizing CSS3 features <span class="quiet">to make panning and zooming really smooth</span></li>
<li>Smart polyline/polygon rendering <span class="quiet">with dynamic clipping and simplification makes it very fast</span></li>
<li>Modular build system<span class="quiet"> for leaving out features you don't need</span></li>
<li>Tap delay elimination on mobile</li>
</ul>
</div>
<div class="no-break">
<h3>Map Controls</h3>
<ul>
<li>Zoom buttons</li>
<li>Attribution</li>
<li>Layer switcher</li>
<li>Scale</li>
</ul>
</div>
<div class="no-break">
<h3>Browser Support</h3>
<h4>Desktop</h4>
<ul>
<li>Chrome</li>
<li>Firefox</li>
<li>Safari 5+</li>
<li>Opera 12+</li>
<li>IE 7&ndash;11</li>
</ul>
</div>
<div class="no-break">
<h4>Mobile</h4>
<ul>
<li>Safari for iOS 7+</li>
<li>Android browser 2.2+,&nbsp;3.1+,&nbsp;4+</li>
<li>Chrome for mobile</li>
<li>Firefox for mobile</li>
<li>IE10+ for Win8 devices</li>
</ul>
</div>
<div class="no-break">
<h3>Misc</h3>
<ul>
<li>Extremely lightweight</li>
<li>No external dependencies</li>
</ul>
</div>
</div>
<p>If you find some feature really missing in Leaflet, first check if there's a <a href="plugins.html">plugin for it</a>. If not, please vote for the feature on the <a href="https://leaflet.uservoice.com">Leaflet UserVoice page</a>.</p>
<h2>Getting Involved</h2>
<p>Let's create the best mapping library that will ever exist! Leaflet is developed by <a href="http://agafonkin.com">Vladimir Agafonkin</a> of <a href="http://mapbox.com">Mapbox</a> with a team of dedicated <a href="https://github.com/Leaflet/Leaflet/graphs/contributors">contributors</a>.
<a href="https://github.com/Leaflet/Leaflet">Pull requests</a> are always welcome.
However, there are many more ways to get involved with the development of Leaflet.</p>
<p>You can help the project tremendously by discovering and <a href="https://github.com/Leaflet/Leaflet/blob/master/CONTRIBUTING.md#reporting-bugs">reporting bugs</a>, <a href="https://github.com/Leaflet/Leaflet/blob/master/CONTRIBUTING.md#improving-documentation">improving documentation</a>,
helping others on <a href="https://stackoverflow.com/questions/tagged/leaflet">Stack Overflow</a>, <a href="https://gis.stackexchange.com/questions/tagged/leaflet">GIS Stack Exchange</a>
and <a href="https://github.com/Leaflet/Leaflet/issues">GitHub issues</a>,
showing your support for your favorite feature suggestions on <a href="http://leaflet.uservoice.com">Leaflet UserVoice page</a>,
tweeting to <a href="http://twitter.com/LeafletJS">@LeafletJS</a>
and spreading the word about Leaflet among your colleagues and friends.</p>
<p>Check out the <a href="https://github.com/Leaflet/Leaflet/blob/master/CONTRIBUTING.md">contribution guide</a> for more information on getting involved with Leaflet development.</p>
<div class="social-buttons">
<iframe src="http://ghbtns.com/github-btn.html?user=Leaflet&amp;repo=Leaflet&amp;type=watch&amp;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="104px" height="20px"></iframe>
<a href="https://twitter.com/LeafletJS" class="twitter-follow-button" data-show-count="true" data-show-screen-name="false">Follow @LeafletJS</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="http://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fleafletjs.com&amp;layout=button_count&amp;show_faces=false&amp;width=93&amp;action=like&amp;font=arial&amp;colorscheme=light&amp;height=35" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:93px; height:20px;" allowTransparency="true"></iframe>
</div>
<script>
var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
osmAttrib = '&copy; <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors',
osm = L.tileLayer(osmUrl, {maxZoom: 18, attribution: osmAttrib});
var map = L.map('map').setView([51.505, -0.159], 15).addLayer(osm);
L.marker([51.504, -0.159])
.addTo(map)
.bindPopup('A pretty CSS3 popup.<br />Easily customizable.')
.openPopup();
</script>

3351
docs/plugins.md Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More