├── .eslintrc
├── .gitignore
├── .npmignore
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── FAQ.md
├── Jakefile.js
├── LICENSE
├── PLUGIN-GUIDE.md
├── README.md
├── bower.json
├── build
├── build.html
├── build.js
├── deps.js
├── docs-index.leafdoc
├── docs-misc.leafdoc
├── docs.js
├── leafdoc-templates
│ ├── comments.hbs
│ ├── crs.hbs
│ ├── event.hbs
│ ├── example.hbs
│ ├── factory.hbs
│ ├── function.hbs
│ ├── html.hbs
│ ├── inherited.hbs
│ ├── method.hbs
│ ├── namespace.hbs
│ ├── option.hbs
│ ├── pane.hbs
│ ├── projection.hbs
│ ├── property.hbs
│ ├── section.hbs
│ └── supersection.hbs
└── publish.sh
├── debug
├── css
│ ├── mobile.css
│ └── screen.css
├── hacks
│ └── jitter.html
├── leaflet-include.js
├── map
│ ├── canvas.html
│ ├── control-layers.html
│ ├── controls.html
│ ├── geolocation.html
│ ├── grid.html
│ ├── iframe.html
│ ├── image-overlay.html
│ ├── layer_remove_add.html
│ ├── map-mobile.html
│ ├── map.html
│ ├── markers.html
│ ├── max-bounds-bouncy.html
│ ├── max-bounds-infinite.html
│ ├── max-bounds.html
│ ├── opacity.html
│ ├── popup.html
│ ├── scroll.html
│ ├── simple-proj.html
│ ├── tile-debug.html
│ ├── tile-opacity.html
│ ├── wms-marble.html
│ ├── wms.html
│ ├── zoom-delta.html
│ ├── zoom-remain-centered.html
│ ├── zoomlevels.html
│ └── zoompan.html
├── tests
│ ├── add_remove_layers.html
│ ├── bringtoback.html
│ ├── canvasloop.html
│ ├── click_on_canvas.html
│ ├── detached-dom-memory-leak.html
│ ├── doubleclick-events-slowdown.html
│ ├── dragging_and_copyworldjump.html
│ ├── dragging_cursors.html
│ ├── mousemove_on_polygons.html
│ ├── opacity.html
│ ├── popup_offset.html
│ ├── popupcontextmenuclicks.html
│ ├── remove_while_dragging.html
│ ├── removetilewhilepan.html
│ ├── reuse_popups.html
│ ├── rtl.html
│ ├── rtl2.html
│ ├── set_icon_reuse_dom.html
│ ├── svg_clicks.html
│ ├── tile-bounds.html
│ ├── tile-events.html
│ ├── tile-opacity.html
│ ├── touch-shake.html
│ └── touch-zoom-bounce.html
└── vector
│ ├── bounds-extend.html
│ ├── feature-group-bounds.html
│ ├── geojson-sample.js
│ ├── geojson.html
│ ├── rectangle.html
│ ├── route.js
│ ├── touchzoomemu.html
│ ├── us-states.js
│ ├── vector-bounds.html
│ ├── vector-canvas.html
│ ├── vector-mobile.html
│ ├── vector-simple.html
│ ├── vector.html
│ └── vector2.html
├── dist
├── images
│ ├── layers-2x.png
│ ├── layers.png
│ ├── marker-icon-2x.png
│ ├── marker-icon.png
│ └── marker-shadow.png
└── leaflet.css
├── package.json
├── spec
├── .eslintrc
├── after.js
├── expect.js
├── index.html
├── karma.conf.js
├── sinon.js
├── spec.hintrc.js
└── suites
│ ├── SpecHelper.js
│ ├── control
│ ├── Control.AttributionSpec.js
│ ├── Control.LayersSpec.js
│ ├── Control.ScaleSpec.js
│ └── ControlSpec.js
│ ├── core
│ ├── ClassSpec.js
│ ├── EventsSpec.js
│ └── UtilSpec.js
│ ├── dom
│ ├── DomEventSpec.js
│ └── DomUtilSpec.js
│ ├── geo
│ ├── CRSSpec.js
│ ├── LatLngBoundsSpec.js
│ ├── LatLngSpec.js
│ └── ProjectionSpec.js
│ ├── geometry
│ ├── BoundsSpec.js
│ ├── LineUtilSpec.js
│ ├── PointSpec.js
│ ├── PolyUtilSpec.js
│ └── TransformationSpec.js
│ ├── layer
│ ├── FeatureGroupSpec.js
│ ├── GeoJSONSpec.js
│ ├── ImageOverlaySpec.js
│ ├── LayerGroupSpec.js
│ ├── PopupSpec.js
│ ├── marker
│ │ └── MarkerSpec.js
│ ├── tile
│ │ ├── GridLayerSpec.js
│ │ └── TileLayerSpec.js
│ └── vector
│ │ ├── CanvasSpec.js
│ │ ├── CircleMarkerSpec.js
│ │ ├── CircleSpec.js
│ │ ├── PathSpec.js
│ │ ├── PolygonSpec.js
│ │ ├── PolylineGeometrySpec.js
│ │ └── PolylineSpec.js
│ └── map
│ ├── MapSpec.js
│ └── handler
│ ├── Map.DragSpec.js
│ └── Map.TouchZoomSpec.js
└── src
├── Leaflet.js
├── control
├── Control.Attribution.js
├── Control.Layers.js
├── Control.Scale.js
├── Control.Zoom.js
└── Control.js
├── copyright.js
├── core
├── Browser.js
├── Class.js
├── Class.leafdoc
├── Events.js
├── Events.leafdoc
├── Handler.js
└── Util.js
├── dom
├── DomEvent.DoubleTap.js
├── DomEvent.Pointer.js
├── DomEvent.js
├── DomUtil.js
├── Draggable.js
└── PosAnimation.js
├── geo
├── LatLng.js
├── LatLngBounds.js
├── crs
│ ├── CRS.EPSG3395.js
│ ├── CRS.EPSG3857.js
│ ├── CRS.EPSG4326.js
│ ├── CRS.Earth.js
│ ├── CRS.Simple.js
│ └── CRS.js
└── projection
│ ├── Projection.LonLat.js
│ ├── Projection.Mercator.js
│ ├── Projection.SphericalMercator.js
│ └── Projection.leafdoc
├── geometry
├── Bounds.js
├── LineUtil.js
├── Point.js
├── PolyUtil.js
└── Transformation.js
├── images
├── layers.svg
├── logo.svg
└── marker.svg
├── layer
├── FeatureGroup.js
├── GeoJSON.js
├── ImageOverlay.js
├── Layer.Popup.js
├── Layer.js
├── LayerGroup.js
├── Popup.js
├── marker
│ ├── DivIcon.js
│ ├── Icon.Default.js
│ ├── Icon.js
│ ├── Marker.Drag.js
│ ├── Marker.Popup.js
│ └── Marker.js
├── tile
│ ├── GridLayer.js
│ ├── TileLayer.WMS.js
│ └── TileLayer.js
└── vector
│ ├── Canvas.js
│ ├── Circle.js
│ ├── CircleMarker.js
│ ├── Path.js
│ ├── Polygon.js
│ ├── Polyline.js
│ ├── Rectangle.js
│ ├── Renderer.js
│ ├── SVG.VML.js
│ └── SVG.js
└── map
├── Map.js
├── Map.methodOptions.leafdoc
├── anim
├── Map.FlyTo.js
├── Map.PanAnimation.js
└── Map.ZoomAnimation.js
├── ext
└── Map.Geolocation.js
└── handler
├── Map.BoxZoom.js
├── Map.DoubleClickZoom.js
├── Map.Drag.js
├── Map.Keyboard.js
├── Map.ScrollWheelZoom.js
├── Map.Tap.js
└── Map.TouchZoom.js
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "globals": {
3 | "L": true,
4 | },
5 | "env": {
6 | "commonjs": true,
7 | "amd": true,
8 | "node": false
9 | },
10 | "extends": "mourner",
11 | "rules": {
12 | "no-mixed-spaces-and-tabs": [2, "smart-tabs"],
13 | "indent": [2, "tab", {"VariableDeclarator": 0}],
14 | "curly": 2,
15 | "spaced-comment": 2,
16 | "strict": 0,
17 | "wrap-iife": 0,
18 | "key-spacing": 0,
19 | "consistent-return": 0
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | tmp/**/*
4 | .idea
5 | .idea/**/*
6 | *.iml
7 | *.sublime-*
8 | _site
9 | dist/*.js
10 | dist/*.map
11 | dist/reference.html
12 | coverage/
13 | *.js.html
14 | index.html
15 | .mailmap
16 | bower.json
17 | component.json
18 | debug/local/
19 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | tmp/**/*
4 | .idea
5 | .idea/**/*
6 | *.iml
7 | *.sublime-*
8 | _site
9 | coverage/
10 | dist/leaflet.zip
11 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | node_js: stable
4 | addons:
5 | artifacts:
6 | paths:
7 | - dist
8 | target_paths:
9 | - content/leaflet/${NAME}
10 | env:
11 | global:
12 | - ARTIFACTS_BUCKET=leafletjs-cdn
13 | - ARTIFACTS_PERMISSIONS=public-read
14 | - secure: |-
15 | JlC1rD7WryxlUbWmD3NWVX9E60XB/+ss7+j0OaY3WqWziGUWDCuoVkOMGXnp
16 | Ev27O8qhlmRkeyiimUN64UzK0yeZ139DcZMY6r4A5E2kwHYRAO/H/zl5RAGo
17 | Yd9GUPwZfr3xV8WhH2GFy/L/mRjkGwue2o6ZxdsqBOKfYaF9Ryg=
18 | - secure: |-
19 | XW1hzORAtSpTgTKkQwel5gRMDy6SotzeSRsVV2jQCn46VIMx8G/J5nOI+ImL
20 | yeoH12PhCR0h39dM7mq8TYJo5DHwvbotI5nQhpMruSt8eMFbym8nGiqQh806
21 | fSJXkxmQ4MAjUdNFDIirBHhdZme8q3PueFzJ+5odFMvPGn/aITQ=
22 | after_success:
23 | - npm run build
24 | - cd dist && zip -x .DS_Store -r leaflet.zip . && cd ..
25 | - NAME=$TRAVIS_BRANCH
26 | - '[[ $TRAVIS_PULL_REQUEST != ''false'' ]] && NAME=$TRAVIS_PULL_REQUEST'
27 | - '[[ -n $TRAVIS_TAG ]] && NAME=$TRAVIS_TAG'
28 |
--------------------------------------------------------------------------------
/Jakefile.js:
--------------------------------------------------------------------------------
1 | /*
2 | Leaflet building, testing and linting scripts.
3 |
4 | To use, install Node, then run the following commands in the project root:
5 |
6 | npm install -g jake
7 | npm install
8 |
9 | To check the code for errors and build Leaflet from source, run "jake".
10 | To run the tests, run "jake test". To build the documentation, run "jake docs".
11 |
12 | For a custom build, open build/build.html in the browser and follow the instructions.
13 | */
14 |
15 | var build = require('./build/build.js'),
16 | buildDocs = require('./build/docs'),
17 | git = require('git-rev');
18 |
19 | function hint(msg, args) {
20 | return function () {
21 | console.log(msg);
22 | jake.exec('node node_modules/eslint/bin/eslint.js ' + args,
23 | {printStdout: true}, function () {
24 | console.log('\tCheck passed.\n');
25 | complete();
26 | });
27 | };
28 | }
29 |
30 | // Returns the version string in package.json, plus a semver build metadata if
31 | // this is not an official release
32 | function calculateVersion(officialRelease, callback) {
33 |
34 | var version = require('./package.json').version;
35 |
36 | if (officialRelease) {
37 | callback(version);
38 | } else {
39 | git.short(function(str) {
40 | callback (version + '+' + str);
41 | });
42 | }
43 | }
44 |
45 | desc('Check Leaflet source for errors with ESLint');
46 | task('lint', {async: true}, hint('Checking for JS errors...', 'src --config .eslintrc'));
47 |
48 | desc('Check Leaflet specs source for errors with ESLint');
49 | task('lintspec', {async: true}, hint('Checking for specs JS errors...', 'spec/suites --config spec/.eslintrc'));
50 |
51 | desc('Combine and compress Leaflet source files');
52 | task('build', {async: true}, function (compsBase32, buildName, officialRelease) {
53 | calculateVersion(officialRelease, function(v){
54 | build.build(complete, v, compsBase32, buildName);
55 | });
56 | });
57 |
58 | desc('Run PhantomJS tests');
59 | task('test', ['lint', 'lintspec'], {async: true}, function () {
60 | build.test(complete);
61 | });
62 |
63 | desc('Build documentation');
64 | task('docs', {}, function() {
65 | buildDocs();
66 | });
67 |
68 | task('default', ['test', 'build']);
69 |
70 | jake.addListener('complete', function () {
71 | process.exit();
72 | });
73 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010-2016, Vladimir Agafonkin
2 | Copyright (c) 2010-2011, CloudMade
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification, are
6 | permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this list of
9 | conditions and the following disclaimer.
10 |
11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 | of conditions and the following disclaimer in the documentation and/or other materials
13 | provided with the distribution.
14 |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
16 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18 | COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
22 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | Leaflet is the leading open-source JavaScript library for **mobile-friendly interactive maps**.
4 | Weighing just about 33 KB of gzipped JS code, it has all the mapping [features][] most developers ever need.
5 |
6 | Leaflet is designed with *simplicity*, *performance* and *usability* in mind.
7 | It works efficiently across all major desktop and mobile platforms out of the box,
8 | taking advantage of HTML5 and CSS3 on modern browsers while being accessible on older ones too.
9 | It can be extended with a huge amount of [plugins][],
10 | has a beautiful, easy to use and [well-documented][] API
11 | and a simple, readable [source code][] that is a joy to [contribute][] to.
12 |
13 | For more info, docs and tutorials, check out the [official website][].
14 | For **Leaflet downloads** (including the built master version), check out the [download page][].
15 |
16 | We're happy to meet new contributors.
17 | If you want to **get involved** with Leaflet development, check out the [contribution guide][contribute].
18 | Let's make the best mapping library that will ever exist,
19 | and push the limits of what's possible with online maps!
20 |
21 | [](https://travis-ci.org/Leaflet/Leaflet)
22 |
23 | [contributors]: https://github.com/Leaflet/Leaflet/graphs/contributors
24 | [features]: http://leafletjs.com/#features
25 | [plugins]: http://leafletjs.com/plugins.html
26 | [well-documented]: http://leafletjs.com/reference.html "Leaflet API reference"
27 | [source code]: https://github.com/Leaflet/Leaflet "Leaflet GitHub repository"
28 | [hosted on GitHub]: http://github.com/Leaflet/Leaflet
29 | [contribute]: https://github.com/Leaflet/Leaflet/blob/master/CONTRIBUTING.md "A guide to contributing to Leaflet"
30 | [official website]: http://leafletjs.com
31 | [download page]: http://leafletjs.com/download.html
32 |
33 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "leaflet",
3 | "description": "JavaScript library for mobile-friendly interactive maps",
4 | "main": [
5 | "dist/leaflet.css",
6 | "dist/leaflet-src.js"
7 | ],
8 | "ignore": [
9 | ".*",
10 | "CHANGELOG.json",
11 | "FAQ.md",
12 | "debug",
13 | "spec",
14 | "src",
15 | "build"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/build/docs-index.leafdoc:
--------------------------------------------------------------------------------
1 | This file just defines the order of the classes in the docs.
2 |
3 |
4 |
5 |
6 | @class Map
7 |
8 | @class Marker
9 | @class Popup
10 |
11 | @class TileLayer
12 | @class TileLayer.WMS
13 | @class ImageOverlay
14 |
15 | @class Path
16 | @class Polyline
17 | @class Polygon
18 | @class Rectangle
19 | @class Circle
20 | @class CircleMarker
21 | @class SVG
22 | @class Canvas
23 |
24 | @class LayerGroup
25 | @class FeatureGroup
26 | @class GeoJSON
27 | @class GridLayer
28 |
29 | @class LatLng
30 | @class LatLngBounds
31 | @class Point
32 | @class Bounds
33 | @class Icon
34 | @class DivIcon
35 |
36 | @class Control.Zoom
37 | @class Control.Attribution
38 | @class Control.Layers
39 | @class Control.Scale
40 |
41 | @class Browser
42 | @class Util
43 | @class Transformation
44 | @class LineUtil
45 | @class PolyUtil
46 |
47 | @class DomEvent
48 | @class DomUtil
49 | @class PosAnimation
50 | @class Draggable
51 |
52 | @class Class
53 | @class Evented
54 | @class Layer
55 | @class Control
56 | @class Handler
57 | @class Projection
58 | @class CRS
59 | @class Renderer
60 | @class Event objects
61 |
--------------------------------------------------------------------------------
/build/docs-misc.leafdoc:
--------------------------------------------------------------------------------
1 | Miscellaneous bits of documentation that don't really fit anywhere else
2 |
3 |
4 |
5 | @namespace Global Switches
6 |
7 | Global switches are created for rare cases and generally make
8 | Leaflet to not detect a particular browser feature even if it's
9 | there. You need to set the switch as a global variable to true
10 | before including Leaflet on the page, like this:
11 |
12 | ```html
13 |
14 |
15 | ```
16 |
17 | | Switch | Description |
18 | | -------------- | ---------------- |
19 | | `L_NO_TOUCH` | Forces Leaflet to not use touch events even if it detects them. |
20 | | `L_DISABLE_3D` | Forces Leaflet to not use hardware-accelerated CSS 3D transforms for positioning (which may cause glitches in some rare environments) even if they're supported. |
21 |
22 |
23 | @namespace noConflict
24 |
25 | This method restores the `L` global variable to the original value
26 | it had before Leaflet inclusion, and returns the real Leaflet
27 | namespace so you can put it elsewhere, like this:
28 |
29 | ```html
30 |
40 | ```
41 |
42 |
43 | @namespace version
44 |
45 | A constant that represents the Leaflet version in use.
46 |
47 | ```js
48 | L.version; // contains "1.0.0" (or whatever version is currently in use)
49 | ```
50 |
51 |
52 |
--------------------------------------------------------------------------------
/build/docs.js:
--------------------------------------------------------------------------------
1 |
2 | var packageDef = require('../package.json');
3 |
4 | function buildDocs() {
5 |
6 | console.log('Building Leaflet documentation with Leafdoc');
7 |
8 | var LeafDoc = require('leafdoc');
9 | var doc = new LeafDoc({
10 | templateDir: 'build/leafdoc-templates',
11 | showInheritancesWhenEmpty: true,
12 | leadingCharacter: '@'
13 | });
14 |
15 | // Note to Vladimir: Iván's never gonna uncomment the following line. He's
16 | // too proud of the little leaves around the code.
17 | //doc.setLeadingChar('@');
18 |
19 | // Leaflet uses a couple of non-standard documentable things. They are not
20 | // important enough to be classes/namespaces of their own, and should
21 | // just be listed in a table like the rest of documentables:
22 | doc.registerDocumentable('pane', 'Map panes');
23 | doc.registerDocumentable('projection', 'Defined projections');
24 | doc.registerDocumentable('crs', 'Defined CRSs');
25 |
26 | doc.addFile('build/docs-index.leafdoc', false);
27 | doc.addDir('src');
28 | doc.addFile('build/docs-misc.leafdoc', false);
29 |
30 | var out = doc.outputStr();
31 |
32 | var fs = require('fs');
33 |
34 | fs.writeFileSync('dist/reference-' + packageDef.version + '.html', out);
35 | }
36 |
37 | module.exports = buildDocs;
38 |
--------------------------------------------------------------------------------
/build/leafdoc-templates/comments.hbs:
--------------------------------------------------------------------------------
1 | {{{rawmarkdown comments}}}
--------------------------------------------------------------------------------
/build/leafdoc-templates/crs.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | CRS
4 | Description
5 |
6 |
7 | {{#each documentables}}
8 |
9 | {{name}}
10 | {{{markdown comments}}}
11 |
12 | {{/each}}
13 |
--------------------------------------------------------------------------------
/build/leafdoc-templates/event.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | Event
4 | Data
5 | Description
6 |
7 |
8 | {{#each documentables}}
9 |
10 | {{name}}
11 | {{{type type}}}
12 | {{{markdown comments}}}
13 |
14 | {{/each}}
15 |
--------------------------------------------------------------------------------
/build/leafdoc-templates/example.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{#each documentables}}
3 | {{{rawmarkdown comments}}}
4 | {{/each}}
--------------------------------------------------------------------------------
/build/leafdoc-templates/factory.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | Factory
4 | Description
5 |
6 |
7 | {{#each documentables}}
8 |
9 | {{name}} (
10 | {{~#each params~}}
11 | {{#if type}}<{{{type type}}}> {{/if}}{{name}}
12 | {{~#unless @last}}, {{/unless}}{{/each~}}
13 | )
14 | {{{markdown comments}}}
15 |
16 | {{/each}}
17 |
--------------------------------------------------------------------------------
/build/leafdoc-templates/function.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | Function
4 | Returns
5 | Description
6 |
7 |
8 | {{#each documentables}}
9 |
10 | {{name}} (
11 | {{~#each params~}}
12 | {{#if type}}<{{{type type}}}> {{/if}}{{name}}
13 | {{~#unless @last}}, {{/unless}}{{/each~}}
14 | )
15 | {{{type type}}}
16 | {{{markdown comments}}}
17 |
18 | {{/each}}
19 |
--------------------------------------------------------------------------------
/build/leafdoc-templates/inherited.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
▶ {{name}} inherited from {{{type ancestor}}}
4 |
7 |
8 |
--------------------------------------------------------------------------------
/build/leafdoc-templates/method.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | Method
4 | Returns
5 | Description
6 |
7 |
8 | {{#each documentables}}
9 |
10 | {{name}} (
11 | {{~#each params~}}
12 | {{#if type}}<{{{type type}}}> {{/if}}{{name}}
13 | {{~#unless @last}}, {{/unless}}{{/each~}}
14 | )
15 | {{{type type}}}
16 | {{{rawmarkdown comments}}}
17 |
18 | {{/each}}
19 |
--------------------------------------------------------------------------------
/build/leafdoc-templates/namespace.hbs:
--------------------------------------------------------------------------------
1 | {{#if name ~}}
2 | {{name}}
3 | {{~ else ~}}
4 |
5 | {{/if}}
6 | {{{rawmarkdown comments}}}
7 | {{{supersections}}}
--------------------------------------------------------------------------------
/build/leafdoc-templates/option.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | Option
4 | Type
5 | Default
6 | Description
7 |
8 |
9 | {{#each documentables}}
10 |
11 | {{name}}
12 | {{{type type}}}
13 | {{defaultValue}}
14 | {{{markdown comments}}}
15 |
16 | {{/each}}
17 |
--------------------------------------------------------------------------------
/build/leafdoc-templates/pane.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | Pane
4 | Type
5 | Z-index
6 | Description
7 |
8 |
9 | {{#each documentables}}
10 |
11 | {{name}}
12 | {{{type type}}}
13 | {{defaultValue}}
14 | {{{markdown comments}}}
15 |
16 | {{/each}}
17 |
--------------------------------------------------------------------------------
/build/leafdoc-templates/projection.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | Projection
4 | Description
5 |
6 |
7 | {{#each documentables}}
8 |
9 | {{name}}
10 | {{{markdown comments}}}
11 |
12 | {{/each}}
13 |
--------------------------------------------------------------------------------
/build/leafdoc-templates/property.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | Property
4 | Type
5 | Description
6 |
7 |
8 | {{#each documentables}}
9 |
10 | {{name}}
11 | {{{type type}}}
12 | {{{markdown comments}}}
13 |
14 | {{/each}}
15 |
--------------------------------------------------------------------------------
/build/leafdoc-templates/section.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#if name}}{{name}} {{/if}}
4 |
5 | {{#if comments~}}
6 |
7 | {{/if}}
8 |
9 | {{{documentables}}}
10 |
11 |
--------------------------------------------------------------------------------
/build/leafdoc-templates/supersection.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{name}}
3 | {{markdown comments}}
4 | {{{sections}}}
5 |
6 | {{{inheritances}}}
7 |
--------------------------------------------------------------------------------
/build/publish.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | npm update
4 |
5 | VERSION=$(node --eval "console.log(require('./package.json').version);")
6 |
7 | npm test || exit 1
8 |
9 | git checkout -b build
10 |
11 | jake build[,,true]
12 | git add dist/leaflet-src.js dist/leaflet.js dist/leaflet-src.map -f
13 |
14 | git commit -m "v$VERSION"
15 |
16 | git tag v$VERSION -f
17 | git push --tags -f
18 |
19 | npm publish --tag rc
20 |
21 | git checkout master
22 | git branch -D build
23 |
--------------------------------------------------------------------------------
/debug/css/mobile.css:
--------------------------------------------------------------------------------
1 | html, body, #map {
2 | margin: 0;
3 | padding: 0;
4 | width: 100%;
5 | height: 100%;
6 | }
--------------------------------------------------------------------------------
/debug/css/screen.css:
--------------------------------------------------------------------------------
1 | #map {
2 | width: 800px;
3 | height: 600px;
4 | border: 1px solid #ccc;
5 | }
--------------------------------------------------------------------------------
/debug/hacks/jitter.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
23 | Bug tested to occur on: Safari on Mac (Tested in 5.1.7), iPad/iPhone 5.1.1., Android 4 Browser. Hack is in L.Browser.chrome and TileLayer._addTile
24 |
25 |
26 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/debug/leaflet-include.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | function getFiles() {
3 | var memo = {},
4 | files = [],
5 | i, src;
6 |
7 | function addFiles(srcs) {
8 | for (var j = 0, len = srcs.length; j < len; j++) {
9 | memo[srcs[j]] = true;
10 | }
11 | }
12 |
13 | for (i in deps) {
14 | addFiles(deps[i].src);
15 | }
16 |
17 | for (src in memo) {
18 | files.push(src);
19 | }
20 |
21 | return files;
22 | }
23 | var scripts = getFiles();
24 |
25 | function getSrcUrl() {
26 | var scripts = document.getElementsByTagName('script');
27 | for (var i = 0; i < scripts.length; i++) {
28 | var src = scripts[i].src;
29 | if (src) {
30 | var res = src.match(/^(.*)leaflet-include\.js$/);
31 | if (res) {
32 | return res[1] + '../src/';
33 | }
34 | }
35 | }
36 | }
37 |
38 | var path = getSrcUrl();
39 | for (var i = 0; i < scripts.length; i++) {
40 | document.writeln("");
41 | }
42 | document.writeln('');
43 | })();
44 |
45 | function getRandomLatLng(map) {
46 | var bounds = map.getBounds(),
47 | southWest = bounds.getSouthWest(),
48 | northEast = bounds.getNorthEast(),
49 | lngSpan = northEast.lng - southWest.lng,
50 | latSpan = northEast.lat - southWest.lat;
51 |
52 | return new L.LatLng(
53 | southWest.lat + latSpan * Math.random(),
54 | southWest.lng + lngSpan * Math.random());
55 | }
56 |
57 | function logEvent(e) {
58 | console.log(e.type);
59 | }
60 |
--------------------------------------------------------------------------------
/debug/map/canvas.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/debug/map/control-layers.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/debug/map/controls.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/debug/map/geolocation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet geolocation debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/debug/map/grid.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/debug/map/iframe.html:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/debug/map/image-overlay.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Populate with 10 markers
19 |
20 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/debug/map/layer_remove_add.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Remove and Add Layer
19 |
20 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/debug/map/map-mobile.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/debug/map/map.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Populate with 10 markers
19 |
20 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/debug/map/markers.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/debug/map/max-bounds-bouncy.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Left: Bouncy maxBounds. Right: Not bouncy.
18 |
19 |
20 |
21 |
22 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/debug/map/max-bounds-infinite.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/debug/map/max-bounds.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/debug/map/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/debug/map/scroll.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
22 |
23 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/debug/map/simple-proj.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/debug/map/tile-opacity.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/debug/map/wms-marble.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/debug/map/wms.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/debug/map/zoom-delta.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
34 |
35 |
36 |
37 | Zoom delta test.
38 |
39 | Zooming with touch zoom, box zoom or flyTo then map.stop()
must make the zoom level snap to the value of the zoomSnap
option. Zoom interactions (keyboard, mouse wheel, zoom control buttons must change the zoom by the amount in the zoomDelta
option.
40 |
41 |
42 | SF
43 | TRD
44 | stop
45 |
46 |
47 |
48 | Snap: 0.25. Delta: 0.5.
49 |
50 |
51 |
52 |
53 | Snap: 0 (off). Delta: 0.25.
54 |
55 |
56 |
57 |
58 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/debug/map/zoom-remain-centered.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/debug/map/zoomlevels.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/debug/tests/add_remove_layers.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Add Layer
19 | Remove Layer
20 |
21 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/debug/tests/bringtoback.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Click to add layer, then zoom out or in
19 |
20 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/debug/tests/canvasloop.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/debug/tests/click_on_canvas.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/debug/tests/detached-dom-memory-leak.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
44 |
45 |
46 |
47 | This page will destroy and recreate a map div lots of times. Developer tools shall not display a memory leak.
48 |
49 |
50 | Once
51 | Start
52 | Stop
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/debug/tests/doubleclick-events-slowdown.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | This test is meant for testing the performance of doubleclick event handler in IE. See #4127 and #2820
18 |
19 |
20 | Populate with 100 more markers
21 |
22 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/debug/tests/dragging_and_copyworldjump.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Leaflet debug page
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | On the left Map dragging and worldCopyJump are enabled during initialisation.
19 | On the right Map worldCopyJump is enabled. Dragging is enabled by clicking the button.
20 |
21 |
22 | Click to enable dragging on the right map, then dragging around and watch copying
23 |
24 |
25 |
26 |
27 |
28 |
29 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/debug/tests/dragging_cursors.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Leaflet debug page
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | This page tests if the cursors for dragging the map and the markers behave as expected. The left marker is draggable, the right one is not.
17 |
18 |
19 |
20 | Map dragging enabled:
21 |
22 |
23 |
24 |
25 | Map dragging disabled:
26 |
27 |
28 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/debug/tests/mousemove_on_polygons.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
36 |
37 |
38 |
39 | Enter Move Exit Click
40 | Triangle 1:
41 | Triangle 2:
42 | Map:
43 |
44 |
45 |
46 |
47 |
48 |
49 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/debug/tests/opacity.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/debug/tests/popup_offset.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/debug/tests/popupcontextmenuclicks.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Populate with 10 markers
19 |
20 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/debug/tests/remove_while_dragging.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/debug/tests/removetilewhilepan.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/debug/tests/reuse_popups.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/debug/tests/rtl.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
22 | Click the map to place a popup at the mouse location
23 |
24 |
25 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/debug/tests/rtl2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/debug/tests/set_icon_reuse_dom.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Test for preservation of Icon DOM element
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/debug/tests/svg_clicks.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/debug/tests/tile-bounds.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
22 |
23 |
24 | The CSS in this page makes the boundaries of the GridLayer tiles visible. Tiles which do not overlap the map bounds shall not be shown, even at fractional zoom levels.
25 |
26 | Zoom + 0.1
27 | Zoom - 0.1
28 |
29 |
30 |
31 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/debug/tests/tile-opacity.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
16 |
17 |
18 |
19 | The opacity of the "toner" layer should pulse nicely, even when dragging/zooming the map around with new tiles.
20 |
21 |
22 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/debug/vector/bounds-extend.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Extend the bounds of the center rectangle with the upper right rectangle
16 | Extend the bounds of the center rectangle with the lower left marker
17 |
18 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/debug/vector/feature-group-bounds.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Show GeoJSON layer bounds
17 | Show feature group bounds
18 |
19 |
20 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/debug/vector/geojson-sample.js:
--------------------------------------------------------------------------------
1 | var geojsonSample = {
2 | "type": "FeatureCollection",
3 | "features": [
4 | {
5 | "type": "Feature",
6 | "geometry": {
7 | "type": "Point",
8 | "coordinates": [102.0, 0.5]
9 | },
10 | "properties": {
11 | "prop0": "value0",
12 | "color": "blue"
13 | }
14 | },
15 |
16 | {
17 | "type": "Feature",
18 | "geometry": {
19 | "type": "LineString",
20 | "coordinates": [[102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]]
21 | },
22 | "properties": {
23 | "color": "red",
24 | "prop1": 0.0
25 | }
26 | },
27 |
28 | {
29 | "type": "Feature",
30 | "geometry": {
31 | "type": "Polygon",
32 | "coordinates": [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]]
33 | },
34 | "properties": {
35 | "color": "green",
36 | "prop1": {
37 | "this": "that"
38 | }
39 | }
40 | },
41 |
42 | {
43 | "type": "Feature",
44 | "geometry": {
45 | "type": "MultiPolygon",
46 | "coordinates": [[[[100.0, 1.5], [100.5, 1.5], [100.5, 2.0], [100.0, 2.0], [100.0, 1.5]]], [[[100.5, 2.0], [100.5, 2.5], [101.0, 2.5], [101.0, 2.0], [100.5, 2.0]]]]
47 | },
48 | "properties": {
49 | "color": "purple"
50 | }
51 | }
52 | ]
53 | };
54 |
--------------------------------------------------------------------------------
/debug/vector/rectangle.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/debug/vector/vector-bounds.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Zoom to path
16 | Zoom to polygon
17 |
18 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/debug/vector/vector-canvas.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Remove path
16 | Remove circle
17 | Remove all layers
18 |
19 |
20 |
21 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/debug/vector/vector-mobile.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/debug/vector/vector-simple.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/debug/vector/vector.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/debug/vector/vector2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Leaflet debug page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/dist/images/layers-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/masajid390/leaflet/4ad74d879d2309410773d61e07f8aef23ea09158/dist/images/layers-2x.png
--------------------------------------------------------------------------------
/dist/images/layers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/masajid390/leaflet/4ad74d879d2309410773d61e07f8aef23ea09158/dist/images/layers.png
--------------------------------------------------------------------------------
/dist/images/marker-icon-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/masajid390/leaflet/4ad74d879d2309410773d61e07f8aef23ea09158/dist/images/marker-icon-2x.png
--------------------------------------------------------------------------------
/dist/images/marker-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/masajid390/leaflet/4ad74d879d2309410773d61e07f8aef23ea09158/dist/images/marker-icon.png
--------------------------------------------------------------------------------
/dist/images/marker-shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/masajid390/leaflet/4ad74d879d2309410773d61e07f8aef23ea09158/dist/images/marker-shadow.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "leaflet",
3 | "version": "1.0.0-rc.1",
4 | "description": "JavaScript library for mobile-friendly interactive maps",
5 | "devDependencies": {
6 | "eslint": "^2.8.0",
7 | "eslint-config-mourner": "^2.0.1",
8 | "git-rev": "^0.2.1",
9 | "happen": "~0.3.1",
10 | "jake": "~8.0.12",
11 | "karma": "~0.13.22",
12 | "karma-chrome-launcher": "^0.2.3",
13 | "karma-coverage": "~0.5.5",
14 | "karma-firefox-launcher": "~0.1.7",
15 | "karma-mocha": "~0.2.2",
16 | "karma-phantomjs-launcher": "^1.0.0",
17 | "karma-safari-launcher": "~0.1.1",
18 | "leafdoc": "^1.2.2",
19 | "mocha": "~2.4.5",
20 | "phantomjs-prebuilt": "^2.1.7",
21 | "prosthetic-hand": "^1.3.0",
22 | "source-map": "^0.5.3",
23 | "uglify-js": "~2.6.2"
24 | },
25 | "main": "dist/leaflet-src.js",
26 | "style": "dist/leaflet.css",
27 | "scripts": {
28 | "test": "jake test",
29 | "build": "jake build",
30 | "release": "./build/publish.sh"
31 | },
32 | "repository": {
33 | "type": "git",
34 | "url": "git://github.com/Leaflet/Leaflet.git"
35 | },
36 | "keywords": [
37 | "gis",
38 | "map"
39 | ],
40 | "license": "BSD-2-Clause"
41 | }
42 |
--------------------------------------------------------------------------------
/spec/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "no-unused-vars": 0,
4 | "quotes": 0,
5 | "no-shadow": 0,
6 | "no-irregular-whitespace": 0,
7 | "no-console": 0,
8 | "no-extend-native": 0
9 | },
10 | "env": {
11 | "mocha": true
12 | },
13 | "globals": {
14 | "expect": false,
15 | "sinon": false,
16 | "happen": false,
17 | "Hand": false
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/spec/after.js:
--------------------------------------------------------------------------------
1 | // put after Leaflet files as imagePath can't be detected in a PhantomJS env
2 | L.Icon.Default.imagePath = "/base/dist/images";
3 |
--------------------------------------------------------------------------------
/spec/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | module.exports = function (config) {
3 |
4 | var libSources = require(__dirname+'/../build/build.js').getFiles();
5 |
6 | var files = [
7 | "spec/sinon.js",
8 | "spec/expect.js"
9 | ].concat(libSources, [
10 | "spec/after.js",
11 | "node_modules/happen/happen.js",
12 | "node_modules/prosthetic-hand/dist/prosthetic-hand.js",
13 | "spec/suites/SpecHelper.js",
14 | "spec/suites/**/*.js",
15 | {pattern: "dist/images/*.png", included: false}
16 | ]);
17 |
18 | config.set({
19 | // base path, that will be used to resolve files and exclude
20 | basePath: '../',
21 |
22 | plugins: [
23 | 'karma-mocha',
24 | 'karma-coverage',
25 | 'karma-phantomjs-launcher',
26 | 'karma-chrome-launcher',
27 | 'karma-safari-launcher',
28 | 'karma-firefox-launcher'],
29 |
30 | // frameworks to use
31 | frameworks: ['mocha'],
32 |
33 | // list of files / patterns to load in the browser
34 | files: files,
35 | exclude: [],
36 |
37 | // test results reporter to use
38 | // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
39 | reporters: ['dots'],
40 |
41 | // web server port
42 | port: 9876,
43 |
44 | // level of logging
45 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
46 | logLevel: config.LOG_WARN,
47 |
48 | // enable / disable colors in the output (reporters and logs)
49 | colors: true,
50 |
51 | // enable / disable watching file and executing tests whenever any file changes
52 | autoWatch: false,
53 |
54 | // Start these browsers, currently available:
55 | // - Chrome
56 | // - ChromeCanary
57 | // - Firefox
58 | // - Opera
59 | // - Safari (only Mac)
60 | // - PhantomJS
61 | // - IE (only Windows)
62 | browsers: ['PhantomJS'],
63 |
64 | // If browser does not capture in given timeout [ms], kill it
65 | captureTimeout: 5000,
66 |
67 | // Workaround for PhantomJS random DISCONNECTED error
68 | browserDisconnectTimeout: 10000, // default 2000
69 | browserDisconnectTolerance: 1, // default 0
70 |
71 | // Continuous Integration mode
72 | // if true, it capture browsers, run tests and exit
73 | singleRun: true
74 | });
75 | };
76 |
--------------------------------------------------------------------------------
/spec/spec.hintrc.js:
--------------------------------------------------------------------------------
1 | {
2 | "browser": true,
3 | "node": true,
4 | "predef": ["define", "L", "expect", "describe", "it", "sinon", "happen", "beforeEach", "afterEach", "Hand"],
5 | "strict": false,
6 | "bitwise": true,
7 | "camelcase": true,
8 | "curly": true,
9 | "eqeqeq": true,
10 | "forin": false,
11 | "immed": true,
12 | "latedef": true,
13 | "newcap": true,
14 | "noarg": true,
15 | "noempty": true,
16 | "nonew": true,
17 | "undef": true,
18 | // "unused": true,
19 | // "quotmark": "single",
20 | "indent": 4,
21 | "trailing": true,
22 | "white": true,
23 | "smarttabs": true
24 | // "maxlen": 120
25 | }
26 |
--------------------------------------------------------------------------------
/spec/suites/SpecHelper.js:
--------------------------------------------------------------------------------
1 | if (!Array.prototype.map) {
2 | Array.prototype.map = function (fun) {
3 | "use strict";
4 |
5 | if (this === undefined || this === null) {
6 | throw new TypeError();
7 | }
8 |
9 | var t = Object(this);
10 | var len = t.length >>> 0;
11 | if (typeof fun !== "function") {
12 | throw new TypeError();
13 | }
14 |
15 | var res = new Array(len);
16 | var thisp = arguments[1];
17 | for (var i = 0; i < len; i++) {
18 | if (i in t) {
19 | res[i] = fun.call(thisp, t[i], i, t);
20 | }
21 | }
22 |
23 | return res;
24 | };
25 | }
26 |
27 | expect.Assertion.prototype.near = function (expected, delta) {
28 | delta = delta || 1;
29 | expect(this.obj.x).to
30 | .be.within(expected.x - delta, expected.x + delta);
31 | expect(this.obj.y).to
32 | .be.within(expected.y - delta, expected.y + delta);
33 | };
34 |
35 | expect.Assertion.prototype.nearLatLng = function (expected, delta) {
36 | delta = delta || 1e-4;
37 | expect(this.obj.lat).to
38 | .be.within(expected.lat - delta, expected.lat + delta);
39 | expect(this.obj.lng).to
40 | .be.within(expected.lng - delta, expected.lng + delta);
41 | };
42 |
43 | happen.at = function (what, x, y, props) {
44 | this.once(document.elementFromPoint(x, y), L.Util.extend({
45 | type: what,
46 | clientX: x,
47 | clientY: y,
48 | screenX: x,
49 | screenY: y,
50 | which: 1,
51 | button: 0
52 | }, props || {}));
53 | };
54 |
55 | // We'll want to skip a couple of things when in PhantomJS, due to lack of CSS animations
56 | it.skipInPhantom = L.Browser.any3d ? it : it.skip;
57 |
58 | // A couple of tests need the browser to be touch-capable
59 | it.skipIfNotTouch = window.TouchEvent ? it : it.skip;
60 |
61 | // A couple of tests need the browser to be pointer-capable
62 | it.skipIfNotEdge = window.PointerEvent ? it : it.skip;
63 |
--------------------------------------------------------------------------------
/spec/suites/control/Control.ScaleSpec.js:
--------------------------------------------------------------------------------
1 | describe("Control.Scale", function () {
2 | it("can be added to an unloaded map", function () {
3 | var map = L.map(document.createElement('div'));
4 | new L.Control.Scale().addTo(map);
5 | });
6 | });
7 |
--------------------------------------------------------------------------------
/spec/suites/control/ControlSpec.js:
--------------------------------------------------------------------------------
1 | describe("Control", function () {
2 | var map;
3 |
4 | beforeEach(function () {
5 | map = L.map(document.createElement('div'));
6 | });
7 |
8 | function onAdd() {
9 | return L.DomUtil.create('div', 'leaflet-test-control');
10 | }
11 |
12 | describe("#addTo", function () {
13 | it("adds the container to the map", function () {
14 | var control = new L.Control();
15 | control.onAdd = onAdd;
16 | control.addTo(map);
17 | expect(map.getContainer().querySelector('.leaflet-test-control')).to.equal(control.getContainer());
18 | });
19 |
20 | it("removes the control from any existing map", function () {
21 | var control = new L.Control();
22 | control.onAdd = onAdd;
23 | control.addTo(map);
24 | control.addTo(map);
25 | expect(map.getContainer().querySelectorAll('.leaflet-test-control').length).to.equal(1);
26 | expect(map.getContainer().querySelector('.leaflet-test-control')).to.equal(control.getContainer());
27 | });
28 | });
29 |
30 | describe("#remove", function () {
31 | it("removes the container from the map", function () {
32 | var control = new L.Control();
33 | control.onAdd = onAdd;
34 | control.addTo(map).remove();
35 | expect(map.getContainer().querySelector('.leaflet-test-control')).to.equal(null);
36 | });
37 |
38 | it("calls onRemove if defined", function () {
39 | var control = new L.Control();
40 | control.onAdd = onAdd;
41 | control.onRemove = sinon.spy();
42 | control.addTo(map).remove();
43 | expect(control.onRemove.called).to.be(true);
44 | });
45 |
46 | it("is a no-op if the control has not been added", function () {
47 | var control = new L.Control();
48 | expect(control.remove()).to.equal(control);
49 | });
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/spec/suites/dom/DomEventSpec.js:
--------------------------------------------------------------------------------
1 | describe('DomEvent', function () {
2 | var el;
3 |
4 | function simulateClick(el) {
5 | if (document.createEvent) {
6 | var e = document.createEvent('MouseEvents');
7 | e.initMouseEvent('click', true, true, window,
8 | 0, 0, 0, 0, 0, false, false, false, false, 0, null);
9 | return el.dispatchEvent(e);
10 | } else if (el.fireEvent) {
11 | return el.fireEvent('onclick');
12 | }
13 | }
14 |
15 | beforeEach(function () {
16 | el = document.createElement('div');
17 | el.style.position = 'absolute';
18 | el.style.top = el.style.left = '-10000px';
19 | document.body.appendChild(el);
20 | });
21 |
22 | afterEach(function () {
23 | document.body.removeChild(el);
24 | });
25 |
26 | describe('#addListener', function () {
27 | it('adds a listener and calls it on event', function () {
28 | var listener1 = sinon.spy(),
29 | listener2 = sinon.spy();
30 |
31 | L.DomEvent.addListener(el, 'click', listener1);
32 | L.DomEvent.addListener(el, 'click', listener2);
33 |
34 | simulateClick(el);
35 |
36 | expect(listener1.called).to.be.ok();
37 | expect(listener2.called).to.be.ok();
38 | });
39 |
40 | it('binds "this" to the given context', function () {
41 | var obj = {foo: 'bar'},
42 | result;
43 |
44 | L.DomEvent.addListener(el, 'click', function () {
45 | result = this;
46 | }, obj);
47 |
48 | simulateClick(el);
49 |
50 | expect(result).to.eql(obj);
51 | });
52 |
53 | it('passes an event object to the listener', function () {
54 | var type;
55 |
56 | L.DomEvent.addListener(el, 'click', function (e) {
57 | type = e && e.type;
58 | });
59 | simulateClick(el);
60 |
61 | expect(type).to.eql('click');
62 | });
63 | });
64 |
65 | describe('#removeListener', function () {
66 | it('removes a previously added listener', function () {
67 | var listener = sinon.spy();
68 |
69 | L.DomEvent.addListener(el, 'click', listener);
70 | L.DomEvent.removeListener(el, 'click', listener);
71 |
72 | simulateClick(el);
73 |
74 | expect(listener.called).to.not.be.ok();
75 | });
76 | });
77 |
78 | describe('#stopPropagation', function () {
79 | it('stops propagation of the given event', function () {
80 | var child = document.createElement('div'),
81 | listener = sinon.spy();
82 |
83 | el.appendChild(child);
84 |
85 | L.DomEvent.addListener(child, 'click', L.DomEvent.stopPropagation);
86 | L.DomEvent.addListener(el, 'click', listener);
87 |
88 | simulateClick(child);
89 |
90 | expect(listener.called).to.not.be.ok();
91 |
92 | el.removeChild(child);
93 | });
94 | });
95 | describe('#preventDefault', function () {
96 | it('prevents the default action of event', function () {
97 | L.DomEvent.addListener(el, 'click', L.DomEvent.preventDefault);
98 |
99 | expect(simulateClick(el)).to.be(false);
100 | });
101 | });
102 | });
103 |
--------------------------------------------------------------------------------
/spec/suites/dom/DomUtilSpec.js:
--------------------------------------------------------------------------------
1 | describe('DomUtil', function () {
2 | var el;
3 |
4 | beforeEach(function () {
5 | el = document.createElement('div');
6 | el.style.position = 'absolute';
7 | el.style.top = el.style.left = '-10000px';
8 | document.body.appendChild(el);
9 | });
10 |
11 | afterEach(function () {
12 | document.body.removeChild(el);
13 | });
14 |
15 | describe('#get', function () {
16 | it('gets element by id if the given argument is string', function () {
17 | el.id = 'testId';
18 | expect(L.DomUtil.get(el.id)).to.eql(el);
19 | });
20 |
21 | it('returns the element if it is given as an argument', function () {
22 | expect(L.DomUtil.get(el)).to.eql(el);
23 | });
24 | });
25 |
26 | describe('#addClass, #removeClass, #hasClass', function () {
27 | it('has defined class for test element', function () {
28 | el.className = 'bar foo baz ';
29 | expect(L.DomUtil.hasClass(el, 'foo')).to.be.ok();
30 | expect(L.DomUtil.hasClass(el, 'bar')).to.be.ok();
31 | expect(L.DomUtil.hasClass(el, 'baz')).to.be.ok();
32 | expect(L.DomUtil.hasClass(el, 'boo')).to.not.be.ok();
33 | });
34 |
35 | it('adds or removes the class', function () {
36 | el.className = '';
37 | L.DomUtil.addClass(el, 'foo');
38 |
39 | expect(el.className).to.eql('foo');
40 | expect(L.DomUtil.hasClass(el, 'foo')).to.be.ok();
41 |
42 | L.DomUtil.addClass(el, 'bar');
43 | expect(el.className).to.eql('foo bar');
44 | expect(L.DomUtil.hasClass(el, 'foo')).to.be.ok();
45 |
46 | L.DomUtil.removeClass(el, 'foo');
47 | expect(el.className).to.eql('bar');
48 | expect(L.DomUtil.hasClass(el, 'foo')).to.not.be.ok();
49 |
50 | el.className = 'foo bar barz';
51 | L.DomUtil.removeClass(el, 'bar');
52 | expect(el.className).to.eql('foo barz');
53 | });
54 | });
55 |
56 | // describe('#setPosition', noSpecs);
57 |
58 | // describe('#getStyle', noSpecs);
59 | });
60 |
--------------------------------------------------------------------------------
/spec/suites/geo/ProjectionSpec.js:
--------------------------------------------------------------------------------
1 | describe("Projection.Mercator", function () {
2 | var p = L.Projection.Mercator;
3 |
4 | describe("#project", function () {
5 | it("projects a center point", function () {
6 | // edge cases
7 | expect(p.project(new L.LatLng(0, 0))).near(new L.Point(0, 0));
8 | });
9 |
10 | it("projects the northeast corner of the world", function () {
11 | expect(p.project(new L.LatLng(85.0840591556, 180))).near(new L.Point(20037508, 20037508));
12 | });
13 |
14 | it("projects the southwest corner of the world", function () {
15 | expect(p.project(new L.LatLng(-85.0840591556, -180))).near(new L.Point(-20037508, -20037508));
16 | });
17 |
18 | it("projects other points", function () {
19 | expect(p.project(new L.LatLng(50, 30))).near(new L.Point(3339584, 6413524));
20 |
21 | // from https://github.com/Leaflet/Leaflet/issues/1578
22 | expect(p.project(new L.LatLng(51.9371170300465, 80.11230468750001)))
23 | .near(new L.Point(8918060.964088084, 6755099.410887127));
24 | });
25 | });
26 |
27 | describe("#unproject", function () {
28 | function pr(point) {
29 | return p.project(p.unproject(point));
30 | }
31 |
32 | it("unprojects a center point", function () {
33 | expect(pr(new L.Point(0, 0))).near(new L.Point(0, 0));
34 | });
35 |
36 | it("unprojects pi points", function () {
37 | expect(pr(new L.Point(-Math.PI, Math.PI))).near(new L.Point(-Math.PI, Math.PI));
38 | expect(pr(new L.Point(-Math.PI, -Math.PI))).near(new L.Point(-Math.PI, -Math.PI));
39 |
40 | expect(pr(new L.Point(0.523598775598, 1.010683188683))).near(new L.Point(0.523598775598, 1.010683188683));
41 | });
42 |
43 | it('unprojects other points', function () {
44 | // from https://github.com/Leaflet/Leaflet/issues/1578
45 | expect(pr(new L.Point(8918060.964088084, 6755099.410887127)));
46 | });
47 | });
48 | });
49 | describe("Projection.SphericalMercator", function () {
50 | var p = L.Projection.SphericalMercator;
51 |
52 | describe("#project", function () {
53 | it("projects a center point", function () {
54 | // edge cases
55 | expect(p.project(new L.LatLng(0, 0))).near(new L.Point(0, 0));
56 | });
57 |
58 | it("projects the northeast corner of the world", function () {
59 | expect(p.project(new L.LatLng(85.0511287798, 180))).near(new L.Point(20037508, 20037508));
60 | });
61 |
62 | it("projects the southwest corner of the world", function () {
63 | expect(p.project(new L.LatLng(-85.0511287798, -180))).near(new L.Point(-20037508, -20037508));
64 | });
65 |
66 | it("projects other points", function () {
67 | expect(p.project(new L.LatLng(50, 30))).near(new L.Point(3339584, 6446275));
68 |
69 | // from https://github.com/Leaflet/Leaflet/issues/1578
70 | expect(p.project(new L.LatLng(51.9371170300465, 80.11230468750001)))
71 | .near(new L.Point(8918060.96409, 6788763.38325));
72 | });
73 | });
74 |
75 | describe("#unproject", function () {
76 | function pr(point) {
77 | return p.project(p.unproject(point));
78 | }
79 |
80 | it("unprojects a center point", function () {
81 | expect(pr(new L.Point(0, 0))).near(new L.Point(0, 0));
82 | });
83 |
84 | it("unprojects pi points", function () {
85 | expect(pr(new L.Point(-Math.PI, Math.PI))).near(new L.Point(-Math.PI, Math.PI));
86 | expect(pr(new L.Point(-Math.PI, -Math.PI))).near(new L.Point(-Math.PI, -Math.PI));
87 |
88 | expect(pr(new L.Point(0.523598775598, 1.010683188683))).near(new L.Point(0.523598775598, 1.010683188683));
89 | });
90 |
91 | it('unprojects other points', function () {
92 | // from https://github.com/Leaflet/Leaflet/issues/1578
93 | expect(pr(new L.Point(8918060.964088084, 6755099.410887127)));
94 | });
95 | });
96 | });
97 |
--------------------------------------------------------------------------------
/spec/suites/geometry/BoundsSpec.js:
--------------------------------------------------------------------------------
1 | describe('Bounds', function () {
2 | var a, b, c;
3 |
4 | beforeEach(function () {
5 | a = new L.Bounds(
6 | new L.Point(14, 12),
7 | new L.Point(30, 40));
8 | b = new L.Bounds([
9 | new L.Point(20, 12),
10 | new L.Point(14, 20),
11 | new L.Point(30, 40)
12 | ]);
13 | c = new L.Bounds();
14 | });
15 |
16 | describe('constructor', function () {
17 | it('creates bounds with proper min & max on (Point, Point)', function () {
18 | expect(a.min).to.eql(new L.Point(14, 12));
19 | expect(a.max).to.eql(new L.Point(30, 40));
20 | });
21 | it('creates bounds with proper min & max on (Point[])', function () {
22 | expect(b.min).to.eql(new L.Point(14, 12));
23 | expect(b.max).to.eql(new L.Point(30, 40));
24 | });
25 | });
26 |
27 | describe('#extend', function () {
28 | it('extends the bounds to contain the given point', function () {
29 | a.extend(new L.Point(50, 20));
30 | expect(a.min).to.eql(new L.Point(14, 12));
31 | expect(a.max).to.eql(new L.Point(50, 40));
32 |
33 | b.extend(new L.Point(25, 50));
34 | expect(b.min).to.eql(new L.Point(14, 12));
35 | expect(b.max).to.eql(new L.Point(30, 50));
36 | });
37 | });
38 |
39 | describe('#getCenter', function () {
40 | it('returns the center point', function () {
41 | expect(a.getCenter()).to.eql(new L.Point(22, 26));
42 | });
43 | });
44 |
45 | describe('#contains', function () {
46 | it('contains other bounds or point', function () {
47 | a.extend(new L.Point(50, 10));
48 | expect(a.contains(b)).to.be.ok();
49 | expect(b.contains(a)).to.not.be.ok();
50 | expect(a.contains(new L.Point(24, 25))).to.be.ok();
51 | expect(a.contains(new L.Point(54, 65))).to.not.be.ok();
52 | });
53 | });
54 |
55 | describe('#isValid', function () {
56 | it('returns true if properly set up', function () {
57 | expect(a.isValid()).to.be.ok();
58 | });
59 | it('returns false if is invalid', function () {
60 | expect(c.isValid()).to.not.be.ok();
61 | });
62 | it('returns true if extended', function () {
63 | c.extend([0, 0]);
64 | expect(c.isValid()).to.be.ok();
65 | });
66 | });
67 |
68 | describe('#getSize', function () {
69 | it('returns the size of the bounds as point', function () {
70 | expect(a.getSize()).to.eql(new L.Point(16, 28));
71 | });
72 | });
73 |
74 | describe('#intersects', function () {
75 | it('returns true if bounds intersect', function () {
76 | expect(a.intersects(b)).to.be(true);
77 | expect(a.intersects(new L.Bounds(new L.Point(100, 100), new L.Point(120, 120)))).to.eql(false);
78 | });
79 | });
80 |
81 | describe('L.bounds factory', function () {
82 | it('creates bounds from array of number arrays', function () {
83 | var bounds = L.bounds([[14, 12], [30, 40]]);
84 | expect(bounds).to.eql(a);
85 | });
86 | });
87 | });
88 |
--------------------------------------------------------------------------------
/spec/suites/geometry/LineUtilSpec.js:
--------------------------------------------------------------------------------
1 | describe('LineUtil', function () {
2 |
3 | describe('#clipSegment', function () {
4 |
5 | var bounds;
6 |
7 | beforeEach(function () {
8 | bounds = L.bounds([5, 0], [15, 10]);
9 | });
10 |
11 | it('clips a segment by bounds', function () {
12 | var a = new L.Point(0, 0);
13 | var b = new L.Point(15, 15);
14 |
15 | var segment = L.LineUtil.clipSegment(a, b, bounds);
16 |
17 | expect(segment[0]).to.eql(new L.Point(5, 5));
18 | expect(segment[1]).to.eql(new L.Point(10, 10));
19 |
20 | var c = new L.Point(5, -5);
21 | var d = new L.Point(20, 10);
22 |
23 | var segment2 = L.LineUtil.clipSegment(c, d, bounds);
24 |
25 | expect(segment2[0]).to.eql(new L.Point(10, 0));
26 | expect(segment2[1]).to.eql(new L.Point(15, 5));
27 | });
28 |
29 | it('uses last bit code and reject segments out of bounds', function () {
30 | var a = new L.Point(15, 15);
31 | var b = new L.Point(25, 20);
32 | var segment = L.LineUtil.clipSegment(a, b, bounds, true);
33 |
34 | expect(segment).to.be(false);
35 | });
36 |
37 | it('can round numbers in clipped bounds', function () {
38 | var a = new L.Point(4, 5);
39 | var b = new L.Point(8, 6);
40 |
41 | var segment1 = L.LineUtil.clipSegment(a, b, bounds);
42 |
43 | expect(segment1[0]).to.eql(new L.Point(5, 5.25));
44 | expect(segment1[1]).to.eql(b);
45 |
46 | var segment2 = L.LineUtil.clipSegment(a, b, bounds, false, true);
47 |
48 | expect(segment2[0]).to.eql(new L.Point(5, 5));
49 | expect(segment2[1]).to.eql(b);
50 | });
51 | });
52 |
53 | describe('#pointToSegmentDistance & #closestPointOnSegment', function () {
54 |
55 | var p1 = new L.Point(0, 10);
56 | var p2 = new L.Point(10, 0);
57 | var p = new L.Point(0, 0);
58 |
59 | it('calculates distance from point to segment', function () {
60 | expect(L.LineUtil.pointToSegmentDistance(p, p1, p2)).to.eql(Math.sqrt(200) / 2);
61 | });
62 |
63 | it('calculates point closest to segment', function () {
64 | expect(L.LineUtil.closestPointOnSegment(p, p1, p2)).to.eql(new L.Point(5, 5));
65 | });
66 | });
67 |
68 | describe('#simplify', function () {
69 | it('simplifies polylines according to tolerance', function () {
70 | var points = [
71 | new L.Point(0, 0),
72 | new L.Point(0.01, 0),
73 | new L.Point(0.5, 0.01),
74 | new L.Point(0.7, 0),
75 | new L.Point(1, 0),
76 | new L.Point(1.999, 0.999),
77 | new L.Point(2, 1)
78 | ];
79 |
80 | var simplified = L.LineUtil.simplify(points, 0.1);
81 |
82 | expect(simplified).to.eql([
83 | new L.Point(0, 0),
84 | new L.Point(1, 0),
85 | new L.Point(2, 1)
86 | ]);
87 | });
88 | });
89 |
90 | });
91 |
--------------------------------------------------------------------------------
/spec/suites/geometry/PolyUtilSpec.js:
--------------------------------------------------------------------------------
1 | describe('PolyUtil', function () {
2 |
3 | describe('#clipPolygon', function () {
4 | it('clips polygon by bounds', function () {
5 | var bounds = L.bounds([0, 0], [10, 10]);
6 |
7 | var points = [
8 | new L.Point(5, 5),
9 | new L.Point(15, 10),
10 | new L.Point(10, 15)
11 | ];
12 |
13 | // check clip without rounding
14 | var clipped = L.PolyUtil.clipPolygon(points, bounds);
15 |
16 | for (var i = 0, len = clipped.length; i < len; i++) {
17 | delete clipped[i]._code;
18 | }
19 |
20 | expect(clipped).to.eql([
21 | new L.Point(7.5, 10),
22 | new L.Point(5, 5),
23 | new L.Point(10, 7.5),
24 | new L.Point(10, 10)
25 | ]);
26 |
27 | // check clip with rounding
28 | var clippedRounded = L.PolyUtil.clipPolygon(points, bounds, true);
29 |
30 | for (i = 0, len = clippedRounded.length; i < len; i++) {
31 | delete clippedRounded[i]._code;
32 | }
33 |
34 | expect(clippedRounded).to.eql([
35 | new L.Point(8, 10),
36 | new L.Point(5, 5),
37 | new L.Point(10, 8),
38 | new L.Point(10, 10)
39 | ]);
40 | });
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/spec/suites/geometry/TransformationSpec.js:
--------------------------------------------------------------------------------
1 | describe("Transformation", function () {
2 | var t, p;
3 |
4 | beforeEach(function () {
5 | t = new L.Transformation(1, 2, 3, 4);
6 | p = new L.Point(10, 20);
7 | });
8 |
9 | describe('#transform', function () {
10 | it("performs a transformation", function () {
11 | var p2 = t.transform(p, 2);
12 | expect(p2).to.eql(new L.Point(24, 128));
13 | });
14 | it('assumes a scale of 1 if not specified', function () {
15 | var p2 = t.transform(p);
16 | expect(p2).to.eql(new L.Point(12, 64));
17 | });
18 | });
19 |
20 | describe('#untransform', function () {
21 | it("performs a reverse transformation", function () {
22 | var p2 = t.transform(p, 2);
23 | var p3 = t.untransform(p2, 2);
24 | expect(p3).to.eql(p);
25 | });
26 | it('assumes a scale of 1 if not specified', function () {
27 | var p2 = t.transform(p);
28 | expect(t.untransform(new L.Point(12, 64))).to.eql(new L.Point(10, 20));
29 | });
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/spec/suites/layer/FeatureGroupSpec.js:
--------------------------------------------------------------------------------
1 | describe('FeatureGroup', function () {
2 | var map;
3 | beforeEach(function () {
4 | map = L.map(document.createElement('div'));
5 | map.setView([0, 0], 1);
6 | });
7 | describe("#_propagateEvent", function () {
8 | var marker;
9 | beforeEach(function () {
10 | marker = L.marker([0, 0]);
11 | });
12 | describe("when a Marker is added to multiple FeatureGroups ", function () {
13 | it("e.layer should be the Marker", function () {
14 | var fg1 = L.featureGroup(),
15 | fg2 = L.featureGroup();
16 |
17 | fg1.addLayer(marker);
18 | fg2.addLayer(marker);
19 |
20 | var wasClicked1,
21 | wasClicked2;
22 |
23 | fg2.on('click', function (e) {
24 | expect(e.layer).to.be(marker);
25 | expect(e.target).to.be(fg2);
26 | wasClicked2 = true;
27 | });
28 |
29 | fg1.on('click', function (e) {
30 | expect(e.layer).to.be(marker);
31 | expect(e.target).to.be(fg1);
32 | wasClicked1 = true;
33 | });
34 |
35 | marker.fire('click', {type: 'click'}, true);
36 |
37 | expect(wasClicked1).to.be(true);
38 | expect(wasClicked2).to.be(true);
39 | });
40 | });
41 | });
42 | describe('addLayer', function () {
43 | it('adds the layer', function () {
44 | var fg = L.featureGroup(),
45 | marker = L.marker([0, 0]);
46 |
47 | expect(fg.hasLayer(marker)).to.be(false);
48 |
49 | fg.addLayer(marker);
50 |
51 | expect(fg.hasLayer(marker)).to.be(true);
52 | });
53 | it('supports non-evented layers', function () {
54 | var fg = L.featureGroup(),
55 | g = L.layerGroup();
56 |
57 | expect(fg.hasLayer(g)).to.be(false);
58 |
59 | fg.addLayer(g);
60 |
61 | expect(fg.hasLayer(g)).to.be(true);
62 | });
63 | });
64 | describe('removeLayer', function () {
65 | it('removes the layer passed to it', function () {
66 | var fg = L.featureGroup(),
67 | marker = L.marker([0, 0]);
68 |
69 | fg.addLayer(marker);
70 | expect(fg.hasLayer(marker)).to.be(true);
71 |
72 | fg.removeLayer(marker);
73 | expect(fg.hasLayer(marker)).to.be(false);
74 | });
75 | it('removes the layer passed to it by id', function () {
76 | var fg = L.featureGroup(),
77 | marker = L.marker([0, 0]);
78 |
79 | fg.addLayer(marker);
80 | expect(fg.hasLayer(marker)).to.be(true);
81 |
82 | fg.removeLayer(L.stamp(marker));
83 | expect(fg.hasLayer(marker)).to.be(false);
84 | });
85 | });
86 | });
87 |
--------------------------------------------------------------------------------
/spec/suites/layer/ImageOverlaySpec.js:
--------------------------------------------------------------------------------
1 | describe('ImageOverlay', function () {
2 | describe('#setStyle', function () {
3 | it('sets opacity', function () {
4 | var overlay = L.imageOverlay().setStyle({opacity: 0.5});
5 | expect(overlay.options.opacity).to.equal(0.5);
6 | });
7 | });
8 | describe('#setBounds', function () {
9 | it('sets bounds', function () {
10 | var bounds = new L.LatLngBounds(
11 | new L.LatLng(14, 12),
12 | new L.LatLng(30, 40));
13 | var overlay = L.imageOverlay().setBounds(bounds);
14 | expect(overlay._bounds).to.equal(bounds);
15 | });
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/spec/suites/layer/LayerGroupSpec.js:
--------------------------------------------------------------------------------
1 | describe('LayerGroup', function () {
2 | describe("#hasLayer", function () {
3 | it("returns false when passed undefined, null, or false", function () {
4 | var lg = L.layerGroup();
5 | expect(lg.hasLayer(undefined)).to.equal(false);
6 | expect(lg.hasLayer(null)).to.equal(false);
7 | expect(lg.hasLayer(false)).to.equal(false);
8 | });
9 | });
10 |
11 | describe("#addLayer", function () {
12 | it('adds a layer', function () {
13 | var lg = L.layerGroup(),
14 | marker = L.marker([0, 0]);
15 |
16 | expect(lg.addLayer(marker)).to.eql(lg);
17 |
18 | expect(lg.hasLayer(marker)).to.be(true);
19 | });
20 | });
21 |
22 | describe("#removeLayer", function () {
23 | it('removes a layer', function () {
24 | var lg = L.layerGroup(),
25 | marker = L.marker([0, 0]);
26 |
27 | lg.addLayer(marker);
28 | expect(lg.removeLayer(marker)).to.eql(lg);
29 |
30 | expect(lg.hasLayer(marker)).to.be(false);
31 | });
32 | });
33 |
34 | describe("#clearLayers", function () {
35 | it('removes all layers', function () {
36 | var lg = L.layerGroup(),
37 | marker = L.marker([0, 0]);
38 |
39 | lg.addLayer(marker);
40 | expect(lg.clearLayers()).to.eql(lg);
41 |
42 | expect(lg.hasLayer(marker)).to.be(false);
43 | });
44 | });
45 |
46 | describe("#getLayers", function () {
47 | it('gets all layers', function () {
48 | var lg = L.layerGroup(),
49 | marker = L.marker([0, 0]);
50 |
51 | lg.addLayer(marker);
52 |
53 | expect(lg.getLayers()).to.eql([marker]);
54 | });
55 | });
56 |
57 | describe("#eachLayer", function () {
58 | it('iterates over all layers', function () {
59 | var lg = L.layerGroup(),
60 | marker = L.marker([0, 0]),
61 | ctx = {foo: 'bar'};
62 |
63 | lg.addLayer(marker);
64 |
65 | lg.eachLayer(function (layer) {
66 | expect(layer).to.eql(marker);
67 | expect(this).to.eql(ctx);
68 | }, ctx);
69 | });
70 | });
71 | });
72 |
--------------------------------------------------------------------------------
/spec/suites/layer/vector/CanvasSpec.js:
--------------------------------------------------------------------------------
1 | describe('Canvas', function () {
2 |
3 | var c, map, p2ll, latLngs;
4 |
5 | before(function () {
6 | c = document.createElement('div');
7 | c.style.width = '400px';
8 | c.style.height = '400px';
9 | c.style.position = 'absolute';
10 | c.style.top = '0';
11 | c.style.left = '0';
12 | document.body.appendChild(c);
13 | map = new L.Map(c, {preferCanvas: true, zoomControl: false});
14 | map.setView([0, 0], 6);
15 | p2ll = function (x, y) {
16 | return map.layerPointToLatLng([x, y]);
17 | };
18 | latLngs = [p2ll(0, 0), p2ll(0, 100), p2ll(100, 100), p2ll(100, 0)];
19 | });
20 |
21 | after(function () {
22 | document.body.removeChild(c);
23 | });
24 |
25 | describe("#events", function () {
26 | var layer;
27 |
28 | beforeEach(function () {
29 | layer = L.polygon(latLngs).addTo(map);
30 | });
31 |
32 | afterEach(function () {
33 | layer.remove();
34 | });
35 |
36 | it("should fire event when layer contains mouse", function () {
37 | var spy = sinon.spy();
38 | layer.on('click', spy);
39 | happen.at('click', 50, 50); // Click on the layer.
40 | expect(spy.callCount).to.eql(1);
41 | happen.at('click', 150, 150); // Click outside layer.
42 | expect(spy.callCount).to.eql(1);
43 | layer.off("click", spy);
44 | });
45 |
46 | it("DOM events propagate from canvas polygon to map", function () {
47 | var spy = sinon.spy();
48 | map.on("click", spy);
49 | happen.at('click', 50, 50);
50 | expect(spy.callCount).to.eql(1);
51 | map.off("click", spy);
52 | });
53 |
54 | it("DOM events fired on canvas polygon can be cancelled before being caught by the map", function () {
55 | var mapSpy = sinon.spy();
56 | var layerSpy = sinon.spy();
57 | map.on("click", mapSpy);
58 | layer.on("click", L.DomEvent.stopPropagation).on("click", layerSpy);
59 | happen.at('click', 50, 50);
60 | expect(layerSpy.callCount).to.eql(1);
61 | expect(mapSpy.callCount).to.eql(0);
62 | map.off("click", mapSpy);
63 | layer.off("click", L.DomEvent.stopPropagation).off("click", layerSpy);
64 | });
65 |
66 | it("DOM events fired on canvas polygon are propagated only once to the map even when two layers contains the event", function () {
67 | var spy = sinon.spy();
68 | var layer2 = L.polygon(latLngs).addTo(map);
69 | map.on("click", spy);
70 | happen.at('click', 50, 50);
71 | expect(spy.callCount).to.eql(1);
72 | layer2.remove();
73 | map.off("click", spy);
74 | });
75 |
76 | });
77 |
78 | describe("#events(interactive=false)", function () {
79 | var layer;
80 |
81 | beforeEach(function () {
82 | layer = L.polygon(latLngs, {interactive: false}).addTo(map);
83 | });
84 |
85 | afterEach(function () {
86 | layer.remove();
87 | });
88 |
89 | it("should not fire click when not interactive", function () {
90 | var spy = sinon.spy();
91 | layer.on('click', spy);
92 | happen.at('click', 50, 50); // Click on the layer.
93 | expect(spy.callCount).to.eql(0);
94 | happen.at('click', 150, 150); // Click outside layer.
95 | expect(spy.callCount).to.eql(0);
96 | layer.off("click", spy);
97 | });
98 |
99 | });
100 |
101 | describe('#dashArray', function () {
102 | it('can add polyline with dashArray', function () {
103 | var layer = L.polygon(latLngs, {
104 | dashArray: "5,5"
105 | }).addTo(map);
106 | });
107 | it('can setStyle with dashArray', function () {
108 | var layer = L.polygon(latLngs).addTo(map);
109 | layer.setStyle({
110 | dashArray: "5,5"
111 | });
112 | });
113 | });
114 |
115 | });
116 |
--------------------------------------------------------------------------------
/spec/suites/layer/vector/CircleMarkerSpec.js:
--------------------------------------------------------------------------------
1 | describe('CircleMarker', function () {
2 | describe("#_radius", function () {
3 | var map;
4 | beforeEach(function () {
5 | map = L.map(document.createElement('div'));
6 | map.setView([0, 0], 1);
7 | });
8 | describe("when a CircleMarker is added to the map ", function () {
9 | describe("with a radius set as an option", function () {
10 | it("takes that radius", function () {
11 | var marker = L.circleMarker([0, 0], {radius: 20}).addTo(map);
12 |
13 | expect(marker._radius).to.be(20);
14 | });
15 | });
16 |
17 | describe("and radius is set before adding it", function () {
18 | it("takes that radius", function () {
19 | var marker = L.circleMarker([0, 0], {radius: 20});
20 | marker.setRadius(15);
21 | marker.addTo(map);
22 | expect(marker._radius).to.be(15);
23 | });
24 | });
25 |
26 | describe("and radius is set after adding it", function () {
27 | it("takes that radius", function () {
28 | var marker = L.circleMarker([0, 0], {radius: 20});
29 | marker.addTo(map);
30 | marker.setRadius(15);
31 | expect(marker._radius).to.be(15);
32 | });
33 | });
34 |
35 | describe("and setStyle is used to change the radius after adding", function () {
36 | it("takes the given radius", function () {
37 | var marker = L.circleMarker([0, 0], {radius: 20});
38 | marker.addTo(map);
39 | marker.setStyle({radius: 15});
40 | expect(marker._radius).to.be(15);
41 | });
42 | });
43 | describe("and setStyle is used to change the radius before adding", function () {
44 | it("takes the given radius", function () {
45 | var marker = L.circleMarker([0, 0], {radius: 20});
46 | marker.setStyle({radius: 15});
47 | marker.addTo(map);
48 | expect(marker._radius).to.be(15);
49 | });
50 | });
51 | });
52 | });
53 | });
54 |
--------------------------------------------------------------------------------
/spec/suites/layer/vector/CircleSpec.js:
--------------------------------------------------------------------------------
1 | describe('Circle', function () {
2 |
3 | describe('#init', function () {
4 |
5 | it('uses default radius if not given', function () {
6 | var circle = L.circle([0, 0]);
7 | expect(circle.getRadius()).to.eql(10);
8 | });
9 |
10 | it('throws error if radius is NaN', function () {
11 | expect(function () {
12 | L.circle([0, 0], NaN);
13 | }).to.throwException('Circle radius cannot be NaN');
14 | });
15 |
16 | });
17 |
18 | describe('#getBounds', function () {
19 |
20 | var map, circle;
21 |
22 | beforeEach(function () {
23 | map = L.map(document.createElement('div')).setView([0, 0], 4);
24 | circle = L.circle([50, 30], {radius: 200}).addTo(map);
25 | });
26 |
27 | it('returns bounds', function () {
28 | var bounds = circle.getBounds();
29 |
30 | expect(bounds.getSouthWest()).nearLatLng(new L.LatLng(49.94347, 29.91211));
31 | expect(bounds.getNorthEast()).nearLatLng(new L.LatLng(50.05646, 30.08789));
32 | });
33 | });
34 |
35 | describe('Legacy factory', function () {
36 |
37 | var map, circle;
38 |
39 | beforeEach(function () {
40 | map = L.map(document.createElement('div')).setView([0, 0], 4);
41 | circle = L.circle([50, 30], 200).addTo(map);
42 | });
43 |
44 | it('returns same bounds as 1.0 factory', function () {
45 | var bounds = circle.getBounds();
46 |
47 | expect(bounds.getSouthWest()).nearLatLng(new L.LatLng(49.94347, 29.91211));
48 | expect(bounds.getNorthEast()).nearLatLng(new L.LatLng(50.05646, 30.08789));
49 | });
50 | });
51 |
52 | });
53 |
--------------------------------------------------------------------------------
/spec/suites/layer/vector/PathSpec.js:
--------------------------------------------------------------------------------
1 | describe('Path', function () {
2 | describe('#bringToBack', function () {
3 | it('is a no-op for layers not on a map', function () {
4 | var path = new L.Path();
5 | expect(path.bringToBack()).to.equal(path);
6 | });
7 | });
8 |
9 | describe('#bringToFront', function () {
10 | it('is a no-op for layers not on a map', function () {
11 | var path = new L.Path();
12 | expect(path.bringToFront()).to.equal(path);
13 | });
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/spec/suites/layer/vector/PolylineGeometrySpec.js:
--------------------------------------------------------------------------------
1 | describe('PolylineGeometry', function () {
2 |
3 | var c = document.createElement('div');
4 | c.style.width = '400px';
5 | c.style.height = '400px';
6 | var map = new L.Map(c);
7 | map.setView(new L.LatLng(55.8, 37.6), 6);
8 |
9 | describe("#distanceTo", function () {
10 | it("calculates distances to points", function () {
11 | var p1 = map.latLngToLayerPoint(new L.LatLng(55.8, 37.6));
12 | var p2 = map.latLngToLayerPoint(new L.LatLng(57.123076977278, 44.861962891635));
13 | var latlngs = [[56.485503424111, 35.545556640339], [55.972522915346, 36.116845702918], [55.502459116923, 34.930322265253], [55.31534617509, 38.973291015816]]
14 | .map(function (ll) {
15 | return new L.LatLng(ll[0], ll[1]);
16 | });
17 | var polyline = new L.Polyline([], {
18 | 'noClip': true
19 | });
20 | map.addLayer(polyline);
21 |
22 | expect(polyline.closestLayerPoint(p1)).to.be(null);
23 |
24 | polyline.setLatLngs(latlngs);
25 | var point = polyline.closestLayerPoint(p1);
26 | expect(point).not.to.be(null);
27 | expect(point.distance).to.not.be(Infinity);
28 | expect(point.distance).to.not.be(NaN);
29 |
30 | var point2 = polyline.closestLayerPoint(p2);
31 |
32 | expect(point.distance).to.be.lessThan(point2.distance);
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/spec/suites/map/handler/Map.TouchZoomSpec.js:
--------------------------------------------------------------------------------
1 | describe("Map.TouchZoom", function () {
2 | it.skipIfNotTouch("Increases zoom when pinching out", function (done) {
3 | var container = document.createElement('div');
4 | container.style.width = container.style.height = '600px';
5 | container.style.top = container.style.left = 0;
6 | container.style.position = 'absolute';
7 | document.body.appendChild(container);
8 |
9 | var map = new L.Map(container, {
10 | touchZoom: true,
11 | inertia: false,
12 | zoomAnimation: false // If true, the test has to wait extra 250msec
13 | });
14 | map.setView([0, 0], 1);
15 |
16 | var hand = new Hand({
17 | timing: 'fastframe',
18 | onStop: function () {
19 | map.once('zoomend', function () {
20 | var center = map.getCenter();
21 | var zoom = map.getZoom();
22 | document.body.removeChild(container);
23 | expect(center.lat).to.be(0);
24 | expect(center.lng).to.be(0);
25 |
26 | // Initial zoom 1, initial distance 50px, final distance 450px
27 | expect(zoom).to.be(4);
28 |
29 | done();
30 | });
31 | }
32 | });
33 | var f1 = hand.growFinger('touch');
34 | var f2 = hand.growFinger('touch');
35 |
36 | hand.sync(5);
37 | f1.wait(100).moveTo(275, 300, 0)
38 | .down().moveBy(-200, 0, 500).up(100);
39 | f2.wait(100).moveTo(325, 300, 0)
40 | .down().moveBy(200, 0, 500).up(100);
41 | });
42 |
43 |
44 | it.skipIfNotTouch("Decreases zoom when pinching in", function (done) {
45 | var container = document.createElement('div');
46 | container.style.width = container.style.height = '600px';
47 | container.style.top = container.style.left = 0;
48 | container.style.position = 'absolute';
49 | document.body.appendChild(container);
50 |
51 | var map = new L.Map(container, {
52 | touchZoom: true,
53 | inertia: false,
54 | zoomAnimation: false // If true, the test has to wait extra 250msec
55 | });
56 | map.setView([0, 0], 4);
57 |
58 | var hand = new Hand({
59 | timing: 'fastframe',
60 | onStop: function () {
61 | map.once('zoomend', function () {
62 | var center = map.getCenter();
63 | var zoom = map.getZoom();
64 | document.body.removeChild(container);
65 | expect(center.lat).to.be(0);
66 | expect(center.lng).to.be(0);
67 |
68 | // Initial zoom 4, initial distance 450px, final distance 50px
69 | expect(zoom).to.be(1);
70 |
71 | done();
72 | });
73 | }
74 | });
75 | var f1 = hand.growFinger('touch');
76 | var f2 = hand.growFinger('touch');
77 |
78 | hand.sync(5);
79 | f1.wait(100).moveTo(75, 300, 0)
80 | .down().moveBy(200, 0, 500).up(100);
81 | f2.wait(100).moveTo(525, 300, 0)
82 | .down().moveBy(-200, 0, 500).up(100);
83 | });
84 |
85 |
86 |
87 | });
88 |
--------------------------------------------------------------------------------
/src/Leaflet.js:
--------------------------------------------------------------------------------
1 |
2 | var L = {
3 | version: 'dev'
4 | };
5 |
6 | function expose() {
7 | var oldL = window.L;
8 |
9 | L.noConflict = function () {
10 | window.L = oldL;
11 | return this;
12 | };
13 |
14 | window.L = L;
15 | }
16 |
17 | // define Leaflet for Node module pattern loaders, including Browserify
18 | if (typeof module === 'object' && typeof module.exports === 'object') {
19 | module.exports = L;
20 |
21 | // define Leaflet as an AMD module
22 | } else if (typeof define === 'function' && define.amd) {
23 | define(L);
24 | }
25 |
26 | // define Leaflet as a global L variable, saving the original L to restore later if needed
27 | if (typeof window !== 'undefined') {
28 | expose();
29 | }
30 |
--------------------------------------------------------------------------------
/src/copyright.js:
--------------------------------------------------------------------------------
1 | /*
2 | Leaflet {VERSION}, a JS library for interactive maps. http://leafletjs.com
3 | (c) 2010-2015 Vladimir Agafonkin, (c) 2010-2011 CloudMade
4 | */
5 |
--------------------------------------------------------------------------------
/src/core/Class.js:
--------------------------------------------------------------------------------
1 |
2 | // @class Class
3 | // @aka L.Class
4 |
5 | // @section
6 | // @uninheritable
7 |
8 | // Thanks to John Resig and Dean Edwards for inspiration!
9 |
10 | L.Class = function () {};
11 |
12 | L.Class.extend = function (props) {
13 |
14 | // @function extend(props: Object): Function
15 | // [Extends the current class](#class-inheritance) given the properties to be included.
16 | // Returns a Javascript function that is a class constructor (to be called with `new`).
17 | var NewClass = function () {
18 |
19 | // call the constructor
20 | if (this.initialize) {
21 | this.initialize.apply(this, arguments);
22 | }
23 |
24 | // call all constructor hooks
25 | this.callInitHooks();
26 | };
27 |
28 | var parentProto = NewClass.__super__ = this.prototype;
29 |
30 | var proto = L.Util.create(parentProto);
31 | proto.constructor = NewClass;
32 |
33 | NewClass.prototype = proto;
34 |
35 | // inherit parent's statics
36 | for (var i in this) {
37 | if (this.hasOwnProperty(i) && i !== 'prototype') {
38 | NewClass[i] = this[i];
39 | }
40 | }
41 |
42 | // mix static properties into the class
43 | if (props.statics) {
44 | L.extend(NewClass, props.statics);
45 | delete props.statics;
46 | }
47 |
48 | // mix includes into the prototype
49 | if (props.includes) {
50 | L.Util.extend.apply(null, [proto].concat(props.includes));
51 | delete props.includes;
52 | }
53 |
54 | // merge options
55 | if (proto.options) {
56 | props.options = L.Util.extend(L.Util.create(proto.options), props.options);
57 | }
58 |
59 | // mix given properties into the prototype
60 | L.extend(proto, props);
61 |
62 | proto._initHooks = [];
63 |
64 | // add method for calling all hooks
65 | proto.callInitHooks = function () {
66 |
67 | if (this._initHooksCalled) { return; }
68 |
69 | if (parentProto.callInitHooks) {
70 | parentProto.callInitHooks.call(this);
71 | }
72 |
73 | this._initHooksCalled = true;
74 |
75 | for (var i = 0, len = proto._initHooks.length; i < len; i++) {
76 | proto._initHooks[i].call(this);
77 | }
78 | };
79 |
80 | return NewClass;
81 | };
82 |
83 |
84 | // @function include(properties: Object): this
85 | // [Includes a mixin](#class-includes) into the current class.
86 | L.Class.include = function (props) {
87 | L.extend(this.prototype, props);
88 | return this;
89 | };
90 |
91 | // @function mergeOptions(options: Object): this
92 | // [Merges `options`](#class-options) into the defaults of the class.
93 | L.Class.mergeOptions = function (options) {
94 | L.extend(this.prototype.options, options);
95 | return this;
96 | };
97 |
98 | // @function addInitHook(fn: Function): this
99 | // Adds a [constructor hook](#class-constructor-hooks) to the class.
100 | L.Class.addInitHook = function (fn) { // (Function) || (String, args...)
101 | var args = Array.prototype.slice.call(arguments, 1);
102 |
103 | var init = typeof fn === 'function' ? fn : function () {
104 | this[fn].apply(this, args);
105 | };
106 |
107 | this.prototype._initHooks = this.prototype._initHooks || [];
108 | this.prototype._initHooks.push(init);
109 | return this;
110 | };
111 |
--------------------------------------------------------------------------------
/src/core/Handler.js:
--------------------------------------------------------------------------------
1 | /*
2 | L.Handler is a base class for handler classes that are used internally to inject
3 | interaction features like dragging to classes like Map and Marker.
4 | */
5 |
6 | // @class Handler
7 | // @aka L.Handler
8 | // Abstract class for map interaction handlers
9 |
10 | L.Handler = L.Class.extend({
11 | initialize: function (map) {
12 | this._map = map;
13 | },
14 |
15 | // @method enable()
16 | // Enables the handler
17 | enable: function () {
18 | if (this._enabled) { return; }
19 |
20 | this._enabled = true;
21 | this.addHooks();
22 | },
23 |
24 | // @method disable()
25 | // Disables the handler
26 | disable: function () {
27 | if (!this._enabled) { return; }
28 |
29 | this._enabled = false;
30 | this.removeHooks();
31 | },
32 |
33 | // @method enabled(): Boolean
34 | // Returns `true` if the handler is enabled
35 | enabled: function () {
36 | return !!this._enabled;
37 | }
38 |
39 | // @section Extension methods
40 | // Classes inheriting from `Handler` must implement the two following methods:
41 | // @method addHooks()
42 | // Called when the handler is enabled, should add event hooks.
43 | // @method removeHooks()
44 | // Called when the handler is disabled, should remove the event hooks added previously.
45 | });
46 |
--------------------------------------------------------------------------------
/src/dom/DomEvent.DoubleTap.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Extends the event handling code with double tap support for mobile browsers.
3 | */
4 |
5 | L.extend(L.DomEvent, {
6 |
7 | _touchstart: L.Browser.msPointer ? 'MSPointerDown' : L.Browser.pointer ? 'pointerdown' : 'touchstart',
8 | _touchend: L.Browser.msPointer ? 'MSPointerUp' : L.Browser.pointer ? 'pointerup' : 'touchend',
9 |
10 | // inspired by Zepto touch code by Thomas Fuchs
11 | addDoubleTapListener: function (obj, handler, id) {
12 | var last, touch,
13 | doubleTap = false,
14 | delay = 250;
15 |
16 | function onTouchStart(e) {
17 | var count;
18 |
19 | if (L.Browser.pointer) {
20 | count = L.DomEvent._pointersCount;
21 | } else {
22 | count = e.touches.length;
23 | }
24 |
25 | if (count > 1) { return; }
26 |
27 | var now = Date.now(),
28 | delta = now - (last || now);
29 |
30 | touch = e.touches ? e.touches[0] : e;
31 | doubleTap = (delta > 0 && delta <= delay);
32 | last = now;
33 | }
34 |
35 | function onTouchEnd() {
36 | if (doubleTap && !touch.cancelBubble) {
37 | if (L.Browser.pointer) {
38 | // work around .type being readonly with MSPointer* events
39 | var newTouch = {},
40 | prop, i;
41 |
42 | for (i in touch) {
43 | prop = touch[i];
44 | newTouch[i] = prop && prop.bind ? prop.bind(touch) : prop;
45 | }
46 | touch = newTouch;
47 | }
48 | touch.type = 'dblclick';
49 | handler(touch);
50 | last = null;
51 | }
52 | }
53 |
54 | var pre = '_leaflet_',
55 | touchstart = this._touchstart,
56 | touchend = this._touchend;
57 |
58 | obj[pre + touchstart + id] = onTouchStart;
59 | obj[pre + touchend + id] = onTouchEnd;
60 | obj[pre + 'dblclick' + id] = handler;
61 |
62 | obj.addEventListener(touchstart, onTouchStart, false);
63 | obj.addEventListener(touchend, onTouchEnd, false);
64 |
65 | // On some platforms (notably, chrome on win10 + touchscreen + mouse),
66 | // the browser doesn't fire touchend/pointerup events but does fire
67 | // native dblclicks. See #4127.
68 | if (!L.Browser.edge) {
69 | obj.addEventListener('dblclick', handler, false);
70 | }
71 |
72 | return this;
73 | },
74 |
75 | removeDoubleTapListener: function (obj, id) {
76 | var pre = '_leaflet_',
77 | touchstart = obj[pre + this._touchstart + id],
78 | touchend = obj[pre + this._touchend + id],
79 | dblclick = obj[pre + 'dblclick' + id];
80 |
81 | obj.removeEventListener(this._touchstart, touchstart, false);
82 | obj.removeEventListener(this._touchend, touchend, false);
83 | if (!L.Browser.edge) {
84 | obj.removeEventListener('dblclick', dblclick, false);
85 | }
86 |
87 | return this;
88 | }
89 | });
90 |
--------------------------------------------------------------------------------
/src/dom/PosAnimation.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @class PosAnimation
3 | * @aka L.PosAnimation
4 | * @inherits Evented
5 | * Used internally for panning animations, utilizing CSS3 Transitions for modern browsers and a timer fallback for IE6-9.
6 | *
7 | * @example
8 | * ```js
9 | * var fx = new L.PosAnimation();
10 | * fx.run(el, [300, 500], 0.5);
11 | * ```
12 | *
13 | * @constructor L.PosAnimation()
14 | * Creates a `PosAnimation` object.
15 | *
16 | */
17 |
18 | L.PosAnimation = L.Evented.extend({
19 |
20 | // @method run(el: HTMLElement, newPos: Point, duration?: Number, easeLinearity?: Number)
21 | // Run an animation of a given element to a new position, optionally setting
22 | // duration in seconds (`0.25` by default) and easing linearity factor (3rd
23 | // argument of the [cubic bezier curve](http://cubic-bezier.com/#0,0,.5,1),
24 | // `0.5` by default).
25 | run: function (el, newPos, duration, easeLinearity) {
26 | this.stop();
27 |
28 | this._el = el;
29 | this._inProgress = true;
30 | this._duration = duration || 0.25;
31 | this._easeOutPower = 1 / Math.max(easeLinearity || 0.5, 0.2);
32 |
33 | this._startPos = L.DomUtil.getPosition(el);
34 | this._offset = newPos.subtract(this._startPos);
35 | this._startTime = +new Date();
36 |
37 | // @event start: Event
38 | // Fired when the animation starts
39 | this.fire('start');
40 |
41 | this._animate();
42 | },
43 |
44 | // @method stop()
45 | // Stops the animation (if currently running).
46 | stop: function () {
47 | if (!this._inProgress) { return; }
48 |
49 | this._step(true);
50 | this._complete();
51 | },
52 |
53 | _animate: function () {
54 | // animation loop
55 | this._animId = L.Util.requestAnimFrame(this._animate, this);
56 | this._step();
57 | },
58 |
59 | _step: function (round) {
60 | var elapsed = (+new Date()) - this._startTime,
61 | duration = this._duration * 1000;
62 |
63 | if (elapsed < duration) {
64 | this._runFrame(this._easeOut(elapsed / duration), round);
65 | } else {
66 | this._runFrame(1);
67 | this._complete();
68 | }
69 | },
70 |
71 | _runFrame: function (progress, round) {
72 | var pos = this._startPos.add(this._offset.multiplyBy(progress));
73 | if (round) {
74 | pos._round();
75 | }
76 | L.DomUtil.setPosition(this._el, pos);
77 |
78 | // @event step: Event
79 | // Fired continuously during the animation.
80 | this.fire('step');
81 | },
82 |
83 | _complete: function () {
84 | L.Util.cancelAnimFrame(this._animId);
85 |
86 | this._inProgress = false;
87 | // @event end: Event
88 | // Fired when the animation ends.
89 | this.fire('end');
90 | },
91 |
92 | _easeOut: function (t) {
93 | return 1 - Math.pow(1 - t, this._easeOutPower);
94 | }
95 | });
96 |
--------------------------------------------------------------------------------
/src/geo/crs/CRS.EPSG3395.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @namespace CRS
3 | * @crs L.CRS.EPSG3395
4 | *
5 | * Rarely used by some commercial tile providers. Uses Elliptical Mercator projection.
6 | */
7 |
8 | L.CRS.EPSG3395 = L.extend({}, L.CRS.Earth, {
9 | code: 'EPSG:3395',
10 | projection: L.Projection.Mercator,
11 |
12 | transformation: (function () {
13 | var scale = 0.5 / (Math.PI * L.Projection.Mercator.R);
14 | return new L.Transformation(scale, 0.5, -scale, 0.5);
15 | }())
16 | });
17 |
--------------------------------------------------------------------------------
/src/geo/crs/CRS.EPSG3857.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @namespace CRS
3 | * @crs L.CRS.EPSG3857
4 | *
5 | * The most common CRS for online maps, used by almost all free and commercial
6 | * tile providers. Uses Spherical Mercator projection. Set in by default in
7 | * Map's `crs` option.
8 | */
9 |
10 | L.CRS.EPSG3857 = L.extend({}, L.CRS.Earth, {
11 | code: 'EPSG:3857',
12 | projection: L.Projection.SphericalMercator,
13 |
14 | transformation: (function () {
15 | var scale = 0.5 / (Math.PI * L.Projection.SphericalMercator.R);
16 | return new L.Transformation(scale, 0.5, -scale, 0.5);
17 | }())
18 | });
19 |
20 | L.CRS.EPSG900913 = L.extend({}, L.CRS.EPSG3857, {
21 | code: 'EPSG:900913'
22 | });
23 |
--------------------------------------------------------------------------------
/src/geo/crs/CRS.EPSG4326.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @namespace CRS
3 | * @crs L.CRS.EPSG4326
4 | *
5 | * A common CRS among GIS enthusiasts. Uses simple Equirectangular projection.
6 | */
7 |
8 | L.CRS.EPSG4326 = L.extend({}, L.CRS.Earth, {
9 | code: 'EPSG:4326',
10 | projection: L.Projection.LonLat,
11 | transformation: new L.Transformation(1 / 180, 1, -1 / 180, 0.5)
12 | });
13 |
--------------------------------------------------------------------------------
/src/geo/crs/CRS.Earth.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @namespace CRS
3 | * @crs L.CRS.Earth
4 | *
5 | * Serves as the base for CRS that are global such that they cover the earth.
6 | * Can only be used as the base for other CRS and cannot be used directly,
7 | * since it does not have a `code`, `projection` or `transformation`. `distance()` returns
8 | * meters.
9 | */
10 |
11 | L.CRS.Earth = L.extend({}, L.CRS, {
12 | wrapLng: [-180, 180],
13 |
14 | // Mean Earth Radius, as recommended for use by
15 | // the International Union of Geodesy and Geophysics,
16 | // see http://rosettacode.org/wiki/Haversine_formula
17 | R: 6371000,
18 |
19 | // distance between two geographical points using spherical law of cosines approximation
20 | distance: function (latlng1, latlng2) {
21 | var rad = Math.PI / 180,
22 | lat1 = latlng1.lat * rad,
23 | lat2 = latlng2.lat * rad,
24 | a = Math.sin(lat1) * Math.sin(lat2) +
25 | Math.cos(lat1) * Math.cos(lat2) * Math.cos((latlng2.lng - latlng1.lng) * rad);
26 |
27 | return this.R * Math.acos(Math.min(a, 1));
28 | }
29 | });
30 |
--------------------------------------------------------------------------------
/src/geo/crs/CRS.Simple.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @namespace CRS
3 | * @crs L.CRS.Simple
4 | *
5 | * A simple CRS that maps longitude and latitude into `x` and `y` directly.
6 | * May be used for maps of flat surfaces (e.g. game maps). Note that the `y`
7 | * axis should still be inverted (going from bottom to top). `distance()` returns
8 | * simple euclidean distance.
9 | */
10 |
11 | L.CRS.Simple = L.extend({}, L.CRS, {
12 | projection: L.Projection.LonLat,
13 | transformation: new L.Transformation(1, 0, -1, 0),
14 |
15 | scale: function (zoom) {
16 | return Math.pow(2, zoom);
17 | },
18 |
19 | zoom: function (scale) {
20 | return Math.log(scale) / Math.LN2;
21 | },
22 |
23 | distance: function (latlng1, latlng2) {
24 | var dx = latlng2.lng - latlng1.lng,
25 | dy = latlng2.lat - latlng1.lat;
26 |
27 | return Math.sqrt(dx * dx + dy * dy);
28 | },
29 |
30 | infinite: true
31 | });
32 |
--------------------------------------------------------------------------------
/src/geo/projection/Projection.LonLat.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @namespace Projection
3 | * @section
4 | * Leaflet comes with a set of already defined Projections out of the box:
5 | *
6 | * @projection L.Projection.LonLat
7 | *
8 | * Equirectangular, or Plate Carree projection — the most simple projection,
9 | * mostly used by GIS enthusiasts. Directly maps `x` as longitude, and `y` as
10 | * latitude. Also suitable for flat worlds, e.g. game maps. Used by the
11 | * `EPSG:3395` and `Simple` CRS.
12 | */
13 |
14 | L.Projection = {};
15 |
16 | L.Projection.LonLat = {
17 | project: function (latlng) {
18 | return new L.Point(latlng.lng, latlng.lat);
19 | },
20 |
21 | unproject: function (point) {
22 | return new L.LatLng(point.y, point.x);
23 | },
24 |
25 | bounds: L.bounds([-180, -90], [180, 90])
26 | };
27 |
--------------------------------------------------------------------------------
/src/geo/projection/Projection.Mercator.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @namespace Projection
3 | * @projection L.Projection.Mercator
4 | *
5 | * Elliptical Mercator projection — more complex than Spherical Mercator. Takes into account that Earth is a geoid, not a perfect sphere. Used by the EPSG:3395 CRS.
6 | */
7 |
8 | L.Projection.Mercator = {
9 | R: 6378137,
10 | R_MINOR: 6356752.314245179,
11 |
12 | bounds: L.bounds([-20037508.34279, -15496570.73972], [20037508.34279, 18764656.23138]),
13 |
14 | project: function (latlng) {
15 | var d = Math.PI / 180,
16 | r = this.R,
17 | y = latlng.lat * d,
18 | tmp = this.R_MINOR / r,
19 | e = Math.sqrt(1 - tmp * tmp),
20 | con = e * Math.sin(y);
21 |
22 | var ts = Math.tan(Math.PI / 4 - y / 2) / Math.pow((1 - con) / (1 + con), e / 2);
23 | y = -r * Math.log(Math.max(ts, 1E-10));
24 |
25 | return new L.Point(latlng.lng * d * r, y);
26 | },
27 |
28 | unproject: function (point) {
29 | var d = 180 / Math.PI,
30 | r = this.R,
31 | tmp = this.R_MINOR / r,
32 | e = Math.sqrt(1 - tmp * tmp),
33 | ts = Math.exp(-point.y / r),
34 | phi = Math.PI / 2 - 2 * Math.atan(ts);
35 |
36 | for (var i = 0, dphi = 0.1, con; i < 15 && Math.abs(dphi) > 1e-7; i++) {
37 | con = e * Math.sin(phi);
38 | con = Math.pow((1 - con) / (1 + con), e / 2);
39 | dphi = Math.PI / 2 - 2 * Math.atan(ts * con) - phi;
40 | phi += dphi;
41 | }
42 |
43 | return new L.LatLng(phi * d, point.x * d / r);
44 | }
45 | };
46 |
--------------------------------------------------------------------------------
/src/geo/projection/Projection.SphericalMercator.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @namespace Projection
3 | * @projection L.Projection.SphericalMercator
4 | *
5 | * Spherical Mercator projection — the most common projection for online maps,
6 | * used by almost all free and commercial tile providers. Assumes that Earth is
7 | * a sphere. Used by the `EPSG:3857` CRS.
8 | */
9 |
10 | L.Projection.SphericalMercator = {
11 |
12 | R: 6378137,
13 | MAX_LATITUDE: 85.0511287798,
14 |
15 | project: function (latlng) {
16 | var d = Math.PI / 180,
17 | max = this.MAX_LATITUDE,
18 | lat = Math.max(Math.min(max, latlng.lat), -max),
19 | sin = Math.sin(lat * d);
20 |
21 | return new L.Point(
22 | this.R * latlng.lng * d,
23 | this.R * Math.log((1 + sin) / (1 - sin)) / 2);
24 | },
25 |
26 | unproject: function (point) {
27 | var d = 180 / Math.PI;
28 |
29 | return new L.LatLng(
30 | (2 * Math.atan(Math.exp(point.y / this.R)) - (Math.PI / 2)) * d,
31 | point.x * d / this.R);
32 | },
33 |
34 | bounds: (function () {
35 | var d = 6378137 * Math.PI;
36 | return L.bounds([-d, -d], [d, d]);
37 | })()
38 | };
39 |
--------------------------------------------------------------------------------
/src/geo/projection/Projection.leafdoc:
--------------------------------------------------------------------------------
1 |
2 | @class Projection
3 |
4 | An object with methods for projecting geographical coordinates of the world onto
5 | a flat surface (and back). See [Map projection](http://en.wikipedia.org/wiki/Map_projection).
6 |
7 | @property bounds: LatLngBounds
8 | The bounds where the projection is valid
9 |
10 | @method project(latlng: LatLng): Point
11 | Projects geographical coordinates into a 2D point.
12 |
13 | @method unproject(point: Point): LatLng
14 | The inverse of `project`. Projects a 2D point into a geographical location.
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/geometry/PolyUtil.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @namespace PolyUtil
3 | * Various utility functions for polygon geometries.
4 | */
5 |
6 | L.PolyUtil = {};
7 |
8 | /* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[]
9 | * Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgeman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)).
10 | * Used by Leaflet to only show polygon points that are on the screen or near, increasing
11 | * performance. Note that polygon points needs different algorithm for clipping
12 | * than polyline, so there's a seperate method for it.
13 | */
14 | L.PolyUtil.clipPolygon = function (points, bounds, round) {
15 | var clippedPoints,
16 | edges = [1, 4, 2, 8],
17 | i, j, k,
18 | a, b,
19 | len, edge, p,
20 | lu = L.LineUtil;
21 |
22 | for (i = 0, len = points.length; i < len; i++) {
23 | points[i]._code = lu._getBitCode(points[i], bounds);
24 | }
25 |
26 | // for each edge (left, bottom, right, top)
27 | for (k = 0; k < 4; k++) {
28 | edge = edges[k];
29 | clippedPoints = [];
30 |
31 | for (i = 0, len = points.length, j = len - 1; i < len; j = i++) {
32 | a = points[i];
33 | b = points[j];
34 |
35 | // if a is inside the clip window
36 | if (!(a._code & edge)) {
37 | // if b is outside the clip window (a->b goes out of screen)
38 | if (b._code & edge) {
39 | p = lu._getEdgeIntersection(b, a, edge, bounds, round);
40 | p._code = lu._getBitCode(p, bounds);
41 | clippedPoints.push(p);
42 | }
43 | clippedPoints.push(a);
44 |
45 | // else if b is inside the clip window (a->b enters the screen)
46 | } else if (!(b._code & edge)) {
47 | p = lu._getEdgeIntersection(b, a, edge, bounds, round);
48 | p._code = lu._getBitCode(p, bounds);
49 | clippedPoints.push(p);
50 | }
51 | }
52 | points = clippedPoints;
53 | }
54 |
55 | return points;
56 | };
57 |
--------------------------------------------------------------------------------
/src/geometry/Transformation.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @class Transformation
3 | * @aka L.Transformation
4 | *
5 | * Represents an affine transformation: a set of coefficients `a`, `b`, `c`, `d`
6 | * for transforming a point of a form `(x, y)` into `(a*x + b, c*y + d)` and doing
7 | * the reverse. Used by Leaflet in its projections code.
8 | *
9 | * @example
10 | *
11 | * ```js
12 | * var transformation = new L.Transformation(2, 5, -1, 10),
13 | * p = L.point(1, 2),
14 | * p2 = transformation.transform(p), // L.point(7, 8)
15 | * p3 = transformation.untransform(p2); // L.point(1, 2)
16 | * ```
17 | */
18 |
19 |
20 | // factory new L.Transformation(a: Number, b: Number, c: Number, d: Number)
21 | // Creates a `Transformation` object with the given coefficients.
22 | L.Transformation = function (a, b, c, d) {
23 | this._a = a;
24 | this._b = b;
25 | this._c = c;
26 | this._d = d;
27 | };
28 |
29 | L.Transformation.prototype = {
30 | // @method transform(point: Point, scale?: Number): Point
31 | // Returns a transformed point, optionally multiplied by the given scale.
32 | // Only accepts real `L.Point` instances, not arrays.
33 | transform: function (point, scale) { // (Point, Number) -> Point
34 | return this._transform(point.clone(), scale);
35 | },
36 |
37 | // destructive transform (faster)
38 | _transform: function (point, scale) {
39 | scale = scale || 1;
40 | point.x = scale * (this._a * point.x + this._b);
41 | point.y = scale * (this._c * point.y + this._d);
42 | return point;
43 | },
44 |
45 | // @method untransform(point: Point, scale?: Number): Point
46 | // Returns the reverse transformation of the given point, optionally divided
47 | // by the given scale. Only accepts real `L.Point` instances, not arrays.
48 | untransform: function (point, scale) {
49 | scale = scale || 1;
50 | return new L.Point(
51 | (point.x / scale - this._b) / this._a,
52 | (point.y / scale - this._d) / this._c);
53 | }
54 | };
55 |
--------------------------------------------------------------------------------
/src/images/layers.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/layer/FeatureGroup.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @class FeatureGroup
3 | * @aka L.FeatureGroup
4 | * @inherits LayerGroup
5 | *
6 | * Extended `LayerGroup` that also has mouse events (propagated from members of the group) and a shared bindPopup method.
7 | *
8 | * @example
9 | *
10 | * ```js
11 | * L.featureGroup([marker1, marker2, polyline])
12 | * .bindPopup('Hello world!')
13 | * .on('click', function() { alert('Clicked on a group!'); })
14 | * .addTo(map);
15 | * ```
16 | */
17 |
18 | L.FeatureGroup = L.LayerGroup.extend({
19 |
20 | addLayer: function (layer) {
21 | if (this.hasLayer(layer)) {
22 | return this;
23 | }
24 |
25 | layer.addEventParent(this);
26 |
27 | L.LayerGroup.prototype.addLayer.call(this, layer);
28 |
29 | return this.fire('layeradd', {layer: layer});
30 | },
31 |
32 | removeLayer: function (layer) {
33 | if (!this.hasLayer(layer)) {
34 | return this;
35 | }
36 | if (layer in this._layers) {
37 | layer = this._layers[layer];
38 | }
39 |
40 | layer.removeEventParent(this);
41 |
42 | L.LayerGroup.prototype.removeLayer.call(this, layer);
43 |
44 | return this.fire('layerremove', {layer: layer});
45 | },
46 |
47 | // @method setStyle(style: Path options): this
48 | // Sets the given path options to each layer of the group that has a `setStyle` method.
49 | setStyle: function (style) {
50 | return this.invoke('setStyle', style);
51 | },
52 |
53 | // @method bringToFront(): this
54 | // Brings the layer group to the top of all other layers
55 | bringToFront: function () {
56 | return this.invoke('bringToFront');
57 | },
58 |
59 | // @method bringToBack(): this
60 | // Brings the layer group to the top of all other layers
61 | bringToBack: function () {
62 | return this.invoke('bringToBack');
63 | },
64 |
65 | // @method getBounds(): LatLngBounds
66 | // Returns the LatLngBounds of the Feature Group (created from bounds and coordinates of its children).
67 | getBounds: function () {
68 | var bounds = new L.LatLngBounds();
69 |
70 | for (var id in this._layers) {
71 | var layer = this._layers[id];
72 | bounds.extend(layer.getBounds ? layer.getBounds() : layer.getLatLng());
73 | }
74 | return bounds;
75 | }
76 | });
77 |
78 | // @factory L.featureGroup(layers: Layer[])
79 | // Create a feature group, optionally given an initial set of layers.
80 | L.featureGroup = function (layers) {
81 | return new L.FeatureGroup(layers);
82 | };
83 |
--------------------------------------------------------------------------------
/src/layer/marker/DivIcon.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @class DivIcon
3 | * @aka L.DivIcon
4 | * @inherits Icon
5 | *
6 | * Represents a lightweight icon for markers that uses a simple ``
7 | * element instead of an image. Inherits from `Icon` but ignores the `iconUrl` and shadow options.
8 | *
9 | * @example
10 | * ```js
11 | * var myIcon = L.divIcon({className: 'my-div-icon'});
12 | * // you can set .my-div-icon styles in CSS
13 | *
14 | * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);
15 | * ```
16 | *
17 | * By default, it has a 'leaflet-div-icon' CSS class and is styled as a little white square with a shadow.
18 | */
19 |
20 | L.DivIcon = L.Icon.extend({
21 | options: {
22 | // @section
23 | // @aka DivIcon options
24 | iconSize: [12, 12], // also can be set through CSS
25 |
26 | // iconAnchor: (Point),
27 | // popupAnchor: (Point),
28 |
29 | // @option html: String = ''
30 | // Custom HTML code to put inside the div element, empty by default.
31 | html: false,
32 |
33 | // @option bgPos: Point = [0, 0]
34 | // Optional relative position of the background, in pixels
35 | bgPos: null,
36 |
37 | className: 'leaflet-div-icon'
38 | },
39 |
40 | createIcon: function (oldIcon) {
41 | var div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'),
42 | options = this.options;
43 |
44 | div.innerHTML = options.html !== false ? options.html : '';
45 |
46 | if (options.bgPos) {
47 | var bgPos = L.point(options.bgPos);
48 | div.style.backgroundPosition = (-bgPos.x) + 'px ' + (-bgPos.y) + 'px';
49 | }
50 | this._setIconStyles(div, 'icon');
51 |
52 | return div;
53 | },
54 |
55 | createShadow: function () {
56 | return null;
57 | }
58 | });
59 |
60 | // @factory L.divIcon(options: DivIcon options)
61 | // Creates a `DivIcon` instance with the given options.
62 | L.divIcon = function (options) {
63 | return new L.DivIcon(options);
64 | };
65 |
--------------------------------------------------------------------------------
/src/layer/marker/Icon.Default.js:
--------------------------------------------------------------------------------
1 | /*
2 | * L.Icon.Default is the blue marker icon used by default in Leaflet.
3 | */
4 |
5 | L.Icon.Default = L.Icon.extend({
6 |
7 | options: {
8 | iconSize: [25, 41],
9 | iconAnchor: [12, 41],
10 | popupAnchor: [1, -34],
11 | shadowSize: [41, 41]
12 | },
13 |
14 | _getIconUrl: function (name) {
15 | var key = name + 'Url';
16 |
17 | if (this.options[key]) {
18 | return this.options[key];
19 | }
20 |
21 | var path = L.Icon.Default.imagePath;
22 |
23 | if (!path) {
24 | throw new Error('Couldn\'t autodetect L.Icon.Default.imagePath, set it manually.');
25 | }
26 |
27 | return path + '/marker-' + name + (L.Browser.retina && name === 'icon' ? '-2x' : '') + '.png';
28 | }
29 | });
30 |
31 | L.Icon.Default.imagePath = (function () {
32 | var scripts = document.getElementsByTagName('script'),
33 | leafletRe = /[\/^]leaflet[\-\._]?([\w\-\._]*)\.js\??/;
34 |
35 | var i, len, src, path;
36 |
37 | for (i = 0, len = scripts.length; i < len; i++) {
38 | src = scripts[i].src || '';
39 |
40 | if (src.match(leafletRe)) {
41 | path = src.split(leafletRe)[0];
42 | return (path ? path + '/' : '') + 'images';
43 | }
44 | }
45 | }());
46 |
--------------------------------------------------------------------------------
/src/layer/marker/Marker.Drag.js:
--------------------------------------------------------------------------------
1 | /*
2 | * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable.
3 | */
4 |
5 |
6 | /* @namespace Marker
7 | * @section Interaction handlers
8 | *
9 | * Interaction handlers are properties of a marker instance that allow you to control interaction behavior in runtime, enabling or disabling certain features such as dragging (see `Handler` methods). Example:
10 | *
11 | * ```js
12 | * marker.dragging.disable();
13 | * ```
14 | *
15 | * @property dragging: Handler
16 | * Marker dragging handler (by both mouse and touch).
17 | */
18 |
19 | L.Handler.MarkerDrag = L.Handler.extend({
20 | initialize: function (marker) {
21 | this._marker = marker;
22 | },
23 |
24 | addHooks: function () {
25 | var icon = this._marker._icon;
26 |
27 | if (!this._draggable) {
28 | this._draggable = new L.Draggable(icon, icon, true);
29 | }
30 |
31 | this._draggable.on({
32 | dragstart: this._onDragStart,
33 | drag: this._onDrag,
34 | dragend: this._onDragEnd
35 | }, this).enable();
36 |
37 | L.DomUtil.addClass(icon, 'leaflet-marker-draggable');
38 | },
39 |
40 | removeHooks: function () {
41 | this._draggable.off({
42 | dragstart: this._onDragStart,
43 | drag: this._onDrag,
44 | dragend: this._onDragEnd
45 | }, this).disable();
46 |
47 | if (this._marker._icon) {
48 | L.DomUtil.removeClass(this._marker._icon, 'leaflet-marker-draggable');
49 | }
50 | },
51 |
52 | moved: function () {
53 | return this._draggable && this._draggable._moved;
54 | },
55 |
56 | _onDragStart: function () {
57 | // @section Dragging events
58 | // @event dragstart: Event
59 | // Fired when the user starts dragging the marker.
60 |
61 | // @event movestart: Event
62 | // Fired when the marker starts moving (because of dragging).
63 | this._marker
64 | .closePopup()
65 | .fire('movestart')
66 | .fire('dragstart');
67 | },
68 |
69 | _onDrag: function (e) {
70 | var marker = this._marker,
71 | shadow = marker._shadow,
72 | iconPos = L.DomUtil.getPosition(marker._icon),
73 | latlng = marker._map.layerPointToLatLng(iconPos);
74 |
75 | // update shadow position
76 | if (shadow) {
77 | L.DomUtil.setPosition(shadow, iconPos);
78 | }
79 |
80 | marker._latlng = latlng;
81 | e.latlng = latlng;
82 |
83 | // @event drag: Event
84 | // Fired repeatedly while the user drags the marker.
85 | marker
86 | .fire('move', e)
87 | .fire('drag', e);
88 | },
89 |
90 | _onDragEnd: function (e) {
91 | // @event dragend: DragEndEvent
92 | // Fired when the user stops dragging the marker.
93 |
94 | // @event moveend: Event
95 | // Fired when the marker stops moving (because of dragging).
96 | this._marker
97 | .fire('moveend')
98 | .fire('dragend', e);
99 | }
100 | });
101 |
--------------------------------------------------------------------------------
/src/layer/marker/Marker.Popup.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Popup extension to L.Marker, adding popup-related methods.
3 | */
4 |
5 | L.Marker.include({
6 | _getPopupAnchor: function () {
7 | return this.options.icon.options.popupAnchor || [0, 0];
8 | }
9 | });
10 |
--------------------------------------------------------------------------------
/src/layer/vector/Circle.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @class Circle
3 | * @aka L.Circle
4 | * @inherits CircleMarker
5 | *
6 | * A class for drawing circle overlays on a map. Extends `CircleMarker`.
7 | *
8 | * It's an approximation and starts to diverge from a real circle closer to poles (due to projection distortion).
9 | *
10 | * @example
11 | *
12 | * ```js
13 | * L.circle([50.5, 30.5], 200).addTo(map);
14 | * ```
15 | */
16 |
17 | L.Circle = L.CircleMarker.extend({
18 |
19 | initialize: function (latlng, options, legacyOptions) {
20 | if (typeof options === 'number') {
21 | // Backwards compatibility with 0.7.x factory (latlng, radius, options?)
22 | options = L.extend({}, legacyOptions, {radius: options});
23 | }
24 | L.setOptions(this, options);
25 | this._latlng = L.latLng(latlng);
26 |
27 | if (isNaN(this.options.radius)) { throw new Error('Circle radius cannot be NaN'); }
28 |
29 | // @section
30 | // @aka Circle options
31 | // @option radius: Number; Radius of the circle, in meters.
32 | this._mRadius = this.options.radius;
33 | },
34 |
35 | // @method setRadius(radius: Number): this
36 | // Sets the radius of a circle. Units are in meters.
37 | setRadius: function (radius) {
38 | this._mRadius = radius;
39 | return this.redraw();
40 | },
41 |
42 | // @method getRadius(): Number
43 | // Returns the current radius of a circle. Units are in meters.
44 | getRadius: function () {
45 | return this._mRadius;
46 | },
47 |
48 | // @method getBounds(): LatLngBounds
49 | // Returns the `LatLngBounds` of the path.
50 | getBounds: function () {
51 | var half = [this._radius, this._radiusY || this._radius];
52 |
53 | return new L.LatLngBounds(
54 | this._map.layerPointToLatLng(this._point.subtract(half)),
55 | this._map.layerPointToLatLng(this._point.add(half)));
56 | },
57 |
58 | setStyle: L.Path.prototype.setStyle,
59 |
60 | _project: function () {
61 |
62 | var lng = this._latlng.lng,
63 | lat = this._latlng.lat,
64 | map = this._map,
65 | crs = map.options.crs;
66 |
67 | if (crs.distance === L.CRS.Earth.distance) {
68 | var d = Math.PI / 180,
69 | latR = (this._mRadius / L.CRS.Earth.R) / d,
70 | top = map.project([lat + latR, lng]),
71 | bottom = map.project([lat - latR, lng]),
72 | p = top.add(bottom).divideBy(2),
73 | lat2 = map.unproject(p).lat,
74 | lngR = Math.acos((Math.cos(latR * d) - Math.sin(lat * d) * Math.sin(lat2 * d)) /
75 | (Math.cos(lat * d) * Math.cos(lat2 * d))) / d;
76 |
77 | if (isNaN(lngR) || lngR === 0) {
78 | lngR = latR / Math.cos(Math.PI / 180 * lat); // Fallback for edge case, #2425
79 | }
80 |
81 | this._point = p.subtract(map.getPixelOrigin());
82 | this._radius = isNaN(lngR) ? 0 : Math.max(Math.round(p.x - map.project([lat2, lng - lngR]).x), 1);
83 | this._radiusY = Math.max(Math.round(p.y - top.y), 1);
84 |
85 | } else {
86 | var latlng2 = crs.unproject(crs.project(this._latlng).subtract([this._mRadius, 0]));
87 |
88 | this._point = map.latLngToLayerPoint(this._latlng);
89 | this._radius = this._point.x - map.latLngToLayerPoint(latlng2).x;
90 | }
91 |
92 | this._updateBounds();
93 | }
94 | });
95 |
96 | // @factory L.circle(latlng: LatLng, options?: Circle options)
97 | // Instantiates a circle object given a geographical point, and an options object
98 | // which contains the circle radius.
99 | // @alternative
100 | // @factory L.circle(latlng: LatLng, radius: Number, options?: Circle options)
101 | // Obsolete way of instantiating a circle, for compatibility with 0.7.x code.
102 | // Do not use in new applications or plugins.
103 | L.circle = function (latlng, options, legacyOptions) {
104 | return new L.Circle(latlng, options, legacyOptions);
105 | };
106 |
--------------------------------------------------------------------------------
/src/layer/vector/CircleMarker.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @class CircleMarker
3 | * @aka L.CircleMarker
4 | * @inherits Path
5 | *
6 | * A circle of a fixed size with radius specified in pixels. Extends `Path`.
7 | */
8 |
9 | L.CircleMarker = L.Path.extend({
10 |
11 | // @section
12 | // @aka CircleMarker options
13 | options: {
14 | fill: true,
15 |
16 | // @option radius: Number = 10
17 | // Radius of the circle marker, in pixels
18 | radius: 10
19 | },
20 |
21 | initialize: function (latlng, options) {
22 | L.setOptions(this, options);
23 | this._latlng = L.latLng(latlng);
24 | this._radius = this.options.radius;
25 | },
26 |
27 | // @method setLatLng(latLng: LatLng): this
28 | // Sets the position of a circle marker to a new location.
29 | setLatLng: function (latlng) {
30 | this._latlng = L.latLng(latlng);
31 | this.redraw();
32 | return this.fire('move', {latlng: this._latlng});
33 | },
34 |
35 | // @method getLatLng(): LatLng
36 | // Returns the current geographical position of the circle marker
37 | getLatLng: function () {
38 | return this._latlng;
39 | },
40 |
41 | // @method setRadius(radius: Number): this
42 | // Sets the radius of a circle marker. Units are in pixels.
43 | setRadius: function (radius) {
44 | this.options.radius = this._radius = radius;
45 | return this.redraw();
46 | },
47 |
48 | // @method getRadius(): Number
49 | // Returns the current radius of the circle
50 | getRadius: function () {
51 | return this._radius;
52 | },
53 |
54 | setStyle : function (options) {
55 | var radius = options && options.radius || this._radius;
56 | L.Path.prototype.setStyle.call(this, options);
57 | this.setRadius(radius);
58 | return this;
59 | },
60 |
61 | _project: function () {
62 | this._point = this._map.latLngToLayerPoint(this._latlng);
63 | this._updateBounds();
64 | },
65 |
66 | _updateBounds: function () {
67 | var r = this._radius,
68 | r2 = this._radiusY || r,
69 | w = this._clickTolerance(),
70 | p = [r + w, r2 + w];
71 | this._pxBounds = new L.Bounds(this._point.subtract(p), this._point.add(p));
72 | },
73 |
74 | _update: function () {
75 | if (this._map) {
76 | this._updatePath();
77 | }
78 | },
79 |
80 | _updatePath: function () {
81 | this._renderer._updateCircle(this);
82 | },
83 |
84 | _empty: function () {
85 | return this._radius && !this._renderer._bounds.intersects(this._pxBounds);
86 | }
87 | });
88 |
89 |
90 | // @factory L.circleMarker(latlng: LatLng, options?: CircleMarker options)
91 | // Instantiates a circle marker object given a geographical point, and an optional options object.
92 | L.circleMarker = function (latlng, options) {
93 | return new L.CircleMarker(latlng, options);
94 | };
95 |
--------------------------------------------------------------------------------
/src/layer/vector/Rectangle.js:
--------------------------------------------------------------------------------
1 | /*
2 | * L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds object.
3 | */
4 |
5 | /*
6 | * @class Rectangle
7 | * @aka L.Retangle
8 | * @inherits Polygon
9 | *
10 | * A class for drawing rectangle overlays on a map. Extends `Polygon`.
11 | *
12 | * @example
13 | *
14 | * ```js
15 | * // define rectangle geographical bounds
16 | * var bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]];
17 | *
18 | * // create an orange rectangle
19 | * L.rectangle(bounds, {color: "#ff7800", weight: 1}).addTo(map);
20 | *
21 | * // zoom the map to the rectangle bounds
22 | * map.fitBounds(bounds);
23 | * ```
24 | *
25 | */
26 |
27 |
28 | L.Rectangle = L.Polygon.extend({
29 | initialize: function (latLngBounds, options) {
30 | L.Polygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options);
31 | },
32 |
33 | // @method setBounds(latLngBounds: LatLngBounds): this
34 | // Redraws the rectangle with the passed bounds.
35 | setBounds: function (latLngBounds) {
36 | return this.setLatLngs(this._boundsToLatLngs(latLngBounds));
37 | },
38 |
39 | _boundsToLatLngs: function (latLngBounds) {
40 | latLngBounds = L.latLngBounds(latLngBounds);
41 | return [
42 | latLngBounds.getSouthWest(),
43 | latLngBounds.getNorthWest(),
44 | latLngBounds.getNorthEast(),
45 | latLngBounds.getSouthEast()
46 | ];
47 | }
48 | });
49 |
50 |
51 | // @factory L.rectangle(latLngBounds: LatLngBounds, options?: Polyline options)
52 | L.rectangle = function (latLngBounds, options) {
53 | return new L.Rectangle(latLngBounds, options);
54 | };
55 |
--------------------------------------------------------------------------------
/src/map/anim/Map.FlyTo.js:
--------------------------------------------------------------------------------
1 | // @namespace Map
2 | // @section Methods for modifying map state
3 | L.Map.include({
4 |
5 | // @method flyTo(latlng: LatLng, zoom?: Number, options?: Zoom/Pan options): this
6 | // Sets the view of the map (geographical center and zoom) performing a smooth
7 | // pan-zoom animation.
8 | flyTo: function (targetCenter, targetZoom, options) {
9 |
10 | options = options || {};
11 | if (options.animate === false || !L.Browser.any3d) {
12 | return this.setView(targetCenter, targetZoom, options);
13 | }
14 |
15 | this._stop();
16 |
17 | var from = this.project(this.getCenter()),
18 | to = this.project(targetCenter),
19 | size = this.getSize(),
20 | startZoom = this._zoom;
21 |
22 | targetCenter = L.latLng(targetCenter);
23 | targetZoom = targetZoom === undefined ? startZoom : targetZoom;
24 |
25 | var w0 = Math.max(size.x, size.y),
26 | w1 = w0 * this.getZoomScale(startZoom, targetZoom),
27 | u1 = (to.distanceTo(from)) || 1,
28 | rho = 1.42,
29 | rho2 = rho * rho;
30 |
31 | function r(i) {
32 | var s1 = i ? -1 : 1,
33 | s2 = i ? w1 : w0,
34 | t1 = w1 * w1 - w0 * w0 + s1 * rho2 * rho2 * u1 * u1,
35 | b1 = 2 * s2 * rho2 * u1,
36 | b = t1 / b1,
37 | sq = Math.sqrt(b * b + 1) - b;
38 |
39 | // workaround for floating point precision bug when sq = 0, log = -Infinite,
40 | // thus triggering an infinite loop in flyTo
41 | var log = sq < 0.000000001 ? -18 : Math.log(sq);
42 |
43 | return log;
44 | }
45 |
46 | function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }
47 | function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }
48 | function tanh(n) { return sinh(n) / cosh(n); }
49 |
50 | var r0 = r(0);
51 |
52 | function w(s) { return w0 * (cosh(r0) / cosh(r0 + rho * s)); }
53 | function u(s) { return w0 * (cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2; }
54 |
55 | function easeOut(t) { return 1 - Math.pow(1 - t, 1.5); }
56 |
57 | var start = Date.now(),
58 | S = (r(1) - r0) / rho,
59 | duration = options.duration ? 1000 * options.duration : 1000 * S * 0.8;
60 |
61 | function frame() {
62 | var t = (Date.now() - start) / duration,
63 | s = easeOut(t) * S;
64 |
65 | if (t <= 1) {
66 | this._flyToFrame = L.Util.requestAnimFrame(frame, this);
67 |
68 | this._move(
69 | this.unproject(from.add(to.subtract(from).multiplyBy(u(s) / u1)), startZoom),
70 | this.getScaleZoom(w0 / w(s), startZoom),
71 | {flyTo: true});
72 |
73 | } else {
74 | this
75 | ._move(targetCenter, targetZoom)
76 | ._moveEnd(true);
77 | }
78 | }
79 |
80 | this._moveStart(true);
81 |
82 | frame.call(this);
83 | return this;
84 | },
85 |
86 | // @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this
87 | // Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto),
88 | // but takes a bounds parameter like [`fitBounds`](#map-fitbounds).
89 | flyToBounds: function (bounds, options) {
90 | var target = this._getBoundsCenterZoom(bounds, options);
91 | return this.flyTo(target.center, target.zoom, options);
92 | }
93 | });
94 |
--------------------------------------------------------------------------------
/src/map/anim/Map.PanAnimation.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Extends L.Map to handle panning animations.
3 | */
4 |
5 | L.Map.include({
6 |
7 | setView: function (center, zoom, options) {
8 |
9 | zoom = zoom === undefined ? this._zoom : this._limitZoom(zoom);
10 | center = this._limitCenter(L.latLng(center), zoom, this.options.maxBounds);
11 | options = options || {};
12 |
13 | this._stop();
14 |
15 | if (this._loaded && !options.reset && options !== true) {
16 |
17 | if (options.animate !== undefined) {
18 | options.zoom = L.extend({animate: options.animate}, options.zoom);
19 | options.pan = L.extend({animate: options.animate, duration: options.duration}, options.pan);
20 | }
21 |
22 | // try animating pan or zoom
23 | var moved = (this._zoom !== zoom) ?
24 | this._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom, options.zoom) :
25 | this._tryAnimatedPan(center, options.pan);
26 |
27 | if (moved) {
28 | // prevent resize handler call, the view will refresh after animation anyway
29 | clearTimeout(this._sizeTimer);
30 | return this;
31 | }
32 | }
33 |
34 | // animation didn't start, just reset the map view
35 | this._resetView(center, zoom);
36 |
37 | return this;
38 | },
39 |
40 | panBy: function (offset, options) {
41 | offset = L.point(offset).round();
42 | options = options || {};
43 |
44 | if (!offset.x && !offset.y) {
45 | return this.fire('moveend');
46 | }
47 | // If we pan too far, Chrome gets issues with tiles
48 | // and makes them disappear or appear in the wrong place (slightly offset) #2602
49 | if (options.animate !== true && !this.getSize().contains(offset)) {
50 | this._resetView(this.unproject(this.project(this.getCenter()).add(offset)), this.getZoom());
51 | return this;
52 | }
53 |
54 | if (!this._panAnim) {
55 | this._panAnim = new L.PosAnimation();
56 |
57 | this._panAnim.on({
58 | 'step': this._onPanTransitionStep,
59 | 'end': this._onPanTransitionEnd
60 | }, this);
61 | }
62 |
63 | // don't fire movestart if animating inertia
64 | if (!options.noMoveStart) {
65 | this.fire('movestart');
66 | }
67 |
68 | // animate pan unless animate: false specified
69 | if (options.animate !== false) {
70 | L.DomUtil.addClass(this._mapPane, 'leaflet-pan-anim');
71 |
72 | var newPos = this._getMapPanePos().subtract(offset).round();
73 | this._panAnim.run(this._mapPane, newPos, options.duration || 0.25, options.easeLinearity);
74 | } else {
75 | this._rawPanBy(offset);
76 | this.fire('move').fire('moveend');
77 | }
78 |
79 | return this;
80 | },
81 |
82 | _onPanTransitionStep: function () {
83 | this.fire('move');
84 | },
85 |
86 | _onPanTransitionEnd: function () {
87 | L.DomUtil.removeClass(this._mapPane, 'leaflet-pan-anim');
88 | this.fire('moveend');
89 | },
90 |
91 | _tryAnimatedPan: function (center, options) {
92 | // difference between the new and current centers in pixels
93 | var offset = this._getCenterOffset(center)._floor();
94 |
95 | // don't animate too far unless animate: true specified in options
96 | if ((options && options.animate) !== true && !this.getSize().contains(offset)) { return false; }
97 |
98 | this.panBy(offset, options);
99 |
100 | return true;
101 | }
102 | });
103 |
--------------------------------------------------------------------------------
/src/map/ext/Map.Geolocation.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Provides L.Map with convenient shortcuts for using browser geolocation features.
3 | */
4 |
5 | // @namespace Map
6 |
7 | L.Map.include({
8 | // @section Geolocation methods
9 | _defaultLocateOptions: {
10 | timeout: 10000,
11 | watch: false
12 | // setView: false
13 | // maxZoom:
14 | // maximumAge: 0
15 | // enableHighAccuracy: false
16 | },
17 |
18 | // @method locate(options?: Locate options): this
19 | // Tries to locate the user using the Geolocation API, firing a `locationfound`
20 | // event with location data on success or a `locationerror` event on failure,
21 | // and optionally sets the map view to the user's location with respect to
22 | // detection accuracy (or to the world view if geolocation failed).
23 | // See `Locate options` for more details.
24 | locate: function (options) {
25 |
26 | options = this._locateOptions = L.extend({}, this._defaultLocateOptions, options);
27 |
28 | if (!('geolocation' in navigator)) {
29 | this._handleGeolocationError({
30 | code: 0,
31 | message: 'Geolocation not supported.'
32 | });
33 | return this;
34 | }
35 |
36 | var onResponse = L.bind(this._handleGeolocationResponse, this),
37 | onError = L.bind(this._handleGeolocationError, this);
38 |
39 | if (options.watch) {
40 | this._locationWatchId =
41 | navigator.geolocation.watchPosition(onResponse, onError, options);
42 | } else {
43 | navigator.geolocation.getCurrentPosition(onResponse, onError, options);
44 | }
45 | return this;
46 | },
47 |
48 | // @method stopLocate(): this
49 | // Stops watching location previously initiated by `map.locate({watch: true})`
50 | // and aborts resetting the map view if map.locate was called with
51 | // `{setView: true}`.
52 | stopLocate: function () {
53 | if (navigator.geolocation && navigator.geolocation.clearWatch) {
54 | navigator.geolocation.clearWatch(this._locationWatchId);
55 | }
56 | if (this._locateOptions) {
57 | this._locateOptions.setView = false;
58 | }
59 | return this;
60 | },
61 |
62 | _handleGeolocationError: function (error) {
63 | var c = error.code,
64 | message = error.message ||
65 | (c === 1 ? 'permission denied' :
66 | (c === 2 ? 'position unavailable' : 'timeout'));
67 |
68 | if (this._locateOptions.setView && !this._loaded) {
69 | this.fitWorld();
70 | }
71 |
72 | // @section Location events
73 | // @event locationerror: ErrorEvent
74 | // Fired when geolocation (using the [`locate`](#map-locate) method) failed.
75 | this.fire('locationerror', {
76 | code: c,
77 | message: 'Geolocation error: ' + message + '.'
78 | });
79 | },
80 |
81 | _handleGeolocationResponse: function (pos) {
82 | var lat = pos.coords.latitude,
83 | lng = pos.coords.longitude,
84 | latlng = new L.LatLng(lat, lng),
85 | bounds = latlng.toBounds(pos.coords.accuracy),
86 | options = this._locateOptions;
87 |
88 | if (options.setView) {
89 | var zoom = this.getBoundsZoom(bounds);
90 | this.setView(latlng, options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom);
91 | }
92 |
93 | var data = {
94 | latlng: latlng,
95 | bounds: bounds,
96 | timestamp: pos.timestamp
97 | };
98 |
99 | for (var i in pos.coords) {
100 | if (typeof pos.coords[i] === 'number') {
101 | data[i] = pos.coords[i];
102 | }
103 | }
104 |
105 | // @event locationfound: LocationEvent
106 | // Fired when geolocation (using the [`locate`](#map-locate) method)
107 | // went successfully.
108 | this.fire('locationfound', data);
109 | }
110 | });
111 |
--------------------------------------------------------------------------------
/src/map/handler/Map.BoxZoom.js:
--------------------------------------------------------------------------------
1 | /*
2 | * L.Handler.BoxZoom is used to add shift-drag zoom interaction to the map
3 | * (zoom to a selected bounding box), enabled by default.
4 | */
5 |
6 | // @namespace Map
7 | // @section Interaction Options
8 | L.Map.mergeOptions({
9 | // @option boxZoom: Boolean = true
10 | // Whether the map can be zoomed to a rectangular area specified by
11 | // dragging the mouse while pressing the shift key.
12 | boxZoom: true
13 | });
14 |
15 | L.Map.BoxZoom = L.Handler.extend({
16 | initialize: function (map) {
17 | this._map = map;
18 | this._container = map._container;
19 | this._pane = map._panes.overlayPane;
20 | },
21 |
22 | addHooks: function () {
23 | L.DomEvent.on(this._container, 'mousedown', this._onMouseDown, this);
24 | },
25 |
26 | removeHooks: function () {
27 | L.DomEvent.off(this._container, 'mousedown', this._onMouseDown, this);
28 | },
29 |
30 | moved: function () {
31 | return this._moved;
32 | },
33 |
34 | _resetState: function () {
35 | this._moved = false;
36 | },
37 |
38 | _onMouseDown: function (e) {
39 | if (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; }
40 |
41 | this._resetState();
42 |
43 | L.DomUtil.disableTextSelection();
44 | L.DomUtil.disableImageDrag();
45 |
46 | this._startPoint = this._map.mouseEventToContainerPoint(e);
47 |
48 | L.DomEvent.on(document, {
49 | contextmenu: L.DomEvent.stop,
50 | mousemove: this._onMouseMove,
51 | mouseup: this._onMouseUp,
52 | keydown: this._onKeyDown
53 | }, this);
54 | },
55 |
56 | _onMouseMove: function (e) {
57 | if (!this._moved) {
58 | this._moved = true;
59 |
60 | this._box = L.DomUtil.create('div', 'leaflet-zoom-box', this._container);
61 | L.DomUtil.addClass(this._container, 'leaflet-crosshair');
62 |
63 | this._map.fire('boxzoomstart');
64 | }
65 |
66 | this._point = this._map.mouseEventToContainerPoint(e);
67 |
68 | var bounds = new L.Bounds(this._point, this._startPoint),
69 | size = bounds.getSize();
70 |
71 | L.DomUtil.setPosition(this._box, bounds.min);
72 |
73 | this._box.style.width = size.x + 'px';
74 | this._box.style.height = size.y + 'px';
75 | },
76 |
77 | _finish: function () {
78 | if (this._moved) {
79 | L.DomUtil.remove(this._box);
80 | L.DomUtil.removeClass(this._container, 'leaflet-crosshair');
81 | }
82 |
83 | L.DomUtil.enableTextSelection();
84 | L.DomUtil.enableImageDrag();
85 |
86 | L.DomEvent.off(document, {
87 | contextmenu: L.DomEvent.stop,
88 | mousemove: this._onMouseMove,
89 | mouseup: this._onMouseUp,
90 | keydown: this._onKeyDown
91 | }, this);
92 | },
93 |
94 | _onMouseUp: function (e) {
95 | if ((e.which !== 1) && (e.button !== 1)) { return; }
96 |
97 | this._finish();
98 |
99 | if (!this._moved) { return; }
100 | // Postpone to next JS tick so internal click event handling
101 | // still see it as "moved".
102 | setTimeout(L.bind(this._resetState, this), 0);
103 |
104 | var bounds = new L.LatLngBounds(
105 | this._map.containerPointToLatLng(this._startPoint),
106 | this._map.containerPointToLatLng(this._point));
107 |
108 | this._map
109 | .fitBounds(bounds)
110 | .fire('boxzoomend', {boxZoomBounds: bounds});
111 | },
112 |
113 | _onKeyDown: function (e) {
114 | if (e.keyCode === 27) {
115 | this._finish();
116 | }
117 | }
118 | });
119 |
120 | // @section Handlers
121 | // @property boxZoom: Handler
122 | // Box (shift-drag with mouse) zoom handler.
123 | L.Map.addInitHook('addHandler', 'boxZoom', L.Map.BoxZoom);
124 |
--------------------------------------------------------------------------------
/src/map/handler/Map.DoubleClickZoom.js:
--------------------------------------------------------------------------------
1 | /*
2 | * L.Handler.DoubleClickZoom is used to handle double-click zoom on the map, enabled by default.
3 | */
4 |
5 | // @namespace Map
6 | // @section Interaction Options
7 |
8 | L.Map.mergeOptions({
9 | // @option doubleClickZoom: Boolean|String = true
10 | // Whether the map can be zoomed in by double clicking on it and
11 | // zoomed out by double clicking while holding shift. If passed
12 | // `'center'`, double-click zoom will zoom to the center of the
13 | // view regardless of where the mouse was.
14 | doubleClickZoom: true
15 | });
16 |
17 | L.Map.DoubleClickZoom = L.Handler.extend({
18 | addHooks: function () {
19 | this._map.on('dblclick', this._onDoubleClick, this);
20 | },
21 |
22 | removeHooks: function () {
23 | this._map.off('dblclick', this._onDoubleClick, this);
24 | },
25 |
26 | _onDoubleClick: function (e) {
27 | var map = this._map,
28 | oldZoom = map.getZoom(),
29 | delta = map.options.zoomDelta,
30 | zoom = e.originalEvent.shiftKey ? oldZoom - delta : oldZoom + delta;
31 |
32 | if (map.options.doubleClickZoom === 'center') {
33 | map.setZoom(zoom);
34 | } else {
35 | map.setZoomAround(e.containerPoint, zoom);
36 | }
37 | }
38 | });
39 |
40 | // @section Handlers
41 | //
42 | // Map properties include interaction handlers that allow you to control
43 | // interaction behavior in runtime, enabling or disabling certain features such
44 | // as dragging or touch zoom (see `Handler` methods). For example:
45 | //
46 | // ```js
47 | // map.doubleClickZoom.disable();
48 | // ```
49 | //
50 | // @property doubleClickZoom: Handler
51 | // Double click zoom handler.
52 | L.Map.addInitHook('addHandler', 'doubleClickZoom', L.Map.DoubleClickZoom);
53 |
--------------------------------------------------------------------------------
/src/map/handler/Map.ScrollWheelZoom.js:
--------------------------------------------------------------------------------
1 | /*
2 | * L.Handler.ScrollWheelZoom is used by L.Map to enable mouse scroll wheel zoom on the map.
3 | */
4 |
5 | // @namespace Map
6 | // @section Interaction Options
7 | L.Map.mergeOptions({
8 | // @section Mousewheel options
9 | // @option scrollWheelZoom: Boolean|String = true
10 | // Whether the map can be zoomed by using the mouse wheel. If passed `'center'`,
11 | // it will zoom to the center of the view regardless of where the mouse was.
12 | scrollWheelZoom: true,
13 |
14 | // @option wheelDebounceTime: Number = 40
15 | // Limits the rate at which a wheel can fire (in milliseconds). By default
16 | // user can't zoom via wheel more often than once per 40 ms.
17 | wheelDebounceTime: 40,
18 |
19 | // @option wheelPxPerZoomLevel: Number = 50
20 | // How many scroll pixels (as reported by [L.DomEvent.getWheelDelta](#domevent-getwheeldelta))
21 | // mean a change of one full zoom level. Smaller values will make wheel-zooming
22 | // faster (and vice versa).
23 | wheelPxPerZoomLevel: 50
24 | });
25 |
26 | L.Map.ScrollWheelZoom = L.Handler.extend({
27 | addHooks: function () {
28 | L.DomEvent.on(this._map._container, 'mousewheel', this._onWheelScroll, this);
29 |
30 | this._delta = 0;
31 | },
32 |
33 | removeHooks: function () {
34 | L.DomEvent.off(this._map._container, 'mousewheel', this._onWheelScroll, this);
35 | },
36 |
37 | _onWheelScroll: function (e) {
38 | var delta = L.DomEvent.getWheelDelta(e);
39 |
40 | var debounce = this._map.options.wheelDebounceTime;
41 |
42 | this._delta += delta;
43 | this._lastMousePos = this._map.mouseEventToContainerPoint(e);
44 |
45 | if (!this._startTime) {
46 | this._startTime = +new Date();
47 | }
48 |
49 | var left = Math.max(debounce - (+new Date() - this._startTime), 0);
50 |
51 | clearTimeout(this._timer);
52 | this._timer = setTimeout(L.bind(this._performZoom, this), left);
53 |
54 | L.DomEvent.stop(e);
55 | },
56 |
57 | _performZoom: function () {
58 | var map = this._map,
59 | zoom = map.getZoom(),
60 | snap = this._map.options.zoomSnap || 0;
61 |
62 | map._stop(); // stop panning and fly animations if any
63 |
64 | // map the delta with a sigmoid function to -4..4 range leaning on -1..1
65 | var d2 = this._delta / (this._map.options.wheelPxPerZoomLevel * 4),
66 | d3 = 4 * Math.log(2 / (1 + Math.exp(-Math.abs(d2)))) / Math.LN2,
67 | d4 = snap ? Math.ceil(d3 / snap) * snap : d3,
68 | delta = map._limitZoom(zoom + (this._delta > 0 ? d4 : -d4)) - zoom;
69 |
70 | this._delta = 0;
71 | this._startTime = null;
72 |
73 | if (!delta) { return; }
74 |
75 | if (map.options.scrollWheelZoom === 'center') {
76 | map.setZoom(zoom + delta);
77 | } else {
78 | map.setZoomAround(this._lastMousePos, zoom + delta);
79 | }
80 | }
81 | });
82 |
83 | // @section Handlers
84 | // @property scrollWheelZoom: Handler
85 | // Scroll wheel zoom handler.
86 | L.Map.addInitHook('addHandler', 'scrollWheelZoom', L.Map.ScrollWheelZoom);
87 |
--------------------------------------------------------------------------------