Merge branch 'master' into gh-pages-master
This commit is contained in:
commit
8e4ed9b819
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
node_modules
|
96
CHANGELOG.md
96
CHANGELOG.md
@ -5,19 +5,104 @@ Leaflet Changelog
|
||||
|
||||
## 0.4 (master)
|
||||
|
||||
An in-progress version being developed on the master branch.
|
||||
|
||||
### Notable new features
|
||||
|
||||
* Added configurable **panning inertia** - after a quick pan, the map slows down in the same direction.
|
||||
* Added **polyline and polygon editing**. [#174](https://github.com/CloudMade/Leaflet/issues/174)
|
||||
* Added an unobtrusive **scale control**.
|
||||
* Added `DivIcon` class that easily allows you to create lightweight div-based markers.
|
||||
* Added `Rectangle` vector layer (by [@JasonSanford](https://github.com/JasonSanford)). [#504](https://github.com/CloudMade/Leaflet/pull/504)
|
||||
|
||||
### Improvements
|
||||
|
||||
* Added `setPosition` and `getPosition` to all controls, as well as ability to pass certain position as an option when creating a control.
|
||||
#### Usability improvements
|
||||
|
||||
* Added smooth **zoom animation of markers, vector layers and popups** (by [@danzel](https://github.com/danzel)). [#740](https://github.com/CloudMade/Leaflet/pull/740)
|
||||
* Improved zooming so that you don't get a blank map when you zoom in or out twice quickly (by [@danzel](https://github.com/danzel)). [#7](https://github.com/CloudMade/Leaflet/issues/7) [#729](https://github.com/CloudMade/Leaflet/pull/729)
|
||||
* Drag-panning now works even when there are markers in the starting point (helps on maps with lots of markers). [#506](https://github.com/CloudMade/Leaflet/issues/506)
|
||||
* Improved panning performance even more (there are no wasted frames now).
|
||||
* Replaced box-shadow with border on controls for mobile devices to improve performance.
|
||||
* Slightly improved default popup styling.
|
||||
* Added `TileLayer` `detectRetina` option (`false` by default) that makes tiles show in a higher resolution on iOS retina displays (by [Mithgol](https://github.com/Mithgol)). [#586](https://github.com/CloudMade/Leaflet/pull/586)
|
||||
|
||||
#### Breaking API changes
|
||||
|
||||
* Converted `Icon` properties (like `iconUrl`) to options, changed constructor signature to `Icon(options)`.
|
||||
* Moved default marker icon options to `L.Icon.Default` class (which extends from `L.Icon`).
|
||||
* Improved `TileLayer` constructor to interpolate URL template values from options (removed third `urlParams` argument).
|
||||
* Replaced ugly control position constants (e.g. L.Control.Position.TOP_LEFT) with light strings ('topleft', 'bottomright', etc.)
|
||||
* Removed `Map` `locateAndSetView` method (use `locate` with `setView: true` option)
|
||||
* Changed popup `minWidth` and `maxWidth` options to be applied to content element, not the whole popup.
|
||||
* Moved `prefix` argument to `options` in `Control.Attribution` constructor.
|
||||
* Renamed `L.VERSION` to `L.version`.
|
||||
|
||||
#### Other API improvements
|
||||
|
||||
* Added `Icon` `className` option to assign a custom class to an icon.
|
||||
* Added `Icon` `shadowOffset` option to set the position of shadow relative to the icon.
|
||||
* Made all `Icon` options except `iconUrl` optional (if not specified, they'll be chosen automatically or implemented using CSS). Anchor is centered by default (if size is specified), and otherwise can be set through CSS using negative margins.
|
||||
* Moved all default marker icon options from `L.Icon` to `L.Icon.Default`.
|
||||
* Added `originalEvent` property to `MouseEvent` (by [@k4](https://github.com/k4)). [#521](https://github.com/CloudMade/Leaflet/pull/521)
|
||||
* Added `Circle` `getBounds` method. [#440](https://github.com/CloudMade/Leaflet/issues/440)
|
||||
* Added `Circle` `getLatLng` and `getRadius` methods (by [Guiswa](https://github.com/Guiswa)). [#655](https://github.com/CloudMade/Leaflet/pull/655)
|
||||
* Added `Map` `getContainer` method (by [Guiswa](https://github.com/Guiswa)). [#654](https://github.com/CloudMade/Leaflet/pull/654)
|
||||
* Added `Marker` `opacity` option.
|
||||
* Added public `redraw` method to vector layers (useful if you manipulate their `LatLng` points directly).
|
||||
* Added `setPosition` and `getPosition` to all controls, as well as ability to pass certain position as an option when creating a control.
|
||||
* Added `Popup` `maxHeight` option that makes content inside the popup scrolled if it doesn't fit the specified max height.
|
||||
* Made controls implementation easier (now more magic happens under the hood).
|
||||
* Added `Map` `containerPointToLatLng` and `latLngToContainerPoint` methods. [#474](https://github.com/CloudMade/Leaflet/issues/474)
|
||||
* Added `containerPoint` property to `MouseEvent`. [#413](https://github.com/CloudMade/Leaflet/issues/413)
|
||||
* Added `LatLngBounds` `pad` method that returns bounds extended by a percentage (by [@jacobtoye](https://github.com/jacobtoye)). [#492](https://github.com/CloudMade/Leaflet/pull/492)
|
||||
* Added `contextmenu` event to vector layers (by [@ErrorProne](https://github.com/ErrorProne)). [#500](https://github.com/CloudMade/Leaflet/pull/500)
|
||||
* Added chaining to `DomEvent` methods.
|
||||
* Added `Map` `addHandler` method.
|
||||
* Moved dragging cursor styles from JS code to CSS.
|
||||
* Improved `Marker` `openPopup` not to raise an error if it doesn't have a popup. [#507](https://github.com/CloudMade/Leaflet/issues/507)
|
||||
* Added `geometry` property to `GeoJSON` `featureparse` event (by [@twinbit](https://github.com/twinbit)). [#716](https://github.com/CloudMade/Leaflet/pull/716)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* Fixed a bug where `TileLayer.WMS` wouldn't take `insertAtTheBottom` option into account (by [@bmcbride](https://github.com/bmcbride)). [#478](https://github.com/CloudMade/Leaflet/pull/478)
|
||||
#### General bugfixes
|
||||
|
||||
## 0.3.2 RC
|
||||
* Fixed a bug where the map was zooming incorrectly inside a `position: fixed` container (by [chx007](https://github.com/chx007)). [#602](https://github.com/CloudMade/Leaflet/pull/602)
|
||||
* Fixed a bug where scaled tiles weren't cleared up after zoom in some cases (by [cfis](https://github.com/cfis)) [#683](https://github.com/CloudMade/Leaflet/pull/683)
|
||||
|
||||
#### API bugfixes
|
||||
|
||||
* Fixed a regression where removeLayer would not remove corresponding attribution. [#488](https://github.com/CloudMade/Leaflet/issues/488)
|
||||
* Fixed a bug where popup close button wouldn't work on manually added popups. [#423](https://github.com/CloudMade/Leaflet/issues/423)
|
||||
* Fixed a bug where `TileLayer.WMS` wouldn't take `insertAtTheBottom` option into account (by [@bmcbride](https://github.com/bmcbride)). [#478](https://github.com/CloudMade/Leaflet/pull/478)
|
||||
* Fixed a bug where marker click event would stop working if you dragged it and then disabled dragging. [#434](https://github.com/CloudMade/Leaflet/issues/434)
|
||||
* Fixed a bug where `TileLayer` `setOpacity` wouldn't work when setting it back to 1.
|
||||
* Fixed a bug where vector layer `setStyle({stroke: false})` wouldn't remove stroke and the same for fill. [#441](https://github.com/CloudMade/Leaflet/issues/441)
|
||||
* Fixed a bug where `Marker` `bindPopup` method wouldn't take `offset` option into account.
|
||||
* Fixed a bug where `TileLayer` `load` event wasn't fired if some tile didn't load (by [cfis](https://github.com/cfis)) [#682](https://github.com/CloudMade/Leaflet/pull/682)
|
||||
* Fixed error when removing `GeoJSON` layer. [#685](https://github.com/CloudMade/Leaflet/issues/685)
|
||||
* Fixed error when calling `GeoJSON` `clearLayer` (by [runderwood](https://github.com/runderwood)). [#617](https://github.com/CloudMade/Leaflet/pull/617)
|
||||
* Fixed a bug where polygons/polylines sometimes throwed an error when making them editable manually (by [cfis](https://github.com/cfis)). [#669](https://github.com/CloudMade/Leaflet/pull/669)
|
||||
* Fixed a bug where `Control` `setPosition` wasn't always working correctly (by [ericmmartinez](https://github.com/ericmmartinez)). [#657](https://github.com/CloudMade/Leaflet/pull/657)
|
||||
* Fixed a bug with `Util.bind` sometimes losing arguments (by [johtso](https://github.com/johtso)). [#588](https://github.com/CloudMade/Leaflet/pull/588)
|
||||
|
||||
#### Browser bugfixes
|
||||
|
||||
* Fixed inability to use scrolled content inside popup due to mouse wheel propagation.
|
||||
* Fixed a bug that caused jumping/stuttering of panning animation in some cases.
|
||||
* Fixed a bug where popup size was calculated incorrectly in IE.
|
||||
* Fixed a bug where cursor would flicker when dragging a marker.
|
||||
* Fixed a bug where clickable paths on IE9 didn't have a hand cursor (by [naehrstoff](https://github.com/naehrstoff)). [#671](https://github.com/CloudMade/Leaflet/pull/671)
|
||||
* Fixed a bug in IE with disappearing icons when changing opacity (by [tagliala](https://github.com/tagliala) and [DamonOehlman](https://github.com/DamonOehlman)). [#667](https://github.com/CloudMade/Leaflet/pull/667) [#600](https://github.com/CloudMade/Leaflet/pull/600)
|
||||
* Fixed a bug where `Control.Layers` didn't work on IE7. [#652](https://github.com/CloudMade/Leaflet/issues/652)
|
||||
* Fixed a bug that caused popups to be empty in IE when passing a DOM node as the content (by [@nrenner](https://github.com/nrenner)). [#472](https://github.com/CloudMade/Leaflet/pull/472)
|
||||
|
||||
#### Mobile browser bugfixes
|
||||
|
||||
* Fixed a bug with false map click events on pinch-zoom and zoom/layers controls click. [#485](https://github.com/CloudMade/Leaflet/issues/485)
|
||||
* Fixed a bug where touching the map with two or more fingers simultaneously would raise an error.
|
||||
* Fixed a bug where zoom control wasn't always visible on Android 3. [#335](https://github.com/CloudMade/Leaflet/issues/335)
|
||||
* Fixed a bug where opening the layers control would propagate a click to the map (by [jacobtoye](https://github.com/jacobtoye)). [#638](https://github.com/CloudMade/Leaflet/pull/638)
|
||||
|
||||
## 0.3.1 (February 14, 2012)
|
||||
|
||||
@ -60,6 +145,7 @@ Leaflet Changelog
|
||||
* Added `Polyline` `closestLayerPoint` method that's can be useful for interaction features (by [@anru](https://github.com/anru)). [#186](https://github.com/CloudMade/Leaflet/pull/186)
|
||||
* Added `setLatLngs` method to `MultiPolyline` and `MultiPolygon` (by [@anru](https://github.com/anru)). [#194](https://github.com/CloudMade/Leaflet/pull/194)
|
||||
* Added `getBounds` method to `Polyline` and `Polygon` (by [@JasonSanford](https://github.com/JasonSanford)). [#253](https://github.com/CloudMade/Leaflet/pull/253)
|
||||
* Added `getBounds` method to `FeatureGroup` (by [@JasonSanford](https://github.com/JasonSanford)). [#557](https://github.com/CloudMade/Leaflet/pull/557)
|
||||
* Added `FeatureGroup` `setStyle` method (also inherited by `MultiPolyline` and `MultiPolygon`). [#353](https://github.com/CloudMade/Leaflet/issues/353)
|
||||
* Added `FeatureGroup` `invoke` method to call a particular method on all layers of the group with the given arguments.
|
||||
* Added `ImageOverlay` `load` event. [#213](https://github.com/CloudMade/Leaflet/issues/213)
|
||||
@ -68,16 +154,20 @@ Leaflet Changelog
|
||||
* Added `LatLng` `distanceTo` method (great circle distance) (by [@mortenbekditlevsen](https://github.com/mortenbekditlevsen)). [#462](https://github.com/CloudMade/Leaflet/pull/462)
|
||||
* Added `LatLngBounds` `toBBoxString` method for convenience (by [@JasonSanford](https://github.com/JasonSanford)). [#263](https://github.com/CloudMade/Leaflet/pull/263)
|
||||
* Added `LatLngBounds` `intersects(otherBounds)` method (thanks to [@pagameba](https://github.com/pagameba)). [#350](https://github.com/CloudMade/Leaflet/pull/350)
|
||||
* Made `LatLngBounds` `extend` method to accept other `LatLngBounds` in addition to `LatLng` (by [@JasonSanford](https://github.com/JasonSanford)). [#553](https://github.com/CloudMade/Leaflet/pull/553)
|
||||
* Added `Bounds` `intersects(otherBounds)` method. [#461](https://github.com/CloudMade/Leaflet/issues/461)
|
||||
* Added `L.Util.template` method for simple string template evaluation.
|
||||
* Added `DomUtil.removeClass` method (by [@anru](https://github.com/anru)).
|
||||
* Added ability to pass empty imageUrl to icons for creating transparent clickable regions (by [@mortenbekditlevsen](https://github.com/mortenbekditlevsen)). [#460](https://github.com/CloudMade/Leaflet/pull/460)
|
||||
* Improved browser-specific code to rely more on feature detection rather than user agent string.
|
||||
* Improved superclass access mechanism to work with inheritance chains of 3 or more classes; now you should use `Klass.superclass` instead of `this.superclass` (by [@anru](https://github.com/anru)). [#179](https://github.com/CloudMade/Leaflet/pull/179)
|
||||
* Added `Map` `boxzoomstart` and `boxzoomend` events (by [zedd45](https://github.com/zedd45)). [#554](https://github.com/CloudMade/Leaflet/pull/554)
|
||||
* Added `Popup` `contentupdate` event (by [mehmeta](https://github.com/mehmeta)). [#548](https://github.com/CloudMade/Leaflet/pull/548)
|
||||
|
||||
#### Breaking API changes
|
||||
|
||||
* `shiftDragZoom` map option/property renamed to `boxZoom`.
|
||||
* Removed `mouseEventToLatLng` method (bringed back in 0.4).
|
||||
|
||||
#### Development workflow improvements
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
var build = require('./build/build.js'),
|
||||
lint = require('./build/hint.js');
|
||||
|
||||
var crlf = '\r\n',
|
||||
COPYRIGHT = '/*' + crlf + ' Copyright (c) 2010-2012, CloudMade, Vladimir Agafonkin' + crlf +
|
||||
' Leaflet is a modern open-source JavaScript library for interactive maps.' + crlf +
|
||||
' http://leaflet.cloudmade.com' + crlf + '*/' + crlf;
|
||||
var COPYRIGHT = '/*\n Copyright (c) 2010-2012, CloudMade, Vladimir Agafonkin\n' +
|
||||
' Leaflet is a modern open-source JavaScript library for interactive maps.\n' +
|
||||
' http://leaflet.cloudmade.com\n*/\n';
|
||||
|
||||
desc('Check Leaflet source for errors with JSHint');
|
||||
task('lint', function () {
|
||||
@ -31,6 +30,7 @@ task('build', ['lint'], function (compsBase32, buildName) {
|
||||
var files = build.getFiles(compsBase32);
|
||||
|
||||
console.log('Concatenating ' + files.length + ' files...');
|
||||
|
||||
var content = build.combineFiles(files);
|
||||
|
||||
var oldSrc = build.load(srcPath),
|
||||
|
10
README.md
10
README.md
@ -1,13 +1,13 @@
|
||||
<img src="http://leaflet.cloudmade.com/docs/images/logo.png" alt="Leaflet" />
|
||||
|
||||
Leaflet is a modern, lightweight BSD-licensed JavaScript library for making tile-based interactive maps for both desktop and mobile web browsers, developed by [CloudMade](http://cloudmade.com) to form the core of its next generation JavaScript API.
|
||||
Leaflet is a modern, lightweight open-source JavaScript library for mobile-friendly interactive maps, developed by [CloudMade](http://cloudmade.com) to form the core of its next generation JavaScript API. Weighting just about 21kb of gzipped JS code, it still has all the [features](http://leaflet.cloudmade.com/features.html) you will ever need for your web mapping needs while providing a fast, smooth, pleasant user experience.
|
||||
|
||||
It is built from the ground up to work efficiently and smoothly on both platforms, utilizing cutting-edge technologies included in HTML5. Its top priorities are usability, performance and small size, [A-grade](http://developer.yahoo.com/yui/articles/gbs/) browser support, flexibility and easy to use API. The OOP-based code of the library is designed to be modular, extensible and very easy to understand.
|
||||
It is built from the ground up to work efficiently and smoothly on both desktop and mobile platforms like iOS and Android, utilizing cutting-edge technologies included in HTML5 and CSS3, focusing on usability, performance, small size, [A-grade](http://developer.yahoo.com/yui/articles/gbs/) browser support, flexibility and [easy to use API](http://leaflet.cloudmade.com/reference.html). The OOP-based code of the library is designed to be modular, extensible and very easy to understand.
|
||||
|
||||
Check out the website for more information: [leaflet.cloudmade.com](http://leaflet.cloudmade.com)
|
||||
|
||||
## Contributing to Leaflet
|
||||
Let's make the best open-source library for maps that can possibly exist!
|
||||
Let's make the best open-source library for maps that can possibly exist!
|
||||
|
||||
Contributing is simple: make the changes in your fork, make sure that Leaflet builds successfully (see below) and then create a pull request to [Vladimir Agafonkin](http://github.com/mourner) (Leaflet maintainer). Updates to Leaflet [documentation](http://leaflet.cloudmade.com/reference.html) and [examples](http://leaflet.cloudmade.com/examples.html) (located in the `gh-pages` branch) are really appreciated too.
|
||||
|
||||
@ -18,7 +18,7 @@ Leaflet build system is powered by the Node.js platform and Jake, JSHint and Ugl
|
||||
|
||||
1. [Download and install Node](http://nodejs.org)
|
||||
2. Run the following commands in the command line:
|
||||
|
||||
|
||||
```
|
||||
npm install -g jake
|
||||
npm install jshint
|
||||
@ -29,4 +29,4 @@ Now that you have everything installed, run `jake` inside the Leaflet directory.
|
||||
|
||||
To make a custom build of the library with only the things you need, use the build helper (`build/build.html`) to choose the components (it figures out dependencies for you) and then run the command generated with it.
|
||||
|
||||
If you add any new files to the Leaflet source, make sure to also add them to `build/deps.js` so that the build system knows about them. Happy coding!
|
||||
If you add any new files to the Leaflet source, make sure to also add them to `build/deps.js` so that the build system knows about them. Happy coding!
|
||||
|
@ -86,13 +86,13 @@
|
||||
<li><a href="http://nodejs.org/#download">Download and install Node</a></li>
|
||||
<li>Run this in the command line:<br />
|
||||
<pre><code>npm install -g jake
|
||||
npm install -g jshint
|
||||
npm install -g uglify-js</code></pre></li>
|
||||
npm install jshint
|
||||
npm install uglify-js</code></pre></li>
|
||||
<li>Run this command inside the Leaflet directory: <br /><input type="text" id="command2" />
|
||||
</ol>
|
||||
<h2>Building using Closure Compiler</h2>
|
||||
<ol>
|
||||
<li><a href="http://closure-compiler.googlecode.com/files/compiler-latest.zip">Download Closure Compiler</a> and extract it into <code>lib/closure-compiler</code> directory</li>
|
||||
<li><a href="http://closure-compiler.googlecode.com/files/compiler-latest.zip">Download Closure Compiler</a>, extract it into <code>closure-compiler</code> directory</li>
|
||||
<li>Run this command in the root Leaflet directory: <br /><input type="text" id="command" /></li>
|
||||
</ol>
|
||||
</div>
|
||||
@ -139,7 +139,7 @@ npm install -g uglify-js</code></pre></li>
|
||||
}
|
||||
}
|
||||
|
||||
var command = 'java -jar lib/closure-compiler/compiler.jar ';
|
||||
var command = 'java -jar closure-compiler/compiler.jar ';
|
||||
for (var src in files) {
|
||||
command += '--js src/' + src + ' ';
|
||||
}
|
||||
@ -154,7 +154,7 @@ npm install -g uglify-js</code></pre></li>
|
||||
this.focus();
|
||||
this.select();
|
||||
};
|
||||
|
||||
|
||||
commandInput.onclick = inputSelect;
|
||||
commandInput2.onclick = inputSelect;
|
||||
|
||||
|
@ -43,19 +43,19 @@ exports.uglify = function (code) {
|
||||
var pro = uglifyjs.uglify;
|
||||
|
||||
var ast = uglifyjs.parser.parse(code);
|
||||
ast = pro.ast_mangle(ast);
|
||||
ast = pro.ast_squeeze(ast, {keep_comps: false});
|
||||
ast = pro.ast_mangle(ast, {mangle: true});
|
||||
ast = pro.ast_squeeze(ast);
|
||||
ast = pro.ast_squeeze_more(ast);
|
||||
|
||||
return pro.gen_code(ast) + ';';
|
||||
};
|
||||
|
||||
exports.combineFiles = function (files) {
|
||||
var content = '';
|
||||
var content = '(function () {\n\n';
|
||||
for (var i = 0, len = files.length; i < len; i++) {
|
||||
content += fs.readFileSync(files[i], 'utf8') + '\r\n\r\n';
|
||||
content += fs.readFileSync(files[i], 'utf8') + '\n\n';
|
||||
}
|
||||
return content;
|
||||
return content + '\n\n}());';
|
||||
};
|
||||
|
||||
exports.save = function (savePath, compressed) {
|
||||
|
@ -57,6 +57,12 @@ var deps = {
|
||||
desc: 'Markers to put on the map.'
|
||||
},
|
||||
|
||||
DivIcon: {
|
||||
src: ['layer/marker/DivIcon.js'],
|
||||
deps: ['Marker'],
|
||||
desc: 'Lightweight div-based icon for markers.'
|
||||
},
|
||||
|
||||
Popup: {
|
||||
src: ['layer/Popup.js', 'layer/marker/Marker.Popup.js', 'map/ext/Map.Popup.js'],
|
||||
deps: ['Marker'],
|
||||
@ -110,6 +116,12 @@ var deps = {
|
||||
desc: 'MultiPolygon and MultyPolyline layers.'
|
||||
},
|
||||
|
||||
Rectangle: {
|
||||
src: ['layer/vector/Rectangle.js'],
|
||||
deps: ['Polygon'],
|
||||
desc: ['Rectangle overlays.']
|
||||
},
|
||||
|
||||
Circle: {
|
||||
src: ['layer/vector/Circle.js'],
|
||||
deps: ['Path'],
|
||||
@ -170,9 +182,16 @@ var deps = {
|
||||
|
||||
MarkerDrag: {
|
||||
src: ['layer/marker/Marker.Drag.js'],
|
||||
deps: ['Marker'],
|
||||
desc: 'Makes markers draggable (by mouse or touch).'
|
||||
},
|
||||
|
||||
PolyEdit: {
|
||||
src: ['layer/vector/Polyline.Edit.js'],
|
||||
deps: ['Polyline', 'DivIcon'],
|
||||
desc: 'Polyline and polygon editing.'
|
||||
},
|
||||
|
||||
|
||||
ControlZoom: {
|
||||
src: ['control/Control.js',
|
||||
@ -189,6 +208,13 @@ var deps = {
|
||||
desc: 'Attribution control.'
|
||||
},
|
||||
|
||||
ControlScale: {
|
||||
src: ['control/Control.js',
|
||||
'map/ext/Map.Control.js',
|
||||
'control/Control.Scale.js'],
|
||||
desc: 'Scale control.'
|
||||
},
|
||||
|
||||
ControlLayers: {
|
||||
src: ['control/Control.js',
|
||||
'map/ext/Map.Control.js',
|
||||
|
@ -1,5 +1,6 @@
|
||||
exports.config = {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"predef": ["L"],
|
||||
|
||||
"debug": false,
|
||||
@ -17,7 +18,7 @@ exports.config = {
|
||||
"eqnull": false,
|
||||
"evil": false,
|
||||
"expr": false,
|
||||
"forin": false,
|
||||
"forin": true,
|
||||
"immed": true,
|
||||
"latedef": true,
|
||||
"loopfunc": false,
|
||||
@ -28,6 +29,7 @@ exports.config = {
|
||||
"shadow": false,
|
||||
"supernew": false,
|
||||
"undef": true,
|
||||
"funcscope": false,
|
||||
|
||||
"newcap": true,
|
||||
"noempty": true,
|
||||
|
@ -1,29 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Leaflet debug page</title>
|
||||
|
||||
<link rel="stylesheet" href="../../dist/leaflet.css" />
|
||||
<!--[if lte IE 8]><link rel="stylesheet" href="../../dist/leaflet.ie.css" /><![endif]-->
|
||||
|
||||
<link rel="stylesheet" href="../css/screen.css" />
|
||||
|
||||
<script src="../leaflet-include.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="map"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png',
|
||||
cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18}),
|
||||
latlng = new L.LatLng(50.5, 30.51);
|
||||
|
||||
var map = new L.Map('map').addLayer(cloudmade).setView(latlng, 15);
|
||||
|
||||
var zoomControl = new L.Control.Zoom();
|
||||
map.addControl(zoomControl);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -62,6 +62,7 @@
|
||||
'layer/Popup.js',
|
||||
|
||||
'layer/marker/Icon.js',
|
||||
'layer/marker/DivIcon.js',
|
||||
'layer/marker/Marker.js',
|
||||
'layer/marker/Marker.Popup.js',
|
||||
'layer/marker/Marker.Drag.js',
|
||||
@ -72,8 +73,10 @@
|
||||
'layer/vector/Path.VML.js',
|
||||
'layer/vector/canvas/Path.Canvas.js',
|
||||
'layer/vector/Polyline.js',
|
||||
'layer/vector/Polyline.Edit.js',
|
||||
'layer/vector/canvas/Polyline.Canvas.js',
|
||||
'layer/vector/Polygon.js',
|
||||
'layer/vector/Rectangle.js',
|
||||
'layer/vector/canvas/Polygon.Canvas.js',
|
||||
'layer/vector/MultiPoly.js',
|
||||
'layer/vector/Circle.js',
|
||||
@ -86,6 +89,7 @@
|
||||
'control/Control.Zoom.js',
|
||||
'control/Control.Attribution.js',
|
||||
'control/Control.Layers.js',
|
||||
'control/Control.Scale.js'
|
||||
];
|
||||
|
||||
function getSrcUrl() {
|
||||
@ -102,9 +106,10 @@
|
||||
}
|
||||
|
||||
var path = getSrcUrl();
|
||||
for (var i = 0; i < scripts.length; i++) {
|
||||
document.writeln("<script type='text/javascript' src='" + path + "../src/" + scripts[i] + "'></script>");
|
||||
for (var i = 0; i < scripts.length; i++) {
|
||||
document.writeln("<script src='" + path + scripts[i] + "'></script>");
|
||||
}
|
||||
document.writeln('<script>L.Icon.Default.imagePath = "' + path + '../dist/images";</script>');
|
||||
})();
|
||||
|
||||
function getRandomLatLng(map) {
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
var marker = new L.Marker(new L.LatLng(50.5, 30.505));
|
||||
map.addLayer(marker);
|
||||
marker.bindPopup("Hello World").openPopup();
|
||||
|
||||
var marker2 = new L.Marker(new L.LatLng(50.502, 30.515));
|
||||
map.addLayer(marker2);
|
||||
@ -41,6 +42,7 @@
|
||||
});
|
||||
|
||||
map.addControl(layersControl);
|
||||
map.addControl(new L.Control.Scale());
|
||||
|
||||
</script>
|
||||
</body>
|
35
debug/map/geolocation.html
Normal file
35
debug/map/geolocation.html
Normal file
@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Leaflet geolocation debug page</title>
|
||||
|
||||
<link rel="stylesheet" href="../../dist/leaflet.css" />
|
||||
<!--[if lte IE 8]><link rel="stylesheet" href="../../dist/leaflet.ie.css" /><![endif]-->
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<link rel="stylesheet" href="../css/screen.css" />
|
||||
|
||||
<script src="../leaflet-include.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="map"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png',
|
||||
cloudmadeAttribution = 'Map data © 2011 OpenStreetMap contributors, Imagery © 2011 CloudMade',
|
||||
cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18, attribution: cloudmadeAttribution});
|
||||
|
||||
var map = new L.Map('map', {zoom: 15, layers: [cloudmade]});
|
||||
|
||||
function logEvent(e) { console.log(e.type); }
|
||||
map.on('locationerror', logEvent);
|
||||
map.on('locationfound', logEvent);
|
||||
|
||||
map.locate({setView: true});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -20,23 +20,15 @@
|
||||
|
||||
var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png',
|
||||
cloudmadeAttribution = 'Map data © 2011 OpenStreetMap contributors, Imagery © 2011 CloudMade',
|
||||
cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18, attribution: cloudmadeAttribution});
|
||||
cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18, attribution: cloudmadeAttribution}),
|
||||
latlng = new L.LatLng(50.5, 30.51);
|
||||
|
||||
var map = new L.Map('map').addLayer(cloudmade);
|
||||
var map = new L.Map('map', {center: latlng, zoom: 15, layers: [cloudmade]});
|
||||
|
||||
map.on('locationfound', function(e) {
|
||||
var marker = new L.Marker(e.latlng);
|
||||
map.addLayer(marker);
|
||||
var marker = new L.Marker(latlng);
|
||||
map.addLayer(marker);
|
||||
|
||||
marker.bindPopup("<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec odio. Quisque volutpat mattis eros. Nullam malesuada erat ut turpis. Suspendisse urna nibh, viverra non, semper suscipit, posuere a, pede.</p><p>Donec nec justo eget felis facilisis fermentum. Aliquam porttitor mauris sit amet orci. Aenean dignissim pellentesque felis.</p>");
|
||||
});
|
||||
|
||||
map.on('locationerror', function(e) {
|
||||
alert(e.message);
|
||||
map.fitWorld();
|
||||
});
|
||||
|
||||
map.locateAndSetView();
|
||||
marker.bindPopup("<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec odio. Quisque volutpat mattis eros. Nullam malesuada erat ut turpis. Suspendisse urna nibh, viverra non, semper suscipit, posuere a, pede.</p><p>Donec nec justo eget felis facilisis fermentum. Aliquam porttitor mauris sit amet orci. Aenean dignissim pellentesque felis.</p>");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -14,7 +14,7 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="map" style="width: 600px; height: 600px; border: 1px solid #ccc"></div>
|
||||
<div id="map"></div>
|
||||
<button id="populate">Populate with 10 markers</button>
|
||||
|
||||
<script type="text/javascript">
|
||||
@ -26,6 +26,8 @@
|
||||
|
||||
var map = new L.Map('map', {center: latlng, zoom: 15, layers: [cloudmade]});
|
||||
|
||||
//map.on('click', function () { alert('hi'); });
|
||||
|
||||
var markers = new L.FeatureGroup();
|
||||
|
||||
function populate() {
|
||||
|
88
debug/vector/bounds-extend.html
Normal file
88
debug/vector/bounds-extend.html
Normal file
@ -0,0 +1,88 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Leaflet debug page</title>
|
||||
|
||||
<link rel="stylesheet" href="../../dist/leaflet.css" />
|
||||
<!--[if lte IE 8]><link rel="stylesheet" href="../../dist/leaflet.ie.css" /><![endif]-->
|
||||
|
||||
<link rel="stylesheet" href="../css/screen.css" />
|
||||
|
||||
<script src="../leaflet-include.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map" style="width: 800px; height: 600px; border: 1px solid #ccc"></div>
|
||||
<button onclick="boundsExtendBounds();">Extend the bounds of the center rectangle with the upper right rectangle</button>
|
||||
<button onclick="boundsExtendLatLng()">Extend the bounds of the center rectangle with the lower left marker</button>
|
||||
<script src="route.js"></script>
|
||||
<script>
|
||||
var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png',
|
||||
cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18});
|
||||
|
||||
var latLng = new L.LatLng(54.18815548107151, -7.657470703124999);
|
||||
|
||||
var bounds1 = new L.LatLngBounds(new L.LatLng(54.559322, -5.767822), new L.LatLng(56.1210604, -3.021240));
|
||||
var bounds2 = new L.LatLngBounds(new L.LatLng(56.56023925701561, -2.076416015625), new L.LatLng(57.01158038001565, -0.9777832031250001));
|
||||
var bounds3;
|
||||
|
||||
var map = new L.Map('map', {
|
||||
layers: [cloudmade],
|
||||
center: bounds1.getCenter(),
|
||||
zoom: 7
|
||||
});
|
||||
|
||||
var rectangle1 = new L.Rectangle(bounds1);
|
||||
var rectangle2 = new L.Rectangle(bounds2);
|
||||
var rectangle3;
|
||||
|
||||
var marker = new L.Marker(latLng);
|
||||
|
||||
map.addLayer(rectangle1).addLayer(rectangle2).addLayer(marker);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function boundsExtendBounds() {
|
||||
if (rectangle3) {
|
||||
map.removeLayer(rectangle3);
|
||||
rectangle3 = null;
|
||||
}
|
||||
if (bounds3) {
|
||||
bounds3 = null;
|
||||
}
|
||||
bounds3 = new L.LatLngBounds(bounds1.getSouthWest(), bounds1.getNorthEast());
|
||||
bounds3.extend(bounds2);
|
||||
rectangle3 = new L.Rectangle(bounds3, {
|
||||
color: "#ff0000",
|
||||
weight: 1,
|
||||
opacity: 1,
|
||||
fillOpacity: 0
|
||||
});
|
||||
|
||||
map.addLayer(rectangle3);
|
||||
}
|
||||
|
||||
function boundsExtendLatLng() {
|
||||
if (rectangle3) {
|
||||
map.removeLayer(rectangle3);
|
||||
rectangle3 = null;
|
||||
}
|
||||
if (bounds3) {
|
||||
bounds3 = null;
|
||||
}
|
||||
bounds3 = new L.LatLngBounds(bounds1.getSouthWest(), bounds1.getNorthEast());
|
||||
bounds3.extend(marker.getLatLng());
|
||||
rectangle3 = new L.Rectangle(bounds3, {
|
||||
color: "#ff0000",
|
||||
weight: 1,
|
||||
opacity: 1,
|
||||
fillOpacity: 0
|
||||
});
|
||||
|
||||
map.addLayer(rectangle3);
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -5,9 +5,9 @@
|
||||
|
||||
<link rel="stylesheet" href="../../dist/leaflet.css" />
|
||||
<!--[if lte IE 8]><link rel="stylesheet" href="../../dist/leaflet.ie.css" /><![endif]-->
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../css/screen.css" />
|
||||
|
||||
|
||||
<script src="../leaflet-include.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
@ -17,27 +17,35 @@
|
||||
<script>
|
||||
var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png',
|
||||
cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18}),
|
||||
map = new L.Map('map', {layers: [cloudmade], center: new L.LatLng(50.5, 30.5), zoom: 15});
|
||||
|
||||
|
||||
var latlngs = [];
|
||||
latlngs.push(getRandomLatLng(map));
|
||||
latlngs.push(getRandomLatLng(map));
|
||||
latlngs.push(getRandomLatLng(map));
|
||||
|
||||
var path = new L.Polygon(latlngs);
|
||||
map = new L.Map('map', {layers: [cloudmade], center: new L.LatLng(51.505, -0.04), zoom: 13});
|
||||
|
||||
console.log(latlngs);
|
||||
|
||||
var marker = new L.Marker(latlngs[0], {draggable: true});
|
||||
map.addLayer(marker);
|
||||
|
||||
marker.on('drag', function() {
|
||||
latlngs[0] = marker.getLatLng();
|
||||
path.setLatLngs(latlngs);
|
||||
});
|
||||
|
||||
map.addLayer(path);
|
||||
|
||||
var polygon = new L.Polygon([
|
||||
new L.LatLng(51.51, -0.1),
|
||||
new L.LatLng(51.5, -0.06),
|
||||
new L.LatLng(51.52, -0.03)
|
||||
]);
|
||||
|
||||
polygon.editing.enable();
|
||||
|
||||
map.addLayer(polygon);
|
||||
|
||||
var polyline = new L.Polyline([
|
||||
new L.LatLng(51.49, -0.02),
|
||||
new L.LatLng(51.51, 0),
|
||||
new L.LatLng(51.52, -0.02)
|
||||
]);
|
||||
|
||||
polyline.editing.enable();
|
||||
|
||||
map.addLayer(polyline);
|
||||
|
||||
polygon.on('edit', function() {
|
||||
console.log('Polygon was edited!');
|
||||
});
|
||||
polyline.on('edit', function() {
|
||||
console.log('Polyline was edited!');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
94
debug/vector/feature-group-bounds.html
Normal file
94
debug/vector/feature-group-bounds.html
Normal file
@ -0,0 +1,94 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Leaflet debug page</title>
|
||||
|
||||
<link rel="stylesheet" href="../../dist/leaflet.css" />
|
||||
<!--[if lte IE 8]><link rel="stylesheet" href="../../dist/leaflet.ie.css" /><![endif]-->
|
||||
|
||||
<link rel="stylesheet" href="../css/screen.css" />
|
||||
|
||||
<script src="../leaflet-include.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="map" style="width: 600px; height: 600px; border: 1px solid #ccc"></div>
|
||||
<button onclick="geojsonLayerBounds();">Show GeoJSON layer bounds</button>
|
||||
<button onclick="featureGroupBounds();">Show feature group bounds</button>
|
||||
|
||||
<script type="text/javascript" src="geojson-sample.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png',
|
||||
cloudmadeAttribution = 'Map data © 2011 OpenStreetMap contributors, Imagery © 2011 CloudMade',
|
||||
cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18, attribution: cloudmadeAttribution}),
|
||||
rectangle,
|
||||
featureGroup;
|
||||
|
||||
var map = new L.Map('map', {
|
||||
center: new L.LatLng(0.78, 102.37),
|
||||
zoom: 7,
|
||||
layers: [cloudmade]
|
||||
});
|
||||
|
||||
var geojson = new L.GeoJSON();
|
||||
|
||||
/* points are rendered as markers by default, but you can change this:
|
||||
|
||||
var geojson = new L.GeoJSON(null, {
|
||||
pointToLayer: function(latlng) { return new L.CircleMarker(latlng); }
|
||||
});
|
||||
*/
|
||||
|
||||
geojson.on('featureparse', function(e) {
|
||||
// you can style features depending on their properties, etc.
|
||||
var popupText = 'geometry type: ' + e.geometryType;
|
||||
|
||||
if (e.layer.setStyle && e.properties && e.properties.color) {
|
||||
e.layer.setStyle({color: e.properties.color});
|
||||
popupText += '<br/>color: ' + e.properties.color;
|
||||
}
|
||||
e.layer.bindPopup(popupText);
|
||||
});
|
||||
|
||||
geojson.addGeoJSON(geojsonSample);
|
||||
geojson.addLayer(new L.Marker(new L.LatLng(2.745530718801952, 105.194091796875)))
|
||||
|
||||
var eye1 = new L.Marker(new L.LatLng(-0.7250783020332547, 101.8212890625));
|
||||
var eye2 = new L.Marker(new L.LatLng(-0.7360637370492077, 103.2275390625));
|
||||
var nose = new L.Marker(new L.LatLng(-1.3292264529974207, 102.5463867187));
|
||||
var mouth = new L.Polyline([
|
||||
new L.LatLng(-1.3841426927920029, 101.7333984375),
|
||||
new L.LatLng(-1.6037944300589726, 101.964111328125),
|
||||
new L.LatLng(-1.6806671337507222, 102.249755859375),
|
||||
new L.LatLng(-1.7355743631421197, 102.67822265625),
|
||||
new L.LatLng(-1.5928123762763, 103.0078125),
|
||||
new L.LatLng(-1.3292264529974207, 103.3154296875)
|
||||
]);
|
||||
map.addLayer(eye1).addLayer(eye2).addLayer(nose).addLayer(mouth);
|
||||
featureGroup = new L.FeatureGroup([eye1, eye2, nose, mouth]);
|
||||
|
||||
map.addLayer(geojson);
|
||||
map.addLayer(featureGroup);
|
||||
|
||||
function geojsonLayerBounds() {
|
||||
if (rectangle) {
|
||||
rectangle.setBounds(geojson.getBounds());
|
||||
} else {
|
||||
rectangle = new L.Rectangle(geojson.getBounds());
|
||||
map.addLayer(rectangle);
|
||||
}
|
||||
}
|
||||
|
||||
function featureGroupBounds() {
|
||||
if (rectangle) {
|
||||
rectangle.setBounds(featureGroup.getBounds());
|
||||
} else {
|
||||
rectangle = new L.Rectangle(featureGroup.getBounds());
|
||||
map.addLayer(rectangle);
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -13,41 +13,39 @@
|
||||
<body>
|
||||
|
||||
<div id="map" style="width: 500px; height: 500px;"></div>
|
||||
|
||||
<button onclick="javascript:capture1();">Capture Bounds 1</button>
|
||||
<button onclick="javascript:capture2();">Capture Bounds 2</button>
|
||||
<button onclick="javascript:testBounds();">Test Bounds</button>
|
||||
<input type="button" value="Set blue rectangle bounds as current map extent." onclick="resetBounds();" />
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png',
|
||||
cloudmadeAttribution = 'Map data © 2011 OpenStreetMap contributors, Imagery © 2011 CloudMade',
|
||||
cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18, attribution: cloudmadeAttribution}),
|
||||
bounds = new L.LatLngBounds(new L.LatLng(49.5, -11.3), new L.LatLng(61.2, 2.5));
|
||||
cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18, attribution: cloudmadeAttribution});;
|
||||
|
||||
var bounds1, bounds2;
|
||||
var bounds = new L.LatLngBounds(new L.LatLng(54.559322, -5.767822), new L.LatLng(56.1210604, -3.021240));
|
||||
var bounds2 = new L.LatLngBounds(new L.LatLng(56.2124322195806, -3.427734375), new L.LatLng(56.307776937156945, -3.2560729980468746));
|
||||
|
||||
var rectangle = new L.Rectangle(bounds);
|
||||
var styledRectangle = new L.Rectangle(bounds2, {
|
||||
fillColor: "#ff7800",
|
||||
color: "#000000",
|
||||
opacity: 1,
|
||||
weight: 2
|
||||
});
|
||||
|
||||
rectangle.on("click", function () {
|
||||
alert("you clicked a rectangle.")
|
||||
});
|
||||
|
||||
var map = new L.Map('map', {
|
||||
center: bounds.getCenter(),
|
||||
zoom: 7,
|
||||
layers: [cloudmade],
|
||||
maxBounds: bounds
|
||||
layers: [cloudmade]
|
||||
});
|
||||
|
||||
function capture1 () {
|
||||
bounds1 = map.getBounds();
|
||||
}
|
||||
|
||||
function capture2() {
|
||||
bounds2 = map.getBounds();
|
||||
}
|
||||
|
||||
function testBounds() {
|
||||
if (!(bounds1 && bounds2)) {
|
||||
alert("Bounds 1 and 2 have not been set");
|
||||
return;
|
||||
}
|
||||
alert("Bounds 1 " + (bounds1.equals(bounds2) ? "equals": "does not equal") + " bounds 2.")
|
||||
|
||||
map.addLayer(rectangle).addLayer(styledRectangle);
|
||||
|
||||
function resetBounds() {
|
||||
rectangle.setBounds(map.getBounds());
|
||||
}
|
||||
|
||||
</script>
|
121
debug/vector/touchzoomemu.html
Normal file
121
debug/vector/touchzoomemu.html
Normal file
@ -0,0 +1,121 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Leaflet debug page</title>
|
||||
|
||||
<link rel="stylesheet" href="../../dist/leaflet.css" />
|
||||
<!--[if lte IE 8]><link rel="stylesheet" href="../../dist/leaflet.ie.css" /><![endif]-->
|
||||
|
||||
<link rel="stylesheet" href="../css/screen.css" />
|
||||
|
||||
<script src="../leaflet-include.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map" style="width: 800px; height: 600px; border: 1px solid #ccc"></div>
|
||||
<div style="background-color:chartreuse; width: 100px; height:100px; position: absolute; left: 850px; top: 10px" onclick="Hack1()">Hack1Touch</div>
|
||||
<div style="background-color:coral; width: 100px; height:100px; position: absolute; left: 850px; top: 120px" onclick="Hack2()">Hack2Touch</div>
|
||||
<script src="route.js"></script>
|
||||
<script>
|
||||
var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png',
|
||||
cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18}),
|
||||
map = new L.Map('map', {layers: [cloudmade], center: new L.LatLng(51.505, -0.04), zoom: 13});
|
||||
|
||||
|
||||
var polygon = new L.Polygon([
|
||||
new L.LatLng(51.51, -0.1),
|
||||
new L.LatLng(51.5, -0.06),
|
||||
new L.LatLng(51.52, -0.03)
|
||||
]);
|
||||
|
||||
polygon.editing.enable();
|
||||
|
||||
map.addLayer(polygon);
|
||||
|
||||
var polyline = new L.Polyline([
|
||||
new L.LatLng(51.49, -0.02),
|
||||
new L.LatLng(51.51, 0),
|
||||
new L.LatLng(51.52, -0.02)
|
||||
]);
|
||||
|
||||
polyline.editing.enable();
|
||||
|
||||
map.addLayer(polyline);
|
||||
|
||||
polygon.on('edit', function() {
|
||||
console.log('Polygon was edited!');
|
||||
});
|
||||
polyline.on('edit', function() {
|
||||
console.log('Polyline was edited!');
|
||||
});
|
||||
|
||||
var _timerAt, _timer;
|
||||
function Hack1() {
|
||||
_timerAt = 0;
|
||||
clearInterval(_timer);
|
||||
_timer = setInterval(Hack1Timer, 1000);
|
||||
}
|
||||
function Hack1Timer() {
|
||||
switch (_timerAt) {
|
||||
case 0:
|
||||
map.touchZoom._onTouchStart({ touches: [{ pageX: 405, pageY: 312 }, { pageX: 233, pageY: 321 }] });
|
||||
break;
|
||||
case 1:
|
||||
map.touchZoom._onTouchMove({ touches: [{ pageX: 412, pageY: 312 }, { pageX: 236, pageY: 322 }] });
|
||||
break;
|
||||
case 2:
|
||||
map.touchZoom._onTouchMove({ touches: [{ pageX: 423, pageY: 313 }, { pageX: 243, pageY: 321 }] });
|
||||
break;
|
||||
case 3:
|
||||
map.touchZoom._onTouchMove({ touches: [{ pageX: 476, pageY: 326 }, { pageX: 299, pageY: 321 }] });
|
||||
break;
|
||||
case 4:
|
||||
map.touchZoom._onTouchEnd();
|
||||
break;
|
||||
case 5:
|
||||
clearInterval(_timer);
|
||||
break;
|
||||
}
|
||||
_timerAt++;
|
||||
}
|
||||
function Hack2() {
|
||||
map.touchZoom._onTouchStart({ touches: [{ pageX: 405, pageY: 312 }, { pageX: 233, pageY: 321 }] });
|
||||
map.touchZoom._onTouchMove({ touches: [{ pageX: 476, pageY: 326 }, { pageX: 299, pageY: 321 }] });
|
||||
//_timerAt = 0;
|
||||
//clearInterval(_timer);
|
||||
//_timer = setInterval(Hack2Timer, 100);
|
||||
}
|
||||
function Hack2Timer() {
|
||||
switch (_timerAt) {
|
||||
case 0:
|
||||
map.touchZoom._onTouchStart({ touches: [{ pageX: 100, pageY: 100 }, { pageX: 50, pageY: 100}] });
|
||||
break;
|
||||
case 1:
|
||||
map.touchZoom._onTouchMove({ touches: [{ pageX: 100, pageY: 100 }, { pageX: 50, pageY: 100 }] });
|
||||
break;
|
||||
case 2:
|
||||
map.touchZoom._onTouchMove({ touches: [{ pageX: 110, pageY: 100 }, { pageX: 50, pageY: 100 }] });
|
||||
break;
|
||||
case 3:
|
||||
map.touchZoom._onTouchMove({ touches: [{ pageX: 120, pageY: 100 }, { pageX: 50, pageY: 100 }] });
|
||||
break;
|
||||
case 4:
|
||||
map.touchZoom._onTouchMove({ touches: [{ pageX: 130, pageY: 100 }, { pageX: 50, pageY: 100 }] });
|
||||
break;
|
||||
case 5:
|
||||
map.touchZoom._onTouchMove({ touches: [{ pageX: 140, pageY: 100 }, { pageX: 50, pageY: 100 }] });
|
||||
break;
|
||||
case 6:
|
||||
map.touchZoom._onTouchMove({ touches: [{ pageX: 150, pageY: 100 }, { pageX: 50, pageY: 100 }] });
|
||||
break;
|
||||
case 7:
|
||||
map.touchZoom._onTouchEnd();
|
||||
break;
|
||||
case 8:
|
||||
clearInterval(_timer);
|
||||
break;
|
||||
}
|
||||
_timerAt++;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -17,14 +17,14 @@
|
||||
|
||||
<script>
|
||||
|
||||
var map = new L.Map('map', {fadeAnimation: false});
|
||||
var map = new L.Map('map');
|
||||
|
||||
var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png',
|
||||
cloudmadeAttribution = 'Map data © 2011 OpenStreetMap contributors, Imagery © 2011 CloudMade',
|
||||
cloudmade = new L.TileLayer(cloudmadeUrl, {
|
||||
maxZoom: 18,
|
||||
attribution: cloudmadeAttribution
|
||||
});
|
||||
var cloudmade = new L.TileLayer('http://{s}.tile.cloudmade.com/{key}/{styleId}/256/{z}/{x}/{y}.png', {
|
||||
maxZoom: 18,
|
||||
attribution: 'Map data © 2011 OpenStreetMap contributors, Imagery © 2011 CloudMade',
|
||||
key: 'BC9A493B41014CAABB98F0471D759707',
|
||||
styleId: 997
|
||||
});
|
||||
|
||||
map.setView(new L.LatLng(51.505, -0.09), 13).addLayer(cloudmade);
|
||||
|
||||
@ -60,4 +60,4 @@
|
||||
map.addLayer(polygon);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
BIN
dist/images/marker.png
vendored
BIN
dist/images/marker.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 2.5 KiB |
2775
dist/leaflet-src.js
vendored
2775
dist/leaflet-src.js
vendored
File diff suppressed because it is too large
Load Diff
142
dist/leaflet.css
vendored
142
dist/leaflet.css
vendored
@ -17,7 +17,11 @@
|
||||
.leaflet-container {
|
||||
overflow: hidden;
|
||||
}
|
||||
.leaflet-tile-pane, .leaflet-container {
|
||||
.leaflet-tile-pane,
|
||||
.leaflet-container,
|
||||
.leaflet-corner,
|
||||
.leaflet-popup {
|
||||
/* TODO make this configurable */
|
||||
-webkit-transform: translate3d(0,0,0);
|
||||
}
|
||||
.leaflet-tile,
|
||||
@ -34,9 +38,22 @@
|
||||
.leaflet-clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.leaflet-dragging {
|
||||
cursor: move;
|
||||
}
|
||||
.leaflet-dragging .leaflet-clickable {
|
||||
cursor: move;
|
||||
}
|
||||
.leaflet-container img {
|
||||
max-width: none !important;
|
||||
}
|
||||
.leaflet-div-icon {
|
||||
background: #fff;
|
||||
border: 1px solid #666;
|
||||
}
|
||||
.leaflet-editing-icon {
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.leaflet-tile-pane { z-index: 2; }
|
||||
|
||||
@ -52,7 +69,8 @@
|
||||
}
|
||||
|
||||
.leaflet-tile {
|
||||
visibility: hidden;
|
||||
filter: inherit;
|
||||
visibility: hidden;
|
||||
}
|
||||
.leaflet-tile-loaded {
|
||||
visibility: inherit;
|
||||
@ -105,7 +123,7 @@ a.leaflet-active {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.leaflet-control-zoom, .leaflet-control-layers {
|
||||
.leaflet-control-zoom {
|
||||
-moz-border-radius: 7px;
|
||||
-webkit-border-radius: 7px;
|
||||
border-radius: 7px;
|
||||
@ -132,7 +150,7 @@ a.leaflet-active {
|
||||
.leaflet-control-zoom a:hover {
|
||||
background-color: #fff;
|
||||
}
|
||||
.leaflet-big-buttons .leaflet-control-zoom a {
|
||||
.leaflet-touch .leaflet-control-zoom a {
|
||||
width: 27px;
|
||||
height: 27px;
|
||||
}
|
||||
@ -145,18 +163,18 @@ a.leaflet-active {
|
||||
}
|
||||
|
||||
.leaflet-control-layers {
|
||||
-moz-box-shadow: 0 0 7px #999;
|
||||
-webkit-box-shadow: 0 0 7px #999;
|
||||
box-shadow: 0 0 7px #999;
|
||||
|
||||
box-shadow: 0 1px 7px #999;
|
||||
background: #f8f8f9;
|
||||
-moz-border-radius: 8px;
|
||||
-webkit-border-radius: 8px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.leaflet-control-layers a {
|
||||
background-image: url(images/layers.png);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
.leaflet-big-buttons .leaflet-control-layers a {
|
||||
.leaflet-touch .leaflet-control-layers a {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
@ -189,23 +207,57 @@ a.leaflet-active {
|
||||
}
|
||||
|
||||
.leaflet-container .leaflet-control-attribution {
|
||||
margin: 0;
|
||||
padding: 0 5px;
|
||||
|
||||
font: 11px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
color: #333;
|
||||
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
box-shadow: 0 0 5px #bbb;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
-moz-box-shadow: 0 0 7px #ccc;
|
||||
-webkit-box-shadow: 0 0 7px #ccc;
|
||||
box-shadow: 0 0 7px #ccc;
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale-line {
|
||||
padding: 0 5px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.leaflet-container .leaflet-control-attribution,
|
||||
.leaflet-container .leaflet-control-scale {
|
||||
font: 11px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.leaflet-left .leaflet-control-scale {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control-scale {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.leaflet-control-scale-line {
|
||||
border: 2px solid #777;
|
||||
border-top: none;
|
||||
color: black;
|
||||
line-height: 1;
|
||||
font-size: 10px;
|
||||
padding-bottom: 2px;
|
||||
text-shadow: 1px 1px 1px #fff;
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.leaflet-control-scale-line:nth-child(2) {
|
||||
border-top: 2px solid #777;
|
||||
padding-top: 1px;
|
||||
border-bottom: none;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-attribution, .leaflet-touch .leaflet-control-layers {
|
||||
box-shadow: none;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers {
|
||||
border: 5px solid #bbb;
|
||||
}
|
||||
|
||||
|
||||
/* Fade animations */
|
||||
|
||||
.leaflet-fade-anim .leaflet-tile {
|
||||
.leaflet-fade-anim .leaflet-tile, .leaflet-fade-anim .leaflet-popup {
|
||||
opacity: 0;
|
||||
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
@ -213,47 +265,48 @@ a.leaflet-active {
|
||||
-o-transition: opacity 0.2s linear;
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-tile-loaded {
|
||||
.leaflet-fade-anim .leaflet-tile-loaded, .leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.leaflet-fade-anim .leaflet-popup {
|
||||
opacity: 0;
|
||||
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
-moz-transition: opacity 0.2s linear;
|
||||
-o-transition: opacity 0.2s linear;
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-tile {
|
||||
.leaflet-zoom-anim .leaflet-tile, .leaflet-pan-anim .leaflet-tile {
|
||||
-webkit-transition: none;
|
||||
-moz-transition: none;
|
||||
-o-transition: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-objects-pane {
|
||||
visibility: hidden;
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0.25,0.1,0.25,0.75);
|
||||
-moz-transition: -moz-transform 0.25s cubic-bezier(0.25,0.1,0.25,0.75);
|
||||
-o-transition: -o-transform 0.25s cubic-bezier(0.25,0.1,0.25,0.75);
|
||||
transition: transform 0.25s cubic-bezier(0.25,0.1,0.25,0.75);
|
||||
}
|
||||
|
||||
.leaflet-touching .leaflet-zoom-animated {
|
||||
-webkit-transition: none;
|
||||
-moz-transition: none;
|
||||
-o-transition: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-hide {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/* Popup layout */
|
||||
|
||||
.leaflet-popup {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
-webkit-transform: translate3d(0,0,0);
|
||||
}
|
||||
.leaflet-popup-content-wrapper {
|
||||
padding: 1px;
|
||||
text-align: left;
|
||||
}
|
||||
.leaflet-popup-content {
|
||||
margin: 19px;
|
||||
margin: 14px 20px;
|
||||
}
|
||||
.leaflet-popup-tip-container {
|
||||
margin: 0 auto;
|
||||
@ -277,8 +330,8 @@ a.leaflet-active {
|
||||
}
|
||||
.leaflet-popup-close-button {
|
||||
position: absolute;
|
||||
top: 9px;
|
||||
right: 9px;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
@ -288,6 +341,11 @@ a.leaflet-active {
|
||||
.leaflet-popup-content p {
|
||||
margin: 18px 0;
|
||||
}
|
||||
.leaflet-popup-scrolled {
|
||||
overflow: auto;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
|
||||
/* Visual appearance */
|
||||
@ -306,9 +364,9 @@ a.leaflet-active {
|
||||
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
|
||||
background: white;
|
||||
|
||||
box-shadow: 0 1px 10px #888;
|
||||
-moz-box-shadow: 0 1px 10px #888;
|
||||
-webkit-box-shadow: 0 1px 14px #999;
|
||||
box-shadow: 0 3px 10px #888;
|
||||
-moz-box-shadow: 0 3px 10px #888;
|
||||
-webkit-box-shadow: 0 3px 14px #999;
|
||||
}
|
||||
.leaflet-popup-content-wrapper {
|
||||
-moz-border-radius: 20px;
|
||||
|
4
dist/leaflet.ie.css
vendored
4
dist/leaflet.ie.css
vendored
@ -1,7 +1,3 @@
|
||||
.leaflet-tile {
|
||||
filter: inherit;
|
||||
}
|
||||
|
||||
.leaflet-vml-shape {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
|
2
dist/leaflet.js
vendored
2
dist/leaflet.js
vendored
File diff suppressed because one or more lines are too long
3
lib/closure-compiler/.gitignore
vendored
3
lib/closure-compiler/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
compiler.jar
|
||||
COPYING
|
||||
README
|
@ -2,24 +2,24 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Jasmine Test Runner</title>
|
||||
<link rel="stylesheet" type="text/css" href="../lib/jasmine/jasmine.css">
|
||||
<script type="text/javascript" src="../lib/jasmine/jasmine.js"></script>
|
||||
<script type="text/javascript" src="../lib/jasmine/jasmine-html.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="jasmine/jasmine.css">
|
||||
<script type="text/javascript" src="jasmine/jasmine.js"></script>
|
||||
<script type="text/javascript" src="jasmine/jasmine-html.js"></script>
|
||||
|
||||
<!-- source files -->
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
L = 'test'; //to test L#noConflict later
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/javascript" src="../debug/leaflet-include.js"></script>
|
||||
|
||||
|
||||
|
||||
<!-- spec files -->
|
||||
|
||||
|
||||
<script type="text/javascript" src="suites/SpecHelper.js"></script>
|
||||
<script type="text/javascript" src="suites/LeafletSpec.js"></script>
|
||||
|
||||
|
||||
<!-- /core -->
|
||||
<script type="text/javascript" src="suites/core/UtilSpec.js"></script>
|
||||
<script type="text/javascript" src="suites/core/ClassSpec.js"></script>
|
||||
@ -42,7 +42,7 @@
|
||||
<!-- /layer -->
|
||||
<script type="text/javascript" src="suites/layer/TileLayerSpec.js"></script>
|
||||
<script type="text/javascript" src="suites/layer/vector/PolylineGeometrySpec.js"></script>
|
||||
|
||||
|
||||
<!-- /map -->
|
||||
<script type="text/javascript" src="suites/map/MapSpec.js"></script>
|
||||
</head>
|
||||
|
@ -46,6 +46,7 @@ describe("Class", function() {
|
||||
expect(method).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
/* superclass deprecated
|
||||
it("should grant the ability to call parent methods, including constructor", function() {
|
||||
var Klass2 = Klass.extend({
|
||||
initialize: function() {},
|
||||
@ -60,7 +61,7 @@ describe("Class", function() {
|
||||
|
||||
b.constructor.superclass.bar.call(this);
|
||||
expect(method).toHaveBeenCalled();
|
||||
});
|
||||
}); */
|
||||
|
||||
it("should support static properties", function() {
|
||||
expect(Klass.bla).toEqual(1);
|
||||
@ -123,6 +124,7 @@ describe("Class", function() {
|
||||
});
|
||||
});
|
||||
|
||||
/* superclass deprecated
|
||||
it("should have working superclass access with inheritance level > 2", function() {
|
||||
var constructor2 = jasmine.createSpy("Klass2 constructor"),
|
||||
constructor3 = jasmine.createSpy("Klass3 constructor");
|
||||
@ -149,5 +151,6 @@ describe("Class", function() {
|
||||
expect(constructor2).toHaveBeenCalled();
|
||||
expect(constructor).toHaveBeenCalled();
|
||||
});
|
||||
*/
|
||||
});
|
||||
});
|
@ -1,33 +1,18 @@
|
||||
var L, originalL;
|
||||
|
||||
(function (root) {
|
||||
root.L = {
|
||||
VERSION: '0.4',
|
||||
if (typeof exports !== 'undefined') {
|
||||
L = exports;
|
||||
} else {
|
||||
L = {};
|
||||
|
||||
originalL = window.L;
|
||||
|
||||
ROOT_URL: root.L_ROOT_URL || (function () {
|
||||
var scripts = document.getElementsByTagName('script'),
|
||||
leafletRe = /\/?leaflet[\-\._]?([\w\-\._]*)\.js\??/;
|
||||
|
||||
var i, len, src, matches;
|
||||
|
||||
for (i = 0, len = scripts.length; i < len; i++) {
|
||||
src = scripts[i].src;
|
||||
matches = src.match(leafletRe);
|
||||
|
||||
if (matches) {
|
||||
if (matches[1] === 'include') {
|
||||
return '../../dist/';
|
||||
}
|
||||
return src.split(leafletRe)[0] + '/';
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}()),
|
||||
|
||||
noConflict: function () {
|
||||
root.L = this._originalL;
|
||||
return this;
|
||||
},
|
||||
|
||||
_originalL: root.L
|
||||
L.noConflict = function () {
|
||||
window.L = originalL;
|
||||
return L;
|
||||
};
|
||||
}(this));
|
||||
|
||||
window.L = L;
|
||||
}
|
||||
|
||||
L.version = '0.4';
|
||||
|
@ -1,52 +1,60 @@
|
||||
L.Control.Attribution = L.Control.extend({
|
||||
options: {
|
||||
position: 'bottomright'
|
||||
position: 'bottomright',
|
||||
prefix: 'Powered by <a href="http://leaflet.cloudmade.com">Leaflet</a>'
|
||||
},
|
||||
|
||||
initialize: function (prefix, options) {
|
||||
initialize: function (options) {
|
||||
L.Util.setOptions(this, options);
|
||||
|
||||
this._prefix = prefix || 'Powered by <a href="http://leaflet.cloudmade.com">Leaflet</a>';
|
||||
this._attributions = {};
|
||||
},
|
||||
|
||||
onAdd: function (map) {
|
||||
this._container = L.DomUtil.create('div', 'leaflet-control-attribution');
|
||||
L.DomEvent.disableClickPropagation(this._container);
|
||||
this._map = map;
|
||||
|
||||
map
|
||||
.on('layeradd', this._onLayerAdd, this)
|
||||
.on('layerremove', this._onLayerRemove, this);
|
||||
|
||||
this._update();
|
||||
|
||||
return this._container;
|
||||
},
|
||||
|
||||
onRemove: function (map) {
|
||||
map
|
||||
.off('layeradd', this._onLayerAdd)
|
||||
.off('layerremove', this._onLayerRemove);
|
||||
|
||||
},
|
||||
|
||||
setPrefix: function (prefix) {
|
||||
this._prefix = prefix;
|
||||
this.options.prefix = prefix;
|
||||
this._update();
|
||||
},
|
||||
|
||||
addAttribution: function (text) {
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
if (!text) { return; }
|
||||
|
||||
if (!this._attributions[text]) {
|
||||
this._attributions[text] = 0;
|
||||
}
|
||||
this._attributions[text]++;
|
||||
|
||||
this._update();
|
||||
},
|
||||
|
||||
removeAttribution: function (text) {
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
if (!text) { return; }
|
||||
|
||||
this._attributions[text]--;
|
||||
this._update();
|
||||
},
|
||||
|
||||
_update: function () {
|
||||
if (!this._map) {
|
||||
return;
|
||||
}
|
||||
if (!this._map) { return; }
|
||||
|
||||
var attribs = [];
|
||||
|
||||
@ -57,13 +65,36 @@ L.Control.Attribution = L.Control.extend({
|
||||
}
|
||||
|
||||
var prefixAndAttribs = [];
|
||||
if (this._prefix) {
|
||||
prefixAndAttribs.push(this._prefix);
|
||||
|
||||
if (this.options.prefix) {
|
||||
prefixAndAttribs.push(this.options.prefix);
|
||||
}
|
||||
if (attribs.length) {
|
||||
prefixAndAttribs.push(attribs.join(', '));
|
||||
}
|
||||
|
||||
this._container.innerHTML = prefixAndAttribs.join(' — ');
|
||||
},
|
||||
|
||||
_onLayerAdd: function (e) {
|
||||
if (e.layer.getAttribution) {
|
||||
this.addAttribution(e.layer.getAttribution());
|
||||
}
|
||||
},
|
||||
|
||||
_onLayerRemove: function (e) {
|
||||
if (e.layer.getAttribution) {
|
||||
this.removeAttribution(e.layer.getAttribution());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
L.Map.mergeOptions({
|
||||
attributionControl: true
|
||||
});
|
||||
|
||||
L.Map.addInitHook(function () {
|
||||
if (this.options.attributionControl) {
|
||||
this.attributionControl = (new L.Control.Attribution()).addTo(this);
|
||||
}
|
||||
});
|
@ -24,8 +24,6 @@ L.Control.Layers = L.Control.extend({
|
||||
},
|
||||
|
||||
onAdd: function (map) {
|
||||
this._map = map;
|
||||
|
||||
this._initLayout();
|
||||
this._update();
|
||||
|
||||
@ -52,40 +50,47 @@ L.Control.Layers = L.Control.extend({
|
||||
},
|
||||
|
||||
_initLayout: function () {
|
||||
this._container = L.DomUtil.create('div', 'leaflet-control-layers');
|
||||
var className = 'leaflet-control-layers',
|
||||
container = this._container = L.DomUtil.create('div', className);
|
||||
|
||||
if (!L.Browser.touch) {
|
||||
L.DomEvent.disableClickPropagation(this._container);
|
||||
L.DomEvent.disableClickPropagation(container);
|
||||
} else {
|
||||
L.DomEvent.addListener(container, 'click', L.DomEvent.stopPropagation);
|
||||
}
|
||||
|
||||
this._form = L.DomUtil.create('form', 'leaflet-control-layers-list');
|
||||
var form = this._form = L.DomUtil.create('form', className + '-list');
|
||||
|
||||
if (this.options.collapsed) {
|
||||
L.DomEvent.addListener(this._container, 'mouseover', this._expand, this);
|
||||
L.DomEvent.addListener(this._container, 'mouseout', this._collapse, this);
|
||||
L.DomEvent
|
||||
.addListener(container, 'mouseover', this._expand, this)
|
||||
.addListener(container, 'mouseout', this._collapse, this);
|
||||
|
||||
var link = this._layersLink = L.DomUtil.create('a', 'leaflet-control-layers-toggle');
|
||||
var link = this._layersLink = L.DomUtil.create('a', className + '-toggle', container);
|
||||
link.href = '#';
|
||||
link.title = 'Layers';
|
||||
|
||||
if (L.Browser.touch) {
|
||||
L.DomEvent.addListener(link, 'click', this._expand, this);
|
||||
//L.DomEvent.disableClickPropagation(link);
|
||||
} else {
|
||||
L.DomEvent
|
||||
.addListener(link, 'click', L.DomEvent.stopPropagation)
|
||||
.addListener(link, 'click', L.DomEvent.preventDefault)
|
||||
.addListener(link, 'click', this._expand, this);
|
||||
}
|
||||
else {
|
||||
L.DomEvent.addListener(link, 'focus', this._expand, this);
|
||||
}
|
||||
|
||||
this._map.on('movestart', this._collapse, this);
|
||||
// TODO keyboard accessibility
|
||||
|
||||
this._container.appendChild(link);
|
||||
} else {
|
||||
this._expand();
|
||||
}
|
||||
|
||||
this._baseLayersList = L.DomUtil.create('div', 'leaflet-control-layers-base', this._form);
|
||||
this._separator = L.DomUtil.create('div', 'leaflet-control-layers-separator', this._form);
|
||||
this._overlaysList = L.DomUtil.create('div', 'leaflet-control-layers-overlays', this._form);
|
||||
this._baseLayersList = L.DomUtil.create('div', className + '-base', form);
|
||||
this._separator = L.DomUtil.create('div', className + '-separator', form);
|
||||
this._overlaysList = L.DomUtil.create('div', className + '-overlays', form);
|
||||
|
||||
this._container.appendChild(this._form);
|
||||
container.appendChild(form);
|
||||
},
|
||||
|
||||
_addLayer: function (layer, name, overlay) {
|
||||
@ -128,8 +133,8 @@ L.Control.Layers = L.Control.extend({
|
||||
input.name = 'leaflet-base-layers';
|
||||
}
|
||||
input.type = obj.overlay ? 'checkbox' : 'radio';
|
||||
input.checked = this._map.hasLayer(obj.layer);
|
||||
input.layerId = L.Util.stamp(obj.layer);
|
||||
input.defaultChecked = this._map.hasLayer(obj.layer);
|
||||
|
||||
L.DomEvent.addListener(input, 'click', this._onInputClick, this);
|
||||
|
||||
|
94
src/control/Control.Scale.js
Normal file
94
src/control/Control.Scale.js
Normal file
@ -0,0 +1,94 @@
|
||||
L.Control.Scale = L.Control.extend({
|
||||
options: {
|
||||
position: 'bottomleft',
|
||||
maxWidth: 100,
|
||||
metric: true,
|
||||
imperial: true,
|
||||
updateWhenIdle: false
|
||||
},
|
||||
|
||||
onAdd: function (map) {
|
||||
this._map = map;
|
||||
|
||||
var className = 'leaflet-control-scale',
|
||||
container = L.DomUtil.create('div', className),
|
||||
options = this.options;
|
||||
|
||||
if (options.metric) {
|
||||
this._mScale = L.DomUtil.create('div', className + '-line', container);
|
||||
}
|
||||
if (options.imperial) {
|
||||
this._iScale = L.DomUtil.create('div', className + '-line', container);
|
||||
}
|
||||
|
||||
map.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
|
||||
this._update();
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
onRemove: function (map) {
|
||||
map.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
|
||||
},
|
||||
|
||||
_update: function () {
|
||||
var bounds = this._map.getBounds(),
|
||||
centerLat = bounds.getCenter().lat,
|
||||
|
||||
left = new L.LatLng(centerLat, bounds.getSouthWest().lng),
|
||||
right = new L.LatLng(centerLat, bounds.getNorthEast().lng),
|
||||
|
||||
size = this._map.getSize(),
|
||||
options = this.options,
|
||||
|
||||
maxMeters = left.distanceTo(right) * (options.maxWidth / size.x);
|
||||
|
||||
if (options.metric) {
|
||||
this._updateMetric(maxMeters);
|
||||
}
|
||||
|
||||
if (options.imperial) {
|
||||
this._updateImperial(maxMeters);
|
||||
}
|
||||
},
|
||||
|
||||
_updateMetric: function (maxMeters) {
|
||||
var meters = this._getRoundNum(maxMeters);
|
||||
|
||||
this._mScale.style.width = this._getScaleWidth(meters / maxMeters) + 'px';
|
||||
this._mScale.innerHTML = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km';
|
||||
},
|
||||
|
||||
_updateImperial: function (maxMeters) {
|
||||
var maxFeet = maxMeters * 3.2808399,
|
||||
scale = this._iScale,
|
||||
maxMiles, miles, feet;
|
||||
|
||||
if (maxFeet > 5280) {
|
||||
maxMiles = maxFeet / 5280;
|
||||
miles = this._getRoundNum(maxMiles);
|
||||
|
||||
scale.style.width = this._getScaleWidth(miles / maxMiles) + 'px';
|
||||
scale.innerHTML = miles + ' mi';
|
||||
|
||||
} else {
|
||||
feet = this._getRoundNum(maxFeet);
|
||||
|
||||
scale.style.width = this._getScaleWidth(feet / maxFeet) + 'px';
|
||||
scale.innerHTML = feet + ' ft';
|
||||
}
|
||||
},
|
||||
|
||||
_getScaleWidth: function (ratio) {
|
||||
return Math.round(this.options.maxWidth * ratio) - 10;
|
||||
},
|
||||
|
||||
_getRoundNum: function (num) {
|
||||
var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1),
|
||||
d = num / pow10;
|
||||
|
||||
d = d >= 10 ? 10 : d >= 5 ? 5 : d >= 2 ? 2 : 1;
|
||||
|
||||
return pow10 * d;
|
||||
}
|
||||
});
|
@ -1,4 +1,3 @@
|
||||
|
||||
L.Control.Zoom = L.Control.extend({
|
||||
options: {
|
||||
position: 'topleft'
|
||||
@ -6,28 +5,35 @@ L.Control.Zoom = L.Control.extend({
|
||||
|
||||
onAdd: function (map) {
|
||||
var className = 'leaflet-control-zoom',
|
||||
container = L.DomUtil.create('div', className),
|
||||
zoomInButton = this._createButton('Zoom in', className + '-in', map.zoomIn, map),
|
||||
zoomOutButton = this._createButton('Zoom out', className + '-out', map.zoomOut, map);
|
||||
container = L.DomUtil.create('div', className);
|
||||
|
||||
container.appendChild(zoomInButton);
|
||||
container.appendChild(zoomOutButton);
|
||||
this._createButton('Zoom in', className + '-in', container, map.zoomIn, map);
|
||||
this._createButton('Zoom out', className + '-out', container, map.zoomOut, map);
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
_createButton: function (title, className, fn, context) {
|
||||
var link = document.createElement('a');
|
||||
_createButton: function (title, className, container, fn, context) {
|
||||
var link = L.DomUtil.create('a', className, container);
|
||||
link.href = '#';
|
||||
link.title = title;
|
||||
link.className = className;
|
||||
|
||||
if (!L.Browser.touch) {
|
||||
L.DomEvent.disableClickPropagation(link);
|
||||
}
|
||||
L.DomEvent.addListener(link, 'click', L.DomEvent.preventDefault);
|
||||
L.DomEvent.addListener(link, 'click', fn, context);
|
||||
L.DomEvent
|
||||
.addListener(link, 'click', L.DomEvent.stopPropagation)
|
||||
.addListener(link, 'click', L.DomEvent.preventDefault)
|
||||
.addListener(link, 'click', fn, context);
|
||||
|
||||
return link;
|
||||
}
|
||||
});
|
||||
|
||||
L.Map.mergeOptions({
|
||||
zoomControl: true
|
||||
});
|
||||
|
||||
L.Map.addInitHook(function () {
|
||||
if (this.options.zoomControl) {
|
||||
this.zoomControl = new L.Control.Zoom();
|
||||
this.addControl(this.zoomControl);
|
||||
}
|
||||
});
|
@ -13,12 +13,49 @@ L.Control = L.Class.extend({
|
||||
},
|
||||
|
||||
setPosition: function (position) {
|
||||
var map = this._map;
|
||||
|
||||
if (map) {
|
||||
map.removeControl(this);
|
||||
}
|
||||
|
||||
this.options.position = position;
|
||||
|
||||
if (this._map) {
|
||||
this._map.removeControl(this);
|
||||
this._map.addControl(this);
|
||||
if (map) {
|
||||
map.addControl(this);
|
||||
}
|
||||
},
|
||||
|
||||
addTo: function (map) {
|
||||
this._map = map;
|
||||
|
||||
var container = this._container = this.onAdd(map),
|
||||
pos = this.getPosition(),
|
||||
corner = map._controlCorners[pos];
|
||||
|
||||
L.DomUtil.addClass(container, 'leaflet-control');
|
||||
|
||||
if (pos.indexOf('bottom') !== -1) {
|
||||
corner.insertBefore(container, corner.firstChild);
|
||||
} else {
|
||||
corner.appendChild(container);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
removeFrom: function (map) {
|
||||
var pos = this.getPosition(),
|
||||
corner = map._controlCorners[pos];
|
||||
|
||||
corner.removeChild(this._container);
|
||||
this._map = null;
|
||||
|
||||
if (this.onRemove) {
|
||||
this.onRemove(map);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
var ua = navigator.userAgent.toLowerCase(),
|
||||
ie = !!window.ActiveXObject,
|
||||
webkit = ua.indexOf("webkit") !== -1,
|
||||
gecko = ua.indexOf("gecko") !== -1,
|
||||
mobile = typeof orientation !== 'undefined' ? true : false,
|
||||
android = ua.indexOf("android") !== -1,
|
||||
opera = window.opera;
|
||||
@ -13,9 +14,11 @@
|
||||
webkit: webkit,
|
||||
webkit3d: webkit && ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()),
|
||||
|
||||
gecko: ua.indexOf("gecko") !== -1,
|
||||
gecko: gecko,
|
||||
gecko3d: gecko && ('MozPerspective' in document.createElement('div').style),
|
||||
|
||||
opera: opera,
|
||||
opera3d: opera && ('OTransition' in document.createElement('div').style),
|
||||
|
||||
android: android,
|
||||
mobileWebkit: mobile && webkit,
|
||||
@ -50,4 +53,6 @@
|
||||
return touchSupported;
|
||||
}())
|
||||
};
|
||||
L.Browser.any3d = !!L.Browser.webkit3d || !!L.Browser.gecko3d || !!L.Browser.opera3d;
|
||||
|
||||
}());
|
||||
|
@ -16,20 +16,15 @@ L.Class.extend = function (/*Object*/ props) /*-> Class*/ {
|
||||
// instantiate class without calling constructor
|
||||
var F = function () {};
|
||||
F.prototype = this.prototype;
|
||||
|
||||
var proto = new F();
|
||||
|
||||
proto.constructor = NewClass;
|
||||
|
||||
NewClass.prototype = proto;
|
||||
|
||||
// add superclass access
|
||||
NewClass.superclass = this.prototype;
|
||||
|
||||
// add class name
|
||||
//proto.className = props;
|
||||
|
||||
//inherit parent's statics
|
||||
for (var i in this) {
|
||||
if (this.hasOwnProperty(i) && i !== 'prototype' && i !== 'superclass') {
|
||||
if (this.hasOwnProperty(i) && i !== 'prototype') {
|
||||
NewClass[i] = this[i];
|
||||
}
|
||||
}
|
||||
@ -54,13 +49,15 @@ L.Class.extend = function (/*Object*/ props) /*-> Class*/ {
|
||||
// mix given properties into the prototype
|
||||
L.Util.extend(proto, props);
|
||||
|
||||
// allow inheriting further
|
||||
NewClass.extend = L.Class.extend;
|
||||
|
||||
// method for adding properties to prototype
|
||||
NewClass.include = function (props) {
|
||||
L.Util.extend(this.prototype, props);
|
||||
};
|
||||
|
||||
return NewClass;
|
||||
};
|
||||
|
||||
|
||||
// method for adding properties to prototype
|
||||
L.Class.include = function (props) {
|
||||
L.Util.extend(this.prototype, props);
|
||||
};
|
||||
|
||||
L.Class.mergeOptions = function (options) {
|
||||
L.Util.extend(this.prototype.options, options);
|
||||
};
|
@ -16,9 +16,10 @@ L.Util = {
|
||||
return dest;
|
||||
},
|
||||
|
||||
bind: function (/*Function*/ fn, /*Object*/ obj) /*-> Object*/ {
|
||||
bind: function (fn, obj) { // (Function, Object) -> Function
|
||||
var args = arguments.length > 2 ? Array.prototype.slice.call(arguments, 2) : null;
|
||||
return function () {
|
||||
return fn.apply(obj, arguments);
|
||||
return fn.apply(obj, args || arguments);
|
||||
};
|
||||
},
|
||||
|
||||
@ -30,6 +31,9 @@ L.Util = {
|
||||
};
|
||||
}()),
|
||||
|
||||
|
||||
// TODO refactor: remove repetition
|
||||
|
||||
requestAnimFrame: (function () {
|
||||
function timeoutDefer(callback) {
|
||||
window.setTimeout(callback, 1000 / 60);
|
||||
@ -47,29 +51,48 @@ L.Util = {
|
||||
if (immediate && requestFn === timeoutDefer) {
|
||||
callback();
|
||||
} else {
|
||||
requestFn(callback, contextEl);
|
||||
return requestFn.call(window, callback, contextEl);
|
||||
}
|
||||
};
|
||||
}()),
|
||||
|
||||
cancelAnimFrame: (function () {
|
||||
var requestFn = window.cancelAnimationFrame ||
|
||||
window.webkitCancelRequestAnimationFrame ||
|
||||
window.mozCancelRequestAnimationFrame ||
|
||||
window.oCancelRequestAnimationFrame ||
|
||||
window.msCancelRequestAnimationFrame ||
|
||||
clearTimeout;
|
||||
|
||||
return function (handle) {
|
||||
if (!handle) { return; }
|
||||
return requestFn.call(window, handle);
|
||||
};
|
||||
}()),
|
||||
|
||||
limitExecByInterval: function (fn, time, context) {
|
||||
var lock, execOnUnlock, args;
|
||||
function exec() {
|
||||
lock = false;
|
||||
if (execOnUnlock) {
|
||||
args.callee.apply(context, args);
|
||||
execOnUnlock = false;
|
||||
}
|
||||
}
|
||||
return function () {
|
||||
args = arguments;
|
||||
if (!lock) {
|
||||
lock = true;
|
||||
setTimeout(exec, time);
|
||||
fn.apply(context, args);
|
||||
} else {
|
||||
var lock, execOnUnlock;
|
||||
|
||||
return function wrapperFn() {
|
||||
var args = arguments;
|
||||
|
||||
if (lock) {
|
||||
execOnUnlock = true;
|
||||
return;
|
||||
}
|
||||
|
||||
lock = true;
|
||||
|
||||
setTimeout(function () {
|
||||
lock = false;
|
||||
|
||||
if (execOnUnlock) {
|
||||
wrapperFn.apply(context, args);
|
||||
execOnUnlock = false;
|
||||
}
|
||||
}, time);
|
||||
|
||||
fn.apply(context, args);
|
||||
};
|
||||
},
|
||||
|
||||
@ -84,6 +107,7 @@ L.Util = {
|
||||
|
||||
setOptions: function (obj, options) {
|
||||
obj.options = L.Util.extend({}, obj.options, options);
|
||||
return obj.options;
|
||||
},
|
||||
|
||||
getParamString: function (obj) {
|
||||
@ -104,5 +128,7 @@ L.Util = {
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
emptyImageUrl: 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='
|
||||
};
|
||||
|
@ -9,7 +9,7 @@ L.DomEvent = {
|
||||
key = '_leaflet_' + type + id;
|
||||
|
||||
if (obj[key]) {
|
||||
return;
|
||||
return this;
|
||||
}
|
||||
|
||||
var handler = function (e) {
|
||||
@ -40,6 +40,8 @@ L.DomEvent = {
|
||||
}
|
||||
|
||||
obj[key] = handler;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
removeListener: function (/*HTMLElement*/ obj, /*String*/ type, /*Function*/ fn) {
|
||||
@ -66,6 +68,8 @@ L.DomEvent = {
|
||||
obj.detachEvent("on" + type, handler);
|
||||
}
|
||||
obj[key] = null;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_checkMouse: function (el, e) {
|
||||
@ -109,12 +113,14 @@ L.DomEvent = {
|
||||
} else {
|
||||
e.cancelBubble = true;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
disableClickPropagation: function (/*HTMLElement*/ el) {
|
||||
L.DomEvent.addListener(el, L.Draggable.START, L.DomEvent.stopPropagation);
|
||||
L.DomEvent.addListener(el, 'click', L.DomEvent.stopPropagation);
|
||||
L.DomEvent.addListener(el, 'dblclick', L.DomEvent.stopPropagation);
|
||||
return L.DomEvent
|
||||
.addListener(el, L.Draggable.START, L.DomEvent.stopPropagation)
|
||||
.addListener(el, 'click', L.DomEvent.stopPropagation)
|
||||
.addListener(el, 'dblclick', L.DomEvent.stopPropagation);
|
||||
},
|
||||
|
||||
preventDefault: function (/*Event*/ e) {
|
||||
@ -123,11 +129,13 @@ L.DomEvent = {
|
||||
} else {
|
||||
e.returnValue = false;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
stop: function (e) {
|
||||
L.DomEvent.preventDefault(e);
|
||||
L.DomEvent.stopPropagation(e);
|
||||
return L.DomEvent
|
||||
.preventDefault(e)
|
||||
.stopPropagation(e);
|
||||
},
|
||||
|
||||
getMousePosition: function (e, container) {
|
||||
@ -136,6 +144,7 @@ L.DomEvent = {
|
||||
y = e.pageY ? e.pageY : e.clientY +
|
||||
document.body.scrollTop + document.documentElement.scrollTop,
|
||||
pos = new L.Point(x, y);
|
||||
|
||||
return (container ?
|
||||
pos.subtract(L.DomUtil.getViewportOffset(container)) : pos);
|
||||
},
|
||||
|
@ -33,6 +33,12 @@ L.DomUtil = {
|
||||
L.DomUtil.getStyle(el, 'position') === 'absolute') {
|
||||
break;
|
||||
}
|
||||
if (L.DomUtil.getStyle(el, 'position') === 'fixed') {
|
||||
top += docBody.scrollTop || 0;
|
||||
left += docBody.scrollLeft || 0;
|
||||
break;
|
||||
}
|
||||
|
||||
el = el.offsetParent;
|
||||
} while (el);
|
||||
|
||||
@ -98,7 +104,7 @@ L.DomUtil = {
|
||||
|
||||
setOpacity: function (el, value) {
|
||||
if (L.Browser.ie) {
|
||||
el.style.filter = 'alpha(opacity=' + Math.round(value * 100) + ')';
|
||||
el.style.filter += value !== 1 ? 'alpha(opacity=' + Math.round(value * 100) + ')' : '';
|
||||
} else {
|
||||
el.style.opacity = value;
|
||||
}
|
||||
@ -133,13 +139,9 @@ L.DomUtil = {
|
||||
|
||||
setPosition: function (el, point) {
|
||||
el._leaflet_pos = point;
|
||||
if (L.Browser.webkit3d) {
|
||||
if (L.Browser.any3d) {
|
||||
el.style[L.DomUtil.TRANSFORM] = L.DomUtil.getTranslateString(point);
|
||||
|
||||
if (L.Browser.android) {
|
||||
el.style['-webkit-perspective'] = '1000';
|
||||
el.style['-webkit-backface-visibility'] = 'hidden';
|
||||
}
|
||||
el.style[L.DomUtil.BACKFACEVISIBILITY] = 'hidden';
|
||||
} else {
|
||||
el.style.left = point.x + 'px';
|
||||
el.style.top = point.y + 'px';
|
||||
@ -154,6 +156,7 @@ L.DomUtil = {
|
||||
L.Util.extend(L.DomUtil, {
|
||||
TRANSITION: L.DomUtil.testProp(['transition', 'webkitTransition', 'OTransition', 'MozTransition', 'msTransition']),
|
||||
TRANSFORM: L.DomUtil.testProp(['transformProperty', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']),
|
||||
BACKFACEVISIBILITY: L.DomUtil.testProp(['backfaceVisibility', 'WebkitBackfaceVisibility', 'OBackfaceVisibility', 'MozBackfaceVisibility', 'msBackfaceVisibility']),
|
||||
|
||||
TRANSLATE_OPEN: 'translate' + (L.Browser.webkit3d ? '3d(' : '('),
|
||||
TRANSLATE_CLOSE: L.Browser.webkit3d ? ',0)' : ')'
|
||||
|
@ -31,6 +31,7 @@ L.Draggable = L.Class.extend({
|
||||
}
|
||||
L.DomEvent.removeListener(this._dragStartTarget, L.Draggable.START, this._onDown);
|
||||
this._enabled = false;
|
||||
this._moved = false;
|
||||
},
|
||||
|
||||
_onDown: function (e) {
|
||||
@ -38,7 +39,10 @@ L.Draggable = L.Class.extend({
|
||||
return;
|
||||
}
|
||||
|
||||
this._simulateClick = true;
|
||||
|
||||
if (e.touches && e.touches.length > 1) {
|
||||
this._simulateClick = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -86,7 +90,8 @@ L.Draggable = L.Class.extend({
|
||||
var newPoint = new L.Point(first.clientX, first.clientY);
|
||||
this._newPos = this._startPos.add(newPoint).subtract(this._startPoint);
|
||||
|
||||
L.Util.requestAnimFrame(this._updatePosition, this, true, this._dragStartTarget);
|
||||
L.Util.cancelAnimFrame(this._animRequest);
|
||||
this._animRequest = L.Util.requestAnimFrame(this._updatePosition, this, true, this._dragStartTarget);
|
||||
},
|
||||
|
||||
_updatePosition: function () {
|
||||
@ -96,7 +101,7 @@ L.Draggable = L.Class.extend({
|
||||
},
|
||||
|
||||
_onUp: function (e) {
|
||||
if (e.changedTouches) {
|
||||
if (this._simulateClick && e.changedTouches) {
|
||||
var first = e.changedTouches[0],
|
||||
el = first.target,
|
||||
dist = (this._newPos && this._newPos.distanceTo(this._startPos)) || 0;
|
||||
@ -125,12 +130,11 @@ L.Draggable = L.Class.extend({
|
||||
},
|
||||
|
||||
_setMovingCursor: function () {
|
||||
this._bodyCursor = document.body.style.cursor;
|
||||
document.body.style.cursor = 'move';
|
||||
document.body.className += ' leaflet-dragging';
|
||||
},
|
||||
|
||||
_restoreCursor: function () {
|
||||
document.body.style.cursor = this._bodyCursor;
|
||||
document.body.className = document.body.className.replace(/ leaflet-dragging/g, '');
|
||||
},
|
||||
|
||||
_simulateEvent: function (type, e) {
|
||||
|
@ -20,7 +20,7 @@ L.Transition = L.Transition.extend({
|
||||
|
||||
// transition-property value to use with each particular custom property
|
||||
CUSTOM_PROPS_PROPERTIES: {
|
||||
position: L.Browser.webkit ? L.DomUtil.TRANSFORM : 'top, left'
|
||||
position: L.Browser.any3d ? L.DomUtil.TRANSFORM : 'top, left'
|
||||
}
|
||||
};
|
||||
}()),
|
||||
@ -88,15 +88,18 @@ L.Transition = L.Transition.extend({
|
||||
this.fire('step');
|
||||
},
|
||||
|
||||
_onTransitionEnd: function () {
|
||||
_onTransitionEnd: function (e) {
|
||||
if (this._inProgress) {
|
||||
this._inProgress = false;
|
||||
clearInterval(this._timer);
|
||||
|
||||
this._el.style[L.Transition.PROPERTY] = 'none';
|
||||
this._el.style[L.Transition.TRANSITION] = '';
|
||||
|
||||
this.fire('step');
|
||||
this.fire('end');
|
||||
|
||||
if (e && e.type) {
|
||||
this.fire('end');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -13,17 +13,35 @@ L.LatLngBounds = L.Class.extend({
|
||||
}
|
||||
},
|
||||
|
||||
// extend the bounds to contain the given point
|
||||
extend: function (/*LatLng*/ latlng) {
|
||||
if (!this._southWest && !this._northEast) {
|
||||
this._southWest = new L.LatLng(latlng.lat, latlng.lng, true);
|
||||
this._northEast = new L.LatLng(latlng.lat, latlng.lng, true);
|
||||
} else {
|
||||
this._southWest.lat = Math.min(latlng.lat, this._southWest.lat);
|
||||
this._southWest.lng = Math.min(latlng.lng, this._southWest.lng);
|
||||
this._northEast.lat = Math.max(latlng.lat, this._northEast.lat);
|
||||
this._northEast.lng = Math.max(latlng.lng, this._northEast.lng);
|
||||
// extend the bounds to contain the given point or bounds
|
||||
extend: function (/*LatLng or LatLngBounds*/ obj) {
|
||||
if (obj instanceof L.LatLng) {
|
||||
if (!this._southWest && !this._northEast) {
|
||||
this._southWest = new L.LatLng(obj.lat, obj.lng, true);
|
||||
this._northEast = new L.LatLng(obj.lat, obj.lng, true);
|
||||
} else {
|
||||
this._southWest.lat = Math.min(obj.lat, this._southWest.lat);
|
||||
this._southWest.lng = Math.min(obj.lng, this._southWest.lng);
|
||||
this._northEast.lat = Math.max(obj.lat, this._northEast.lat);
|
||||
this._northEast.lng = Math.max(obj.lng, this._northEast.lng);
|
||||
}
|
||||
} else if (obj instanceof L.LatLngBounds) {
|
||||
this.extend(obj._southWest);
|
||||
this.extend(obj._northEast);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// extend the bounds by a percentage
|
||||
pad: function (bufferRatio) { // (Number) -> LatLngBounds
|
||||
var sw = this._southWest,
|
||||
ne = this._northEast,
|
||||
heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio,
|
||||
widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;
|
||||
|
||||
return new L.LatLngBounds(
|
||||
new L.LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer),
|
||||
new L.LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer));
|
||||
},
|
||||
|
||||
getCenter: function () /*-> LatLng*/ {
|
||||
|
@ -3,6 +3,7 @@ L.CRS.EPSG3395 = L.Util.extend({}, L.CRS, {
|
||||
code: 'EPSG:3395',
|
||||
|
||||
projection: L.Projection.Mercator,
|
||||
|
||||
transformation: (function () {
|
||||
var m = L.Projection.Mercator,
|
||||
r = m.R_MAJOR,
|
||||
|
@ -5,7 +5,7 @@ L.CRS.EPSG3857 = L.Util.extend({}, L.CRS, {
|
||||
projection: L.Projection.SphericalMercator,
|
||||
transformation: new L.Transformation(0.5 / Math.PI, 0.5, -0.5 / Math.PI, 0.5),
|
||||
|
||||
project: function (/*LatLng*/ latlng)/*-> Point*/ {
|
||||
project: function (latlng) { // (LatLng) -> Point
|
||||
var projectedPoint = this.projection.project(latlng),
|
||||
earthRadius = 6378137;
|
||||
return projectedPoint.multiplyBy(earthRadius);
|
||||
|
5
src/geo/crs/CRS.Simple.js
Normal file
5
src/geo/crs/CRS.Simple.js
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
L.CRS.Simple = L.Util.extend({}, L.CRS, {
|
||||
projection: L.Projection.LonLat,
|
||||
transformation: new L.Transformation(1, 0, 1, 0)
|
||||
});
|
@ -1,17 +1,25 @@
|
||||
|
||||
L.CRS = {
|
||||
latLngToPoint: function (/*LatLng*/ latlng, /*Number*/ scale)/*-> Point*/ {
|
||||
var projectedPoint = this.projection.project(latlng);
|
||||
latLngToPoint: function (latlng, zoom) { // (LatLng, Number) -> Point
|
||||
var projectedPoint = this.projection.project(latlng),
|
||||
scale = this.scale(zoom);
|
||||
|
||||
return this.transformation._transform(projectedPoint, scale);
|
||||
},
|
||||
|
||||
pointToLatLng: function (/*Point*/ point, /*Number*/ scale, /*(optional) Boolean*/ unbounded)/*-> LatLng*/ {
|
||||
var untransformedPoint = this.transformation.untransform(point, scale);
|
||||
pointToLatLng: function (point, zoom, unbounded) { // (Point, Number[, Boolean]) -> LatLng
|
||||
var scale = this.scale(zoom),
|
||||
untransformedPoint = this.transformation.untransform(point, scale);
|
||||
|
||||
return this.projection.unproject(untransformedPoint, unbounded);
|
||||
//TODO get rid of 'unbounded' everywhere
|
||||
},
|
||||
|
||||
project: function (latlng) {
|
||||
return this.projection.project(latlng);
|
||||
},
|
||||
|
||||
scale: function (zoom) {
|
||||
return 256 * Math.pow(2, zoom);
|
||||
}
|
||||
};
|
||||
|
@ -5,7 +5,7 @@ L.Projection.Mercator = {
|
||||
R_MINOR: 6356752.3142,
|
||||
R_MAJOR: 6378137,
|
||||
|
||||
project: function (/*LatLng*/ latlng) /*-> Point*/ {
|
||||
project: function (latlng) { // (LatLng) -> Point
|
||||
var d = L.LatLng.DEG_TO_RAD,
|
||||
max = this.MAX_LATITUDE,
|
||||
lat = Math.max(Math.min(max, latlng.lat), -max),
|
||||
@ -25,7 +25,7 @@ L.Projection.Mercator = {
|
||||
return new L.Point(x, y);
|
||||
},
|
||||
|
||||
unproject: function (/*Point*/ point, /*Boolean*/ unbounded) /*-> LatLng*/ {
|
||||
unproject: function (point, unbounded) { // (Point, Boolean) -> LatLng
|
||||
var d = L.LatLng.RAD_TO_DEG,
|
||||
r = this.R_MAJOR,
|
||||
r2 = this.R_MINOR,
|
||||
|
@ -2,7 +2,7 @@
|
||||
L.Projection.SphericalMercator = {
|
||||
MAX_LATITUDE: 85.0511287798,
|
||||
|
||||
project: function (/*LatLng*/ latlng) /*-> Point*/ {
|
||||
project: function (latlng) { // (LatLng) -> Point
|
||||
var d = L.LatLng.DEG_TO_RAD,
|
||||
max = this.MAX_LATITUDE,
|
||||
lat = Math.max(Math.min(max, latlng.lat), -max),
|
||||
@ -13,7 +13,7 @@ L.Projection.SphericalMercator = {
|
||||
return new L.Point(x, y);
|
||||
},
|
||||
|
||||
unproject: function (/*Point*/ point, /*Boolean*/ unbounded) /*-> LatLng*/ {
|
||||
unproject: function (point, unbounded) { // (Point, Boolean) -> LatLng
|
||||
var d = L.LatLng.RAD_TO_DEG,
|
||||
lng = point.x * d,
|
||||
lat = (2 * Math.atan(Math.exp(point.y)) - (Math.PI / 2)) * d;
|
||||
|
@ -7,6 +7,7 @@ L.FeatureGroup = L.LayerGroup.extend({
|
||||
|
||||
addLayer: function (layer) {
|
||||
this._initEvents(layer);
|
||||
|
||||
L.LayerGroup.prototype.addLayer.call(this, layer);
|
||||
|
||||
if (this._popupContent && layer.bindPopup) {
|
||||
@ -16,7 +17,6 @@ L.FeatureGroup = L.LayerGroup.extend({
|
||||
|
||||
bindPopup: function (content) {
|
||||
this._popupContent = content;
|
||||
|
||||
return this.invoke('bindPopup', content);
|
||||
},
|
||||
|
||||
@ -24,17 +24,27 @@ L.FeatureGroup = L.LayerGroup.extend({
|
||||
return this.invoke('setStyle', style);
|
||||
},
|
||||
|
||||
_events: ['click', 'dblclick', 'mouseover', 'mouseout'],
|
||||
getBounds: function () {
|
||||
var bounds = new L.LatLngBounds();
|
||||
this._iterateLayers(function (layer) {
|
||||
bounds.extend(layer instanceof L.Marker ? layer.getLatLng() : layer.getBounds());
|
||||
}, this);
|
||||
return bounds;
|
||||
},
|
||||
|
||||
_initEvents: function (layer) {
|
||||
for (var i = 0, len = this._events.length; i < len; i++) {
|
||||
layer.on(this._events[i], this._propagateEvent, this);
|
||||
var events = ['click', 'dblclick', 'mouseover', 'mouseout'],
|
||||
i, len;
|
||||
|
||||
for (i = 0, len = events.length; i < len; i++) {
|
||||
layer.on(events[i], this._propagateEvent, this);
|
||||
}
|
||||
},
|
||||
|
||||
_propagateEvent: function (e) {
|
||||
e.layer = e.target;
|
||||
e.layer = e.target;
|
||||
e.target = this;
|
||||
|
||||
this.fire(e.type, e);
|
||||
}
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
L.GeoJSON = L.FeatureGroup.extend({
|
||||
initialize: function (geojson, options) {
|
||||
L.Util.setOptions(this, options);
|
||||
|
||||
this._geojson = geojson;
|
||||
this._layers = {};
|
||||
|
||||
@ -11,23 +11,27 @@ L.GeoJSON = L.FeatureGroup.extend({
|
||||
},
|
||||
|
||||
addGeoJSON: function (geojson) {
|
||||
if (geojson.features) {
|
||||
for (var i = 0, len = geojson.features.length; i < len; i++) {
|
||||
this.addGeoJSON(geojson.features[i]);
|
||||
var features = geojson.features,
|
||||
i, len;
|
||||
|
||||
if (features) {
|
||||
for (i = 0, len = features.length; i < len; i++) {
|
||||
this.addGeoJSON(features[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var isFeature = (geojson.type === 'Feature'),
|
||||
geometry = (isFeature ? geojson.geometry : geojson),
|
||||
layer = L.GeoJSON.geometryToLayer(geometry, this.options.pointToLayer);
|
||||
geometry = isFeature ? geojson.geometry : geojson,
|
||||
layer = L.GeoJSON.geometryToLayer(geometry, this.options.pointToLayer);
|
||||
|
||||
this.fire('featureparse', {
|
||||
layer: layer,
|
||||
properties: geojson.properties,
|
||||
geometryType: geometry.type,
|
||||
bbox: geojson.bbox,
|
||||
id: geojson.id
|
||||
id: geojson.id,
|
||||
geometry: geojson.geometry
|
||||
});
|
||||
|
||||
this.addLayer(layer);
|
||||
@ -37,10 +41,8 @@ L.GeoJSON = L.FeatureGroup.extend({
|
||||
L.Util.extend(L.GeoJSON, {
|
||||
geometryToLayer: function (geometry, pointToLayer) {
|
||||
var coords = geometry.coordinates,
|
||||
latlng, latlngs,
|
||||
i, len,
|
||||
layer,
|
||||
layers = [];
|
||||
layers = [],
|
||||
latlng, latlngs, i, len, layer;
|
||||
|
||||
switch (geometry.type) {
|
||||
case 'Point':
|
||||
@ -83,22 +85,25 @@ L.Util.extend(L.GeoJSON, {
|
||||
}
|
||||
},
|
||||
|
||||
coordsToLatLng: function (/*Array*/ coords, /*Boolean*/ reverse)/*: LatLng*/ {
|
||||
coordsToLatLng: function (coords, reverse) { // (Array, Boolean) -> LatLng
|
||||
var lat = parseFloat(coords[reverse ? 0 : 1]),
|
||||
lng = parseFloat(coords[reverse ? 1 : 0]);
|
||||
lng = parseFloat(coords[reverse ? 1 : 0]);
|
||||
|
||||
return new L.LatLng(lat, lng, true);
|
||||
},
|
||||
|
||||
coordsToLatLngs: function (/*Array*/ coords, /*Number*/ levelsDeep, /*Boolean*/ reverse)/*: Array*/ {
|
||||
var latlng, latlngs = [],
|
||||
i, len = coords.length;
|
||||
coordsToLatLngs: function (coords, levelsDeep, reverse) { // (Array, Number, Boolean) -> Array
|
||||
var latlng,
|
||||
latlngs = [],
|
||||
i, len;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
for (i = 0, len = coords.length; i < len; i++) {
|
||||
latlng = levelsDeep ?
|
||||
this.coordsToLatLngs(coords[i], levelsDeep - 1, reverse) :
|
||||
this.coordsToLatLng(coords[i], reverse);
|
||||
latlngs.push(latlng);
|
||||
}
|
||||
|
||||
return latlngs;
|
||||
}
|
||||
});
|
||||
|
@ -13,7 +13,7 @@ L.ImageOverlay = L.Class.extend({
|
||||
this._initImage();
|
||||
}
|
||||
|
||||
map.getPanes().overlayPane.appendChild(this._image);
|
||||
map._panes.overlayPane.appendChild(this._image);
|
||||
|
||||
map.on('viewreset', this._reset, this);
|
||||
this._reset();
|
||||
@ -41,14 +41,14 @@ L.ImageOverlay = L.Class.extend({
|
||||
},
|
||||
|
||||
_reset: function () {
|
||||
var topLeft = this._map.latLngToLayerPoint(this._bounds.getNorthWest()),
|
||||
bottomRight = this._map.latLngToLayerPoint(this._bounds.getSouthEast()),
|
||||
size = bottomRight.subtract(topLeft);
|
||||
var image = this._image,
|
||||
topLeft = this._map.latLngToLayerPoint(this._bounds.getNorthWest()),
|
||||
size = this._map.latLngToLayerPoint(this._bounds.getSouthEast()).subtract(topLeft);
|
||||
|
||||
L.DomUtil.setPosition(this._image, topLeft);
|
||||
L.DomUtil.setPosition(image, topLeft);
|
||||
|
||||
this._image.style.width = size.x + 'px';
|
||||
this._image.style.height = size.y + 'px';
|
||||
image.style.width = size.x + 'px';
|
||||
image.style.height = size.y + 'px';
|
||||
},
|
||||
|
||||
_onImageLoad: function () {
|
||||
|
@ -6,8 +6,10 @@ L.LayerGroup = L.Class.extend({
|
||||
initialize: function (layers) {
|
||||
this._layers = {};
|
||||
|
||||
var i, len;
|
||||
|
||||
if (layers) {
|
||||
for (var i = 0, len = layers.length; i < len; i++) {
|
||||
for (i = 0, len = layers.length; i < len; i++) {
|
||||
this.addLayer(layers[i]);
|
||||
}
|
||||
}
|
||||
@ -15,21 +17,25 @@ L.LayerGroup = L.Class.extend({
|
||||
|
||||
addLayer: function (layer) {
|
||||
var id = L.Util.stamp(layer);
|
||||
|
||||
this._layers[id] = layer;
|
||||
|
||||
if (this._map) {
|
||||
this._map.addLayer(layer);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
removeLayer: function (layer) {
|
||||
var id = L.Util.stamp(layer);
|
||||
|
||||
delete this._layers[id];
|
||||
|
||||
if (this._map) {
|
||||
this._map.removeLayer(layer);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
@ -51,6 +57,7 @@ L.LayerGroup = L.Class.extend({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
@ -61,7 +68,7 @@ L.LayerGroup = L.Class.extend({
|
||||
|
||||
onRemove: function (map) {
|
||||
this._iterateLayers(map.removeLayer, map);
|
||||
delete this._map;
|
||||
this._map = null;
|
||||
},
|
||||
|
||||
_iterateLayers: function (method, context) {
|
||||
|
@ -1,10 +1,15 @@
|
||||
|
||||
L.Map.mergeOptions({
|
||||
closePopupOnClick: true
|
||||
});
|
||||
|
||||
L.Popup = L.Class.extend({
|
||||
includes: L.Mixin.Events,
|
||||
|
||||
options: {
|
||||
minWidth: 50,
|
||||
maxWidth: 300,
|
||||
maxHeight: null,
|
||||
autoPan: true,
|
||||
closeButton: true,
|
||||
offset: new L.Point(0, 2),
|
||||
@ -20,79 +25,93 @@ L.Popup = L.Class.extend({
|
||||
|
||||
onAdd: function (map) {
|
||||
this._map = map;
|
||||
|
||||
if (!this._container) {
|
||||
this._initLayout();
|
||||
}
|
||||
this._updateContent();
|
||||
|
||||
this._container.style.opacity = '0';
|
||||
map._panes.popupPane.appendChild(this._container);
|
||||
|
||||
this._map._panes.popupPane.appendChild(this._container);
|
||||
this._map.on('viewreset', this._updatePosition, this);
|
||||
map.on('viewreset', this._updatePosition, this);
|
||||
|
||||
if (this._map.options.closePopupOnClick) {
|
||||
this._map.on('preclick', this._close, this);
|
||||
if (L.Browser.any3d) {
|
||||
map.on('zoomanim', this._zoomAnimation, this);
|
||||
}
|
||||
|
||||
if (map.options.closePopupOnClick) {
|
||||
map.on('preclick', this._close, this);
|
||||
}
|
||||
|
||||
this._update();
|
||||
|
||||
this._container.style.opacity = '1'; //TODO fix ugly opacity hack
|
||||
|
||||
this._opened = true;
|
||||
},
|
||||
|
||||
onRemove: function (map) {
|
||||
map._panes.popupPane.removeChild(this._container);
|
||||
|
||||
L.Util.falseFn(this._container.offsetWidth);
|
||||
|
||||
map.off('viewreset', this._updatePosition, this);
|
||||
map.off('click', this._close, this);
|
||||
map.off('viewreset', this._updatePosition, this)
|
||||
.off('preclick', this._close, this)
|
||||
.off('zoomanim', this._zoomAnimation, this);
|
||||
|
||||
this._container.style.opacity = '0';
|
||||
|
||||
this._opened = false;
|
||||
this._map = null;
|
||||
},
|
||||
|
||||
setLatLng: function (latlng) {
|
||||
this._latlng = latlng;
|
||||
if (this._opened) {
|
||||
this._update();
|
||||
}
|
||||
this._update();
|
||||
return this;
|
||||
},
|
||||
|
||||
setContent: function (content) {
|
||||
this._content = content;
|
||||
if (this._opened) {
|
||||
this._update();
|
||||
}
|
||||
this._update();
|
||||
return this;
|
||||
},
|
||||
|
||||
_close: function () {
|
||||
if (this._opened) {
|
||||
this._map.closePopup();
|
||||
var map = this._map;
|
||||
|
||||
if (map) {
|
||||
map._popup = null;
|
||||
|
||||
map
|
||||
.removeLayer(this)
|
||||
.fire('popupclose', {popup: this});
|
||||
}
|
||||
},
|
||||
|
||||
_initLayout: function () {
|
||||
this._container = L.DomUtil.create('div', 'leaflet-popup ' + this.options.className);
|
||||
var prefix = 'leaflet-popup',
|
||||
container = this._container = L.DomUtil.create('div', prefix + ' ' + this.options.className + ' leaflet-zoom-animated'),
|
||||
closeButton;
|
||||
|
||||
if (this.options.closeButton) {
|
||||
this._closeButton = L.DomUtil.create('a', 'leaflet-popup-close-button', this._container);
|
||||
this._closeButton.href = '#close';
|
||||
L.DomEvent.addListener(this._closeButton, 'click', this._onCloseButtonClick, this);
|
||||
closeButton = this._closeButton = L.DomUtil.create('a', prefix + '-close-button', container);
|
||||
closeButton.href = '#close';
|
||||
|
||||
L.DomEvent.addListener(closeButton, 'click', this._onCloseButtonClick, this);
|
||||
}
|
||||
|
||||
this._wrapper = L.DomUtil.create('div', 'leaflet-popup-content-wrapper', this._container);
|
||||
L.DomEvent.disableClickPropagation(this._wrapper);
|
||||
this._contentNode = L.DomUtil.create('div', 'leaflet-popup-content', this._wrapper);
|
||||
var wrapper = this._wrapper = L.DomUtil.create('div', prefix + '-content-wrapper', container);
|
||||
L.DomEvent.disableClickPropagation(wrapper);
|
||||
|
||||
this._tipContainer = L.DomUtil.create('div', 'leaflet-popup-tip-container', this._container);
|
||||
this._tip = L.DomUtil.create('div', 'leaflet-popup-tip', this._tipContainer);
|
||||
this._contentNode = L.DomUtil.create('div', prefix + '-content', wrapper);
|
||||
L.DomEvent.addListener(this._contentNode, 'mousewheel', L.DomEvent.stopPropagation);
|
||||
|
||||
this._tipContainer = L.DomUtil.create('div', prefix + '-tip-container', container);
|
||||
this._tip = L.DomUtil.create('div', prefix + '-tip', this._tipContainer);
|
||||
},
|
||||
|
||||
_update: function () {
|
||||
if (!this._map) { return; }
|
||||
|
||||
this._container.style.visibility = 'hidden';
|
||||
|
||||
this._updateContent();
|
||||
@ -105,60 +124,85 @@ L.Popup = L.Class.extend({
|
||||
},
|
||||
|
||||
_updateContent: function () {
|
||||
if (!this._content) {
|
||||
return;
|
||||
}
|
||||
if (!this._content) { return; }
|
||||
|
||||
if (typeof this._content === 'string') {
|
||||
this._contentNode.innerHTML = this._content;
|
||||
} else {
|
||||
this._contentNode.innerHTML = '';
|
||||
while (this._contentNode.hasChildNodes()) {
|
||||
this._contentNode.removeChild(this._contentNode.firstChild);
|
||||
}
|
||||
this._contentNode.appendChild(this._content);
|
||||
}
|
||||
this.fire('contentupdate');
|
||||
},
|
||||
|
||||
_updateLayout: function () {
|
||||
this._container.style.width = '';
|
||||
this._container.style.whiteSpace = 'nowrap';
|
||||
var container = this._contentNode;
|
||||
|
||||
var width = this._container.offsetWidth;
|
||||
container.style.width = '';
|
||||
container.style.whiteSpace = 'nowrap';
|
||||
|
||||
this._container.style.width = (width > this.options.maxWidth ?
|
||||
this.options.maxWidth : (width < this.options.minWidth ? this.options.minWidth : width)) + 'px';
|
||||
this._container.style.whiteSpace = '';
|
||||
var width = container.offsetWidth;
|
||||
width = Math.min(width, this.options.maxWidth);
|
||||
width = Math.max(width, this.options.minWidth);
|
||||
|
||||
container.style.width = (width + 1) + 'px';
|
||||
container.style.whiteSpace = '';
|
||||
|
||||
container.style.height = '';
|
||||
|
||||
var height = container.offsetHeight,
|
||||
maxHeight = this.options.maxHeight,
|
||||
scrolledClass = ' leaflet-popup-scrolled';
|
||||
|
||||
if (maxHeight && height > maxHeight) {
|
||||
container.style.height = maxHeight + 'px';
|
||||
container.className += scrolledClass;
|
||||
} else {
|
||||
container.className = container.className.replace(scrolledClass, '');
|
||||
}
|
||||
|
||||
this._containerWidth = this._container.offsetWidth;
|
||||
this._containerBottom = -this.options.offset.y;
|
||||
this._containerLeft = -Math.round(this._containerWidth / 2) + this.options.offset.x;
|
||||
},
|
||||
|
||||
_updatePosition: function () {
|
||||
var pos = this._map.latLngToLayerPoint(this._latlng);
|
||||
|
||||
this._containerBottom = -pos.y - this.options.offset.y;
|
||||
this._containerLeft = pos.x - Math.round(this._containerWidth / 2) + this.options.offset.x;
|
||||
|
||||
this._container.style.bottom = this._containerBottom + 'px';
|
||||
this._container.style.left = this._containerLeft + 'px';
|
||||
|
||||
L.DomUtil.setPosition(this._container, pos);
|
||||
},
|
||||
|
||||
_zoomAnimation: function (opt) {
|
||||
var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center)._round();
|
||||
|
||||
L.DomUtil.setPosition(this._container, pos);
|
||||
},
|
||||
|
||||
_adjustPan: function () {
|
||||
if (!this.options.autoPan) {
|
||||
return;
|
||||
}
|
||||
if (!this.options.autoPan) { return; }
|
||||
|
||||
var containerHeight = this._container.offsetHeight,
|
||||
layerPos = new L.Point(
|
||||
this._containerLeft,
|
||||
-containerHeight - this._containerBottom),
|
||||
containerPos = this._map.layerPointToContainerPoint(layerPos),
|
||||
var map = this._map,
|
||||
containerHeight = this._container.offsetHeight,
|
||||
containerWidth = this._containerWidth,
|
||||
|
||||
layerPos = L.DomUtil.getPosition(this._container).add(
|
||||
new L.Point(this._containerLeft, -containerHeight - this._containerBottom)),
|
||||
|
||||
containerPos = map.layerPointToContainerPoint(layerPos),
|
||||
adjustOffset = new L.Point(0, 0),
|
||||
padding = this.options.autoPanPadding,
|
||||
size = this._map.getSize();
|
||||
padding = this.options.autoPanPadding,
|
||||
size = map.getSize();
|
||||
|
||||
if (containerPos.x < 0) {
|
||||
adjustOffset.x = containerPos.x - padding.x;
|
||||
}
|
||||
if (containerPos.x + this._containerWidth > size.x) {
|
||||
adjustOffset.x = containerPos.x + this._containerWidth - size.x + padding.x;
|
||||
if (containerPos.x + containerWidth > size.x) {
|
||||
adjustOffset.x = containerPos.x + containerWidth - size.x + padding.x;
|
||||
}
|
||||
if (containerPos.y < 0) {
|
||||
adjustOffset.y = containerPos.y - padding.y;
|
||||
@ -168,7 +212,7 @@ L.Popup = L.Class.extend({
|
||||
}
|
||||
|
||||
if (adjustOffset.x || adjustOffset.y) {
|
||||
this._map.panBy(adjustOffset);
|
||||
map.panBy(adjustOffset);
|
||||
}
|
||||
},
|
||||
|
||||
|
20
src/layer/marker/DivIcon.js
Normal file
20
src/layer/marker/DivIcon.js
Normal file
@ -0,0 +1,20 @@
|
||||
L.DivIcon = L.Icon.extend({
|
||||
options: {
|
||||
iconSize: new L.Point(12, 12), // also can be set through CSS
|
||||
/*
|
||||
iconAnchor: (Point)
|
||||
popupAnchor: (Point)
|
||||
*/
|
||||
className: 'leaflet-div-icon'
|
||||
},
|
||||
|
||||
createIcon: function () {
|
||||
var div = document.createElement('div');
|
||||
this._setIconStyles(div, 'icon');
|
||||
return div;
|
||||
},
|
||||
|
||||
createShadow: function () {
|
||||
return null;
|
||||
}
|
||||
});
|
@ -1,17 +1,18 @@
|
||||
L.Icon = L.Class.extend({
|
||||
iconUrl: L.ROOT_URL + 'images/marker.png',
|
||||
shadowUrl: L.ROOT_URL + 'images/marker-shadow.png',
|
||||
options: {
|
||||
/*
|
||||
iconUrl: (String) (required)
|
||||
iconSize: (Point) (can be set through CSS)
|
||||
iconAnchor: (Point) (centered by default if size is specified, can be set in CSS with negative margins)
|
||||
popupAnchor: (Point) (if not specified, popup opens in the anchor point)
|
||||
shadowUrl: (Point) (no shadow by default)
|
||||
shadowSize: (Point)
|
||||
*/
|
||||
className: ''
|
||||
},
|
||||
|
||||
iconSize: new L.Point(25, 41),
|
||||
shadowSize: new L.Point(41, 41),
|
||||
|
||||
iconAnchor: new L.Point(13, 41),
|
||||
popupAnchor: new L.Point(0, -33),
|
||||
|
||||
initialize: function (iconUrl) {
|
||||
if (iconUrl) {
|
||||
this.iconUrl = iconUrl;
|
||||
}
|
||||
initialize: function (options) {
|
||||
L.Util.setOptions(this, options);
|
||||
},
|
||||
|
||||
createIcon: function () {
|
||||
@ -23,35 +24,45 @@ L.Icon = L.Class.extend({
|
||||
},
|
||||
|
||||
_createIcon: function (name) {
|
||||
var size = this[name + 'Size'],
|
||||
src = this[name + 'Url'];
|
||||
if (!src && name === 'shadow') {
|
||||
return null;
|
||||
}
|
||||
var src = this._getIconUrl(name);
|
||||
|
||||
var img;
|
||||
if (!src) {
|
||||
img = this._createDiv();
|
||||
}
|
||||
else {
|
||||
img = this._createImg(src);
|
||||
}
|
||||
|
||||
img.className = 'leaflet-marker-' + name;
|
||||
|
||||
img.style.marginLeft = (-this.iconAnchor.x) + 'px';
|
||||
img.style.marginTop = (-this.iconAnchor.y) + 'px';
|
||||
|
||||
if (size) {
|
||||
img.style.width = size.x + 'px';
|
||||
img.style.height = size.y + 'px';
|
||||
}
|
||||
if (!src) { return null; }
|
||||
|
||||
var img = this._createImg(src);
|
||||
this._setIconStyles(img, name);
|
||||
|
||||
return img;
|
||||
},
|
||||
|
||||
_setIconStyles: function (img, name) {
|
||||
var options = this.options,
|
||||
size = options[name + 'Size'],
|
||||
anchor = options.iconAnchor;
|
||||
|
||||
if (!anchor && size) {
|
||||
anchor = size.divideBy(2, true);
|
||||
}
|
||||
|
||||
if (name === 'shadow' && anchor && options.shadowOffset) {
|
||||
anchor._add(options.shadowOffset);
|
||||
}
|
||||
|
||||
img.className = 'leaflet-marker-' + name + ' ' + options.className + ' leaflet-zoom-animated';
|
||||
|
||||
if (anchor) {
|
||||
img.style.marginLeft = (-anchor.x) + 'px';
|
||||
img.style.marginTop = (-anchor.y) + 'px';
|
||||
}
|
||||
|
||||
if (size) {
|
||||
img.style.width = size.x + 'px';
|
||||
img.style.height = size.y + 'px';
|
||||
}
|
||||
},
|
||||
|
||||
_createImg: function (src) {
|
||||
var el;
|
||||
|
||||
if (!L.Browser.ie6) {
|
||||
el = document.createElement('img');
|
||||
el.src = src;
|
||||
@ -62,7 +73,45 @@ L.Icon = L.Class.extend({
|
||||
return el;
|
||||
},
|
||||
|
||||
_createDiv: function () {
|
||||
return document.createElement('div');
|
||||
_getIconUrl: function (name) {
|
||||
return this.options[name + 'Url'];
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// TODO move to a separate file
|
||||
|
||||
L.Icon.Default = L.Icon.extend({
|
||||
options: {
|
||||
iconSize: new L.Point(25, 41),
|
||||
iconAnchor: new L.Point(13, 41),
|
||||
popupAnchor: new L.Point(0, -33),
|
||||
|
||||
shadowSize: new L.Point(41, 41)
|
||||
},
|
||||
|
||||
_getIconUrl: function (name) {
|
||||
var path = L.Icon.Default.imagePath;
|
||||
if (!path) {
|
||||
throw new Error("Couldn't autodetect L.Icon.Default.imagePath, set it manually.");
|
||||
}
|
||||
|
||||
return path + '/marker-' + name + '.png';
|
||||
}
|
||||
});
|
||||
|
||||
L.Icon.Default.imagePath = (function () {
|
||||
var scripts = document.getElementsByTagName('script'),
|
||||
leafletRe = /\/?leaflet[\-\._]?([\w\-\._]*)\.js\??/;
|
||||
|
||||
var i, len, src, matches;
|
||||
|
||||
for (i = 0, len = scripts.length; i < len; i++) {
|
||||
src = scripts[i].src;
|
||||
matches = src.match(leafletRe);
|
||||
|
||||
if (matches) {
|
||||
return src.split(leafletRe)[0] + '/images';
|
||||
}
|
||||
}
|
||||
}());
|
@ -10,9 +10,7 @@ L.Handler.MarkerDrag = L.Handler.extend({
|
||||
addHooks: function () {
|
||||
var icon = this._marker._icon;
|
||||
if (!this._draggable) {
|
||||
this._draggable = new L.Draggable(icon, icon);
|
||||
|
||||
this._draggable
|
||||
this._draggable = new L.Draggable(icon, icon)
|
||||
.on('dragstart', this._onDragStart, this)
|
||||
.on('drag', this._onDrag, this)
|
||||
.on('dragend', this._onDragEnd, this);
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
L.Marker.include({
|
||||
openPopup: function () {
|
||||
this._popup.setLatLng(this._latlng);
|
||||
if (this._map) {
|
||||
if (this._popup && this._map) {
|
||||
this._popup.setLatLng(this._latlng);
|
||||
this._map.openPopup(this._popup);
|
||||
}
|
||||
|
||||
@ -20,14 +20,20 @@ L.Marker.include({
|
||||
},
|
||||
|
||||
bindPopup: function (content, options) {
|
||||
options = L.Util.extend({offset: this.options.icon.popupAnchor}, options);
|
||||
var anchor = this.options.icon.options.popupAnchor || new L.Point(0, 0);
|
||||
|
||||
if (options && options.offset) {
|
||||
anchor = anchor.add(options.offset);
|
||||
}
|
||||
|
||||
options = L.Util.extend({offset: anchor}, options);
|
||||
|
||||
if (!this._popup) {
|
||||
this.on('click', this.openPopup, this);
|
||||
}
|
||||
|
||||
this._popup = new L.Popup(options, this);
|
||||
this._popup.setContent(content);
|
||||
this._popup = new L.Popup(options, this)
|
||||
.setContent(content);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
@ -7,11 +7,12 @@ L.Marker = L.Class.extend({
|
||||
includes: L.Mixin.Events,
|
||||
|
||||
options: {
|
||||
icon: new L.Icon(),
|
||||
icon: new L.Icon.Default(),
|
||||
title: '',
|
||||
clickable: true,
|
||||
draggable: false,
|
||||
zIndexOffset: 0
|
||||
zIndexOffset: 0,
|
||||
opacity: 1
|
||||
},
|
||||
|
||||
initialize: function (latlng, options) {
|
||||
@ -22,9 +23,13 @@ L.Marker = L.Class.extend({
|
||||
onAdd: function (map) {
|
||||
this._map = map;
|
||||
|
||||
this._initIcon();
|
||||
|
||||
map.on('viewreset', this._reset, this);
|
||||
|
||||
if (map.options.zoomAnimation && map.options.animateMarkerZoom) {
|
||||
map.on('zoomanim', this._zoomAnimation, this);
|
||||
}
|
||||
|
||||
this._initIcon();
|
||||
this._reset();
|
||||
},
|
||||
|
||||
@ -36,9 +41,10 @@ L.Marker = L.Class.extend({
|
||||
this.closePopup();
|
||||
}
|
||||
|
||||
this._map = null;
|
||||
map.off('viewreset', this._reset, this)
|
||||
.off('zoomanim', this._zoomAnimation, this);
|
||||
|
||||
map.off('viewreset', this._reset, this);
|
||||
this._map = null;
|
||||
},
|
||||
|
||||
getLatLng: function () {
|
||||
@ -47,20 +53,17 @@ L.Marker = L.Class.extend({
|
||||
|
||||
setLatLng: function (latlng) {
|
||||
this._latlng = latlng;
|
||||
if (this._icon) {
|
||||
this._reset();
|
||||
|
||||
if (this._popup) {
|
||||
this._popup.setLatLng(this._latlng);
|
||||
}
|
||||
this._reset();
|
||||
|
||||
if (this._popup) {
|
||||
this._popup.setLatLng(latlng);
|
||||
}
|
||||
},
|
||||
|
||||
setZIndexOffset: function (offset) {
|
||||
this.options.zIndexOffset = offset;
|
||||
if (this._icon) {
|
||||
this._reset();
|
||||
}
|
||||
this._reset();
|
||||
},
|
||||
|
||||
setIcon: function (icon) {
|
||||
@ -77,37 +80,53 @@ L.Marker = L.Class.extend({
|
||||
},
|
||||
|
||||
_initIcon: function () {
|
||||
if (!this._icon) {
|
||||
this._icon = this.options.icon.createIcon();
|
||||
var options = this.options;
|
||||
|
||||
if (this.options.title) {
|
||||
this._icon.title = this.options.title;
|
||||
if (!this._icon) {
|
||||
this._icon = options.icon.createIcon();
|
||||
|
||||
if (options.title) {
|
||||
this._icon.title = options.title;
|
||||
}
|
||||
|
||||
this._initInteraction();
|
||||
this._updateOpacity();
|
||||
}
|
||||
if (!this._shadow) {
|
||||
this._shadow = this.options.icon.createShadow();
|
||||
this._shadow = options.icon.createShadow();
|
||||
}
|
||||
|
||||
this._map._panes.markerPane.appendChild(this._icon);
|
||||
var panes = this._map._panes;
|
||||
|
||||
panes.markerPane.appendChild(this._icon);
|
||||
|
||||
if (this._shadow) {
|
||||
this._map._panes.shadowPane.appendChild(this._shadow);
|
||||
panes.shadowPane.appendChild(this._shadow);
|
||||
}
|
||||
},
|
||||
|
||||
_removeIcon: function () {
|
||||
this._map._panes.markerPane.removeChild(this._icon);
|
||||
var panes = this._map._panes;
|
||||
|
||||
panes.markerPane.removeChild(this._icon);
|
||||
|
||||
if (this._shadow) {
|
||||
this._map._panes.shadowPane.removeChild(this._shadow);
|
||||
panes.shadowPane.removeChild(this._shadow);
|
||||
}
|
||||
|
||||
this._icon = this._shadow = null;
|
||||
},
|
||||
|
||||
_reset: function () {
|
||||
var pos = this._map.latLngToLayerPoint(this._latlng).round();
|
||||
if (!this._icon) { return; }
|
||||
|
||||
var pos = this._map.latLngToLayerPoint(this._latlng).round();
|
||||
this._setPos(pos);
|
||||
},
|
||||
|
||||
_setPos: function (pos) {
|
||||
L.DomUtil.setPosition(this._icon, pos);
|
||||
|
||||
if (this._shadow) {
|
||||
L.DomUtil.setPosition(this._shadow, pos);
|
||||
}
|
||||
@ -115,16 +134,25 @@ L.Marker = L.Class.extend({
|
||||
this._icon.style.zIndex = pos.y + this.options.zIndexOffset;
|
||||
},
|
||||
|
||||
_zoomAnimation: function (opt) {
|
||||
var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center);
|
||||
|
||||
this._setPos(pos);
|
||||
},
|
||||
|
||||
_initInteraction: function () {
|
||||
if (this.options.clickable) {
|
||||
this._icon.className += ' leaflet-clickable';
|
||||
if (!this.options.clickable) {
|
||||
return;
|
||||
}
|
||||
|
||||
L.DomEvent.addListener(this._icon, 'click', this._onMouseClick, this);
|
||||
var icon = this._icon,
|
||||
events = ['dblclick', 'mousedown', 'mouseover', 'mouseout'];
|
||||
|
||||
var events = ['dblclick', 'mousedown', 'mouseover', 'mouseout'];
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
L.DomEvent.addListener(this._icon, events[i], this._fireMouseEvent, this);
|
||||
}
|
||||
icon.className += ' leaflet-clickable';
|
||||
L.DomEvent.addListener(icon, 'click', this._onMouseClick, this);
|
||||
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
L.DomEvent.addListener(icon, events[i], this._fireMouseEvent, this);
|
||||
}
|
||||
|
||||
if (L.Handler.MarkerDrag) {
|
||||
@ -139,11 +167,29 @@ L.Marker = L.Class.extend({
|
||||
_onMouseClick: function (e) {
|
||||
L.DomEvent.stopPropagation(e);
|
||||
if (this.dragging && this.dragging.moved()) { return; }
|
||||
this.fire(e.type);
|
||||
if (this._map.dragging && this._map.dragging.moved()) { return; }
|
||||
this.fire(e.type, {
|
||||
originalEvent: e
|
||||
});
|
||||
},
|
||||
|
||||
_fireMouseEvent: function (e) {
|
||||
this.fire(e.type);
|
||||
L.DomEvent.stopPropagation(e);
|
||||
this.fire(e.type, {
|
||||
originalEvent: e
|
||||
});
|
||||
if (e.type !== 'mousedown') {
|
||||
L.DomEvent.stopPropagation(e);
|
||||
}
|
||||
},
|
||||
|
||||
setOpacity: function (opacity) {
|
||||
this.options.opacity = opacity;
|
||||
if (this._map) {
|
||||
this._updateOpacity();
|
||||
}
|
||||
},
|
||||
|
||||
_updateOpacity: function (opacity) {
|
||||
L.DomUtil.setOpacity(this._icon, this.options.opacity);
|
||||
}
|
||||
});
|
||||
|
@ -8,9 +8,13 @@ L.TileLayer.Canvas = L.TileLayer.extend({
|
||||
},
|
||||
|
||||
redraw: function () {
|
||||
for (var i in this._tiles) {
|
||||
var tile = this._tiles[i];
|
||||
this._redrawTile(tile);
|
||||
var i,
|
||||
tiles = this._tiles;
|
||||
|
||||
for (i in tiles) {
|
||||
if (tiles.hasOwnProperty(i)) {
|
||||
this._redrawTile(tiles[i]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -19,11 +23,11 @@ L.TileLayer.Canvas = L.TileLayer.extend({
|
||||
},
|
||||
|
||||
_createTileProto: function () {
|
||||
this._canvasProto = L.DomUtil.create('canvas', 'leaflet-tile');
|
||||
var proto = this._canvasProto = L.DomUtil.create('canvas', 'leaflet-tile');
|
||||
|
||||
var tileSize = this.options.tileSize;
|
||||
this._canvasProto.width = tileSize;
|
||||
this._canvasProto.height = tileSize;
|
||||
proto.width = tileSize;
|
||||
proto.height = tileSize;
|
||||
},
|
||||
|
||||
_createTile: function () {
|
||||
|
@ -9,37 +9,46 @@ L.TileLayer.WMS = L.TileLayer.extend({
|
||||
transparent: false
|
||||
},
|
||||
|
||||
initialize: function (/*String*/ url, /*Object*/ options) {
|
||||
initialize: function (url, options) { // (String, Object)
|
||||
this._url = url;
|
||||
|
||||
this.wmsParams = L.Util.extend({}, this.defaultWmsParams);
|
||||
this.wmsParams.width = this.wmsParams.height = this.options.tileSize;
|
||||
var wmsParams = L.Util.extend({}, this.defaultWmsParams);
|
||||
wmsParams.width = wmsParams.height = this.options.tileSize;
|
||||
|
||||
for (var i in options) {
|
||||
// all keys that are not TileLayer options go to WMS params
|
||||
if (!this.options.hasOwnProperty(i)) {
|
||||
this.wmsParams[i] = options[i];
|
||||
wmsParams[i] = options[i];
|
||||
}
|
||||
}
|
||||
|
||||
this.wmsParams = wmsParams;
|
||||
|
||||
L.Util.setOptions(this, options);
|
||||
},
|
||||
|
||||
onAdd: function (map, insertAtTheBottom) {
|
||||
var projectionKey = (parseFloat(this.wmsParams.version) >= 1.3 ? 'crs' : 'srs');
|
||||
var projectionKey = parseFloat(this.wmsParams.version) >= 1.3 ? 'crs' : 'srs';
|
||||
this.wmsParams[projectionKey] = map.options.crs.code;
|
||||
|
||||
L.TileLayer.prototype.onAdd.call(this, map, insertAtTheBottom);
|
||||
},
|
||||
|
||||
getTileUrl: function (/*Point*/ tilePoint, /*Number*/ zoom)/*-> String*/ {
|
||||
var tileSize = this.options.tileSize,
|
||||
getTileUrl: function (tilePoint, zoom) { // (Point, Number) -> String
|
||||
var map = this._map,
|
||||
crs = map.options.crs,
|
||||
|
||||
tileSize = this.options.tileSize,
|
||||
|
||||
nwPoint = tilePoint.multiplyBy(tileSize),
|
||||
sePoint = nwPoint.add(new L.Point(tileSize, tileSize)),
|
||||
nwMap = this._map.unproject(nwPoint, this._zoom, true),
|
||||
seMap = this._map.unproject(sePoint, this._zoom, true),
|
||||
nw = this._map.options.crs.project(nwMap),
|
||||
se = this._map.options.crs.project(seMap),
|
||||
|
||||
nwMap = map.unproject(nwPoint, zoom, true),
|
||||
seMap = map.unproject(sePoint, zoom, true),
|
||||
|
||||
nw = crs.project(nwMap),
|
||||
se = crs.project(seMap),
|
||||
|
||||
bbox = [nw.x, se.y, se.x, nw.y].join(',');
|
||||
|
||||
return this._url + L.Util.getParamString(this.wmsParams) + "&bbox=" + bbox;
|
||||
|
@ -18,20 +18,34 @@ L.TileLayer = L.Class.extend({
|
||||
noWrap: false,
|
||||
zoomOffset: 0,
|
||||
zoomReverse: false,
|
||||
detectRetina: false,
|
||||
|
||||
unloadInvisibleTiles: L.Browser.mobile,
|
||||
updateWhenIdle: L.Browser.mobile,
|
||||
reuseTiles: false
|
||||
},
|
||||
|
||||
initialize: function (url, options, urlParams) {
|
||||
L.Util.setOptions(this, options);
|
||||
initialize: function (url, options) {
|
||||
options = L.Util.setOptions(this, options);
|
||||
|
||||
// detecting retina displays, adjusting tileSize and zoom levels
|
||||
if (options.detectRetina && window.devicePixelRatio > 1 && options.maxZoom > 0) {
|
||||
|
||||
options.tileSize = Math.floor(options.tileSize / 2);
|
||||
options.zoomOffset++;
|
||||
|
||||
if (options.minZoom > 0) {
|
||||
options.minZoom--;
|
||||
}
|
||||
this.options.maxZoom--;
|
||||
}
|
||||
|
||||
this._url = url;
|
||||
this._urlParams = urlParams;
|
||||
|
||||
if (typeof this.options.subdomains === 'string') {
|
||||
this.options.subdomains = this.options.subdomains.split('');
|
||||
var subdomains = this.options.subdomains;
|
||||
|
||||
if (typeof subdomains === 'string') {
|
||||
this.options.subdomains = subdomains.split('');
|
||||
}
|
||||
},
|
||||
|
||||
@ -47,10 +61,9 @@ L.TileLayer = L.Class.extend({
|
||||
|
||||
// set up events
|
||||
map.on('viewreset', this._resetCallback, this);
|
||||
map.on('moveend', this._update, this);
|
||||
|
||||
if (this.options.updateWhenIdle) {
|
||||
map.on('moveend', this._update, this);
|
||||
} else {
|
||||
if (!this.options.updateWhenIdle) {
|
||||
this._limitedUpdate = L.Util.limitExecByInterval(this._update, 150, this);
|
||||
map.on('move', this._limitedUpdate, this);
|
||||
}
|
||||
@ -60,16 +73,17 @@ L.TileLayer = L.Class.extend({
|
||||
},
|
||||
|
||||
onRemove: function (map) {
|
||||
this._map.getPanes().tilePane.removeChild(this._container);
|
||||
this._container = null;
|
||||
map._panes.tilePane.removeChild(this._container);
|
||||
|
||||
this._map.off('viewreset', this._resetCallback, this);
|
||||
map.off('viewreset', this._resetCallback, this);
|
||||
map.off('moveend', this._update, this);
|
||||
|
||||
if (this.options.updateWhenIdle) {
|
||||
this._map.off('moveend', this._update, this);
|
||||
} else {
|
||||
this._map.off('move', this._limitedUpdate, this);
|
||||
if (!this.options.updateWhenIdle) {
|
||||
map.off('move', this._limitedUpdate, this);
|
||||
}
|
||||
|
||||
this._container = null;
|
||||
this._map = null;
|
||||
},
|
||||
|
||||
getAttribution: function () {
|
||||
@ -79,26 +93,29 @@ L.TileLayer = L.Class.extend({
|
||||
setOpacity: function (opacity) {
|
||||
this.options.opacity = opacity;
|
||||
|
||||
this._setOpacity(opacity);
|
||||
if (this._map) {
|
||||
this._updateOpacity();
|
||||
}
|
||||
|
||||
// stupid webkit hack to force redrawing of tiles
|
||||
var i,
|
||||
tiles = this._tiles;
|
||||
|
||||
if (L.Browser.webkit) {
|
||||
for (var i in this._tiles) {
|
||||
if (this._tiles.hasOwnProperty(i)) {
|
||||
this._tiles[i].style.webkitTransform += ' translate(0,0)';
|
||||
for (i in tiles) {
|
||||
if (tiles.hasOwnProperty(i)) {
|
||||
tiles[i].style.webkitTransform += ' translate(0,0)';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_setOpacity: function (opacity) {
|
||||
if (opacity < 1) {
|
||||
L.DomUtil.setOpacity(this._container, opacity);
|
||||
}
|
||||
_updateOpacity: function () {
|
||||
L.DomUtil.setOpacity(this._container, this.options.opacity);
|
||||
},
|
||||
|
||||
_initContainer: function () {
|
||||
var tilePane = this._map.getPanes().tilePane,
|
||||
var tilePane = this._map._panes.tilePane,
|
||||
first = tilePane.firstChild;
|
||||
|
||||
if (!this._container || tilePane.empty) {
|
||||
@ -110,7 +127,9 @@ L.TileLayer = L.Class.extend({
|
||||
tilePane.appendChild(this._container);
|
||||
}
|
||||
|
||||
this._setOpacity(this.options.opacity);
|
||||
if (this.options.opacity < 1) {
|
||||
this._updateOpacity();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -119,12 +138,15 @@ L.TileLayer = L.Class.extend({
|
||||
},
|
||||
|
||||
_reset: function (clearOldContainer) {
|
||||
var key;
|
||||
for (key in this._tiles) {
|
||||
if (this._tiles.hasOwnProperty(key)) {
|
||||
this.fire("tileunload", {tile: this._tiles[key]});
|
||||
var key,
|
||||
tiles = this._tiles;
|
||||
|
||||
for (key in tiles) {
|
||||
if (tiles.hasOwnProperty(key)) {
|
||||
this.fire('tileunload', {tile: tiles[key]});
|
||||
}
|
||||
}
|
||||
|
||||
this._tiles = {};
|
||||
|
||||
if (this.options.reuseTiles) {
|
||||
@ -134,13 +156,16 @@ L.TileLayer = L.Class.extend({
|
||||
if (clearOldContainer && this._container) {
|
||||
this._container.innerHTML = "";
|
||||
}
|
||||
|
||||
this._initContainer();
|
||||
},
|
||||
|
||||
_update: function () {
|
||||
var bounds = this._map.getPixelBounds(),
|
||||
zoom = this._map.getZoom(),
|
||||
tileSize = this.options.tileSize;
|
||||
_update: function (e) {
|
||||
if (this._map._panTransition && this._map._panTransition._inProgress) { return; }
|
||||
|
||||
var bounds = this._map.getPixelBounds(),
|
||||
zoom = this._map.getZoom(),
|
||||
tileSize = this.options.tileSize;
|
||||
|
||||
if (zoom > this.options.maxZoom || zoom < this.options.minZoom) {
|
||||
return;
|
||||
@ -165,12 +190,12 @@ L.TileLayer = L.Class.extend({
|
||||
var queue = [],
|
||||
center = bounds.getCenter();
|
||||
|
||||
for (var j = bounds.min.y; j <= bounds.max.y; j++) {
|
||||
for (var i = bounds.min.x; i <= bounds.max.x; i++) {
|
||||
if ((i + ':' + j) in this._tiles) {
|
||||
continue;
|
||||
var j, i;
|
||||
for (j = bounds.min.y; j <= bounds.max.y; j++) {
|
||||
for (i = bounds.min.x; i <= bounds.max.x; i++) {
|
||||
if (!((i + ':' + j) in this._tiles)) {
|
||||
queue.push(new L.Point(i, j));
|
||||
}
|
||||
queue.push(new L.Point(i, j));
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,7 +207,9 @@ L.TileLayer = L.Class.extend({
|
||||
var fragment = document.createDocumentFragment();
|
||||
|
||||
this._tilesToLoad = queue.length;
|
||||
for (var k = 0, len = this._tilesToLoad; k < len; k++) {
|
||||
|
||||
var k, len;
|
||||
for (k = 0, len = this._tilesToLoad; k < len; k++) {
|
||||
this._addTile(queue[k], fragment);
|
||||
}
|
||||
|
||||
@ -200,40 +227,45 @@ L.TileLayer = L.Class.extend({
|
||||
|
||||
// remove tile if it's out of bounds
|
||||
if (x < bounds.min.x || x > bounds.max.x || y < bounds.min.y || y > bounds.max.y) {
|
||||
|
||||
tile = this._tiles[key];
|
||||
this.fire("tileunload", {tile: tile, url: tile.src});
|
||||
|
||||
if (tile.parentNode === this._container) {
|
||||
this._container.removeChild(tile);
|
||||
}
|
||||
if (this.options.reuseTiles) {
|
||||
this._unusedTiles.push(this._tiles[key]);
|
||||
}
|
||||
tile.src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
|
||||
|
||||
delete this._tiles[key];
|
||||
this._removeTile(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_removeTile: function (key) {
|
||||
var tile = this._tiles[key];
|
||||
|
||||
this.fire("tileunload", {tile: tile, url: tile.src});
|
||||
|
||||
if (tile.parentNode === this._container) {
|
||||
this._container.removeChild(tile);
|
||||
}
|
||||
if (this.options.reuseTiles) {
|
||||
this._unusedTiles.push(tile);
|
||||
}
|
||||
|
||||
tile.src = L.Util.emptyImageUrl;
|
||||
|
||||
delete this._tiles[key];
|
||||
},
|
||||
|
||||
_addTile: function (tilePoint, container) {
|
||||
var tilePos = this._getTilePos(tilePoint),
|
||||
zoom = this._map.getZoom(),
|
||||
key = tilePoint.x + ':' + tilePoint.y,
|
||||
tileLimit = Math.pow(2, this._getOffsetZoom(zoom));
|
||||
key = tilePoint.x + ':' + tilePoint.y,
|
||||
limit = Math.pow(2, this._getOffsetZoom(zoom));
|
||||
|
||||
// wrap tile coordinates
|
||||
if (!this.options.continuousWorld) {
|
||||
if (!this.options.noWrap) {
|
||||
tilePoint.x = ((tilePoint.x % tileLimit) + tileLimit) % tileLimit;
|
||||
} else if (tilePoint.x < 0 || tilePoint.x >= tileLimit) {
|
||||
tilePoint.x = ((tilePoint.x % limit) + limit) % limit;
|
||||
} else if (tilePoint.x < 0 || tilePoint.x >= limit) {
|
||||
this._tilesToLoad--;
|
||||
return;
|
||||
}
|
||||
|
||||
if (tilePoint.y < 0 || tilePoint.y >= tileLimit) {
|
||||
if (tilePoint.y < 0 || tilePoint.y >= limit) {
|
||||
this._tilesToLoad--;
|
||||
return;
|
||||
}
|
||||
@ -246,7 +278,7 @@ L.TileLayer = L.Class.extend({
|
||||
this._tiles[key] = tile;
|
||||
|
||||
if (this.options.scheme === 'tms') {
|
||||
tilePoint.y = tileLimit - tilePoint.y - 1;
|
||||
tilePoint.y = limit - tilePoint.y - 1;
|
||||
}
|
||||
|
||||
this._loadTile(tile, tilePoint, zoom);
|
||||
@ -255,8 +287,9 @@ L.TileLayer = L.Class.extend({
|
||||
},
|
||||
|
||||
_getOffsetZoom: function (zoom) {
|
||||
zoom = this.options.zoomReverse ? this.options.maxZoom - zoom : zoom;
|
||||
return zoom + this.options.zoomOffset;
|
||||
var options = this.options;
|
||||
zoom = options.zoomReverse ? options.maxZoom - zoom : zoom;
|
||||
return zoom + options.zoomOffset;
|
||||
},
|
||||
|
||||
_getTilePos: function (tilePoint) {
|
||||
@ -270,23 +303,24 @@ L.TileLayer = L.Class.extend({
|
||||
|
||||
getTileUrl: function (tilePoint, zoom) {
|
||||
var subdomains = this.options.subdomains,
|
||||
s = this.options.subdomains[(tilePoint.x + tilePoint.y) % subdomains.length];
|
||||
index = (tilePoint.x + tilePoint.y) % subdomains.length,
|
||||
s = this.options.subdomains[index];
|
||||
|
||||
return L.Util.template(this._url, L.Util.extend({
|
||||
s: s,
|
||||
z: this._getOffsetZoom(zoom),
|
||||
x: tilePoint.x,
|
||||
y: tilePoint.y
|
||||
}, this._urlParams));
|
||||
}, this.options));
|
||||
},
|
||||
|
||||
_createTileProto: function () {
|
||||
this._tileImg = L.DomUtil.create('img', 'leaflet-tile');
|
||||
this._tileImg.galleryimg = 'no';
|
||||
var img = this._tileImg = L.DomUtil.create('img', 'leaflet-tile');
|
||||
img.galleryimg = 'no';
|
||||
|
||||
var tileSize = this.options.tileSize;
|
||||
this._tileImg.style.width = tileSize + 'px';
|
||||
this._tileImg.style.height = tileSize + 'px';
|
||||
img.style.width = tileSize + 'px';
|
||||
img.style.height = tileSize + 'px';
|
||||
},
|
||||
|
||||
_getTile: function () {
|
||||
@ -309,33 +343,46 @@ L.TileLayer = L.Class.extend({
|
||||
},
|
||||
|
||||
_loadTile: function (tile, tilePoint, zoom) {
|
||||
tile._layer = this;
|
||||
tile.onload = this._tileOnLoad;
|
||||
tile._layer = this;
|
||||
tile.onload = this._tileOnLoad;
|
||||
tile.onerror = this._tileOnError;
|
||||
tile.src = this.getTileUrl(tilePoint, zoom);
|
||||
|
||||
tile.src = this.getTileUrl(tilePoint, zoom);
|
||||
},
|
||||
|
||||
_tileLoaded: function () {
|
||||
this._tilesToLoad--;
|
||||
if (!this._tilesToLoad) {
|
||||
this.fire('load');
|
||||
}
|
||||
},
|
||||
|
||||
_tileOnLoad: function (e) {
|
||||
var layer = this._layer;
|
||||
|
||||
this.className += ' leaflet-tile-loaded';
|
||||
|
||||
layer.fire('tileload', {tile: this, url: this.src});
|
||||
layer.fire('tileload', {
|
||||
tile: this,
|
||||
url: this.src
|
||||
});
|
||||
|
||||
layer._tilesToLoad--;
|
||||
if (!layer._tilesToLoad) {
|
||||
layer.fire('load');
|
||||
}
|
||||
layer._tileLoaded();
|
||||
},
|
||||
|
||||
_tileOnError: function (e) {
|
||||
var layer = this._layer;
|
||||
|
||||
layer.fire('tileerror', {tile: this, url: this.src});
|
||||
layer.fire('tileerror', {
|
||||
tile: this,
|
||||
url: this.src
|
||||
});
|
||||
|
||||
var newUrl = layer.options.errorTileUrl;
|
||||
if (newUrl) {
|
||||
this.src = newUrl;
|
||||
}
|
||||
}
|
||||
|
||||
layer._tileLoaded();
|
||||
}
|
||||
});
|
||||
|
@ -16,26 +16,38 @@ L.Circle = L.Path.extend({
|
||||
|
||||
setLatLng: function (latlng) {
|
||||
this._latlng = latlng;
|
||||
this._redraw();
|
||||
return this;
|
||||
return this.redraw();
|
||||
},
|
||||
|
||||
setRadius: function (radius) {
|
||||
this._mRadius = radius;
|
||||
this._redraw();
|
||||
return this;
|
||||
return this.redraw();
|
||||
},
|
||||
|
||||
projectLatlngs: function () {
|
||||
var equatorLength = 40075017,
|
||||
hLength = equatorLength * Math.cos(L.LatLng.DEG_TO_RAD * this._latlng.lat);
|
||||
|
||||
var lngSpan = (this._mRadius / hLength) * 360,
|
||||
latlng2 = new L.LatLng(this._latlng.lat, this._latlng.lng - lngSpan, true),
|
||||
var lngRadius = this._getLngRadius(),
|
||||
latlng2 = new L.LatLng(this._latlng.lat, this._latlng.lng - lngRadius, true),
|
||||
point2 = this._map.latLngToLayerPoint(latlng2);
|
||||
|
||||
this._point = this._map.latLngToLayerPoint(this._latlng);
|
||||
this._radius = Math.round(this._point.x - point2.x);
|
||||
this._radius = Math.max(Math.round(this._point.x - point2.x), 1);
|
||||
},
|
||||
|
||||
getBounds: function () {
|
||||
var map = this._map,
|
||||
delta = this._radius * Math.cos(Math.PI / 4),
|
||||
point = map.project(this._latlng),
|
||||
swPoint = new L.Point(point.x - delta, point.y + delta),
|
||||
nePoint = new L.Point(point.x + delta, point.y - delta),
|
||||
zoom = map.getZoom(),
|
||||
sw = map.unproject(swPoint, zoom, true),
|
||||
ne = map.unproject(nePoint, zoom, true);
|
||||
|
||||
return new L.LatLngBounds(sw, ne);
|
||||
},
|
||||
|
||||
getLatLng: function () {
|
||||
return this._latlng;
|
||||
},
|
||||
|
||||
getPathString: function () {
|
||||
@ -56,8 +68,22 @@ L.Circle = L.Path.extend({
|
||||
return "AL " + p.x + "," + p.y + " " + r + "," + r + " 0," + (65535 * 360);
|
||||
}
|
||||
},
|
||||
|
||||
getRadius: function () {
|
||||
return this._mRadius;
|
||||
},
|
||||
|
||||
_getLngRadius: function () {
|
||||
var equatorLength = 40075017,
|
||||
hLength = equatorLength * Math.cos(L.LatLng.DEG_TO_RAD * this._latlng.lat);
|
||||
|
||||
return (this._mRadius / hLength) * 360;
|
||||
},
|
||||
|
||||
_checkIfEmpty: function () {
|
||||
if (!this._map) {
|
||||
return false;
|
||||
}
|
||||
var vp = this._map._pathViewport,
|
||||
r = this._radius,
|
||||
p = this._point;
|
||||
|
@ -19,7 +19,6 @@ L.CircleMarker = L.Circle.extend({
|
||||
|
||||
setRadius: function (radius) {
|
||||
this._radius = radius;
|
||||
this._redraw();
|
||||
return this;
|
||||
return this.redraw();
|
||||
}
|
||||
});
|
||||
|
@ -25,6 +25,8 @@
|
||||
while (i < len) {
|
||||
this.addLayer(new Klass(latlngs[i++], this._options));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -4,16 +4,17 @@ L.Browser.svg = !!(document.createElementNS && document.createElementNS(L.Path.S
|
||||
|
||||
L.Path = L.Path.extend({
|
||||
statics: {
|
||||
SVG: L.Browser.svg,
|
||||
_createElement: function (name) {
|
||||
return document.createElementNS(L.Path.SVG_NS, name);
|
||||
}
|
||||
SVG: L.Browser.svg
|
||||
},
|
||||
|
||||
getPathString: function () {
|
||||
// form path string here
|
||||
},
|
||||
|
||||
_createElement: function (name) {
|
||||
return document.createElementNS(L.Path.SVG_NS, name);
|
||||
},
|
||||
|
||||
_initElements: function () {
|
||||
this._map._initPathRoot();
|
||||
this._initPath();
|
||||
@ -21,9 +22,9 @@ L.Path = L.Path.extend({
|
||||
},
|
||||
|
||||
_initPath: function () {
|
||||
this._container = L.Path._createElement('g');
|
||||
this._container = this._createElement('g');
|
||||
|
||||
this._path = L.Path._createElement('path');
|
||||
this._path = this._createElement('path');
|
||||
this._container.appendChild(this._path);
|
||||
|
||||
this._map._pathRoot.appendChild(this._container);
|
||||
@ -36,8 +37,6 @@ L.Path = L.Path.extend({
|
||||
}
|
||||
if (this.options.fill) {
|
||||
this._path.setAttribute('fill-rule', 'evenodd');
|
||||
} else {
|
||||
this._path.setAttribute('fill', 'none');
|
||||
}
|
||||
this._updateStyle();
|
||||
},
|
||||
@ -47,10 +46,14 @@ L.Path = L.Path.extend({
|
||||
this._path.setAttribute('stroke', this.options.color);
|
||||
this._path.setAttribute('stroke-opacity', this.options.opacity);
|
||||
this._path.setAttribute('stroke-width', this.options.weight);
|
||||
} else {
|
||||
this._path.setAttribute('stroke', 'none');
|
||||
}
|
||||
if (this.options.fill) {
|
||||
this._path.setAttribute('fill', this.options.fillColor || this.options.color);
|
||||
this._path.setAttribute('fill-opacity', this.options.fillOpacity);
|
||||
} else {
|
||||
this._path.setAttribute('fill', 'none');
|
||||
}
|
||||
},
|
||||
|
||||
@ -66,13 +69,13 @@ L.Path = L.Path.extend({
|
||||
// TODO remove duplication with L.Map
|
||||
_initEvents: function () {
|
||||
if (this.options.clickable) {
|
||||
if (!L.Browser.vml) {
|
||||
if (L.Browser.svg || !L.Browser.vml) {
|
||||
this._path.setAttribute('class', 'leaflet-clickable');
|
||||
}
|
||||
|
||||
L.DomEvent.addListener(this._container, 'click', this._onMouseClick, this);
|
||||
|
||||
var events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'mousemove'];
|
||||
var events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'mousemove', 'contextmenu'];
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
L.DomEvent.addListener(this._container, events[i], this._fireMouseEvent, this);
|
||||
}
|
||||
@ -83,6 +86,11 @@ L.Path = L.Path.extend({
|
||||
if (this._map.dragging && this._map.dragging.moved()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.type === 'contextmenu') {
|
||||
L.DomEvent.preventDefault(e);
|
||||
}
|
||||
|
||||
this._fireMouseEvent(e);
|
||||
},
|
||||
|
||||
@ -90,10 +98,18 @@ L.Path = L.Path.extend({
|
||||
if (!this.hasEventListeners(e.type)) {
|
||||
return;
|
||||
}
|
||||
var map = this._map,
|
||||
containerPoint = map.mouseEventToContainerPoint(e),
|
||||
layerPoint = map.containerPointToLayerPoint(containerPoint),
|
||||
latlng = map.layerPointToLatLng(layerPoint);
|
||||
|
||||
this.fire(e.type, {
|
||||
latlng: this._map.mouseEventToLatLng(e),
|
||||
layerPoint: this._map.mouseEventToLayerPoint(e)
|
||||
latlng: latlng,
|
||||
layerPoint: layerPoint,
|
||||
containerPoint: containerPoint,
|
||||
originalEvent: e
|
||||
});
|
||||
|
||||
L.DomEvent.stopPropagation(e);
|
||||
}
|
||||
});
|
||||
@ -101,15 +117,45 @@ L.Path = L.Path.extend({
|
||||
L.Map.include({
|
||||
_initPathRoot: function () {
|
||||
if (!this._pathRoot) {
|
||||
this._pathRoot = L.Path._createElement('svg');
|
||||
this._pathRoot = L.Path.prototype._createElement('svg');
|
||||
this._panes.overlayPane.appendChild(this._pathRoot);
|
||||
|
||||
if (this.options.zoomAnimation) {
|
||||
this._pathRoot.setAttribute('class', ' leaflet-zoom-animated');
|
||||
this.on('zoomanim', this._animatePathZoom);
|
||||
this.on('zoomend', this._endPathZoom);
|
||||
}
|
||||
|
||||
this.on('moveend', this._updateSvgViewport);
|
||||
this._updateSvgViewport();
|
||||
}
|
||||
},
|
||||
|
||||
_animatePathZoom: function (opt) {
|
||||
var centerOffset = this._getNewTopLeftPoint(opt.center).subtract(this._getTopLeftPoint()),
|
||||
scale = Math.pow(2, opt.zoom - this._zoom),
|
||||
offset = centerOffset.divideBy(1 - 1 / scale),
|
||||
centerPoint = this.containerPointToLayerPoint(this.getSize().divideBy(-2)),
|
||||
origin = centerPoint.add(offset).round(),
|
||||
pathRootStyle = this._pathRoot.style;
|
||||
|
||||
pathRootStyle[L.DomUtil.TRANSFORM] = L.DomUtil.getTranslateString((origin.multiplyBy(-1).add(L.DomUtil.getPosition(this._pathRoot)).multiplyBy(scale).add(origin))) + ' scale(' + scale + ') ';
|
||||
|
||||
this._pathZooming = true;
|
||||
},
|
||||
|
||||
_endPathZoom: function () {
|
||||
this._pathZooming = false;
|
||||
},
|
||||
|
||||
_updateSvgViewport: function () {
|
||||
if (this._pathZooming) {
|
||||
//Do not update SVGs while a zoom animation is going on otherwise the animation will break.
|
||||
//When the zoom animation ends we will be updated again anyway
|
||||
//This fixes the case where you do a momentum move and zoom while the move is still ongoing.
|
||||
return;
|
||||
}
|
||||
|
||||
this._updatePathViewport();
|
||||
|
||||
var vp = this._pathViewport,
|
||||
@ -122,7 +168,7 @@ L.Map.include({
|
||||
|
||||
// Hack to make flicker on drag end on mobile webkit less irritating
|
||||
// Unfortunately I haven't found a good workaround for this yet
|
||||
if (L.Browser.webkit) {
|
||||
if (L.Browser.mobileWebkit) {
|
||||
pane.removeChild(root);
|
||||
}
|
||||
|
||||
@ -131,7 +177,7 @@ L.Map.include({
|
||||
root.setAttribute('height', height);
|
||||
root.setAttribute('viewBox', [min.x, min.y, width, height].join(' '));
|
||||
|
||||
if (L.Browser.webkit) {
|
||||
if (L.Browser.mobileWebkit) {
|
||||
pane.appendChild(root);
|
||||
}
|
||||
}
|
||||
|
@ -4,90 +4,104 @@
|
||||
*/
|
||||
|
||||
L.Browser.vml = (function () {
|
||||
var d = document.createElement('div'), s;
|
||||
d.innerHTML = '<v:shape adj="1"/>';
|
||||
s = d.firstChild;
|
||||
s.style.behavior = 'url(#default#VML)';
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = '<v:shape adj="1"/>';
|
||||
|
||||
return (s && (typeof s.adj === 'object'));
|
||||
var shape = div.firstChild;
|
||||
shape.style.behavior = 'url(#default#VML)';
|
||||
|
||||
return shape && (typeof shape.adj === 'object');
|
||||
}());
|
||||
|
||||
L.Path = L.Browser.svg || !L.Browser.vml ? L.Path : L.Path.extend({
|
||||
statics: {
|
||||
VML: true,
|
||||
CLIP_PADDING: 0.02,
|
||||
_createElement: (function () {
|
||||
try {
|
||||
document.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml');
|
||||
return function (name) {
|
||||
return document.createElement('<lvml:' + name + ' class="lvml">');
|
||||
};
|
||||
} catch (e) {
|
||||
return function (name) {
|
||||
return document.createElement('<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">');
|
||||
};
|
||||
}
|
||||
}())
|
||||
CLIP_PADDING: 0.02
|
||||
},
|
||||
|
||||
_createElement: (function () {
|
||||
try {
|
||||
document.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml');
|
||||
return function (name) {
|
||||
return document.createElement('<lvml:' + name + ' class="lvml">');
|
||||
};
|
||||
} catch (e) {
|
||||
return function (name) {
|
||||
return document.createElement('<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">');
|
||||
};
|
||||
}
|
||||
}()),
|
||||
|
||||
_initPath: function () {
|
||||
this._container = L.Path._createElement('shape');
|
||||
this._container.className += ' leaflet-vml-shape' +
|
||||
var container = this._container = this._createElement('shape');
|
||||
container.className += ' leaflet-vml-shape' +
|
||||
(this.options.clickable ? ' leaflet-clickable' : '');
|
||||
this._container.coordsize = '1 1';
|
||||
container.coordsize = '1 1';
|
||||
|
||||
this._path = L.Path._createElement('path');
|
||||
this._container.appendChild(this._path);
|
||||
this._path = this._createElement('path');
|
||||
container.appendChild(this._path);
|
||||
|
||||
this._map._pathRoot.appendChild(this._container);
|
||||
this._map._pathRoot.appendChild(container);
|
||||
},
|
||||
|
||||
_initStyle: function () {
|
||||
var container = this._container,
|
||||
stroke,
|
||||
fill;
|
||||
|
||||
if (this.options.stroke) {
|
||||
this._stroke = L.Path._createElement('stroke');
|
||||
this._stroke.endcap = 'round';
|
||||
this._container.appendChild(this._stroke);
|
||||
} else {
|
||||
this._container.stroked = false;
|
||||
stroke = this._stroke = this._createElement('stroke');
|
||||
stroke.endcap = 'round';
|
||||
container.appendChild(stroke);
|
||||
}
|
||||
|
||||
if (this.options.fill) {
|
||||
this._container.filled = true;
|
||||
this._fill = L.Path._createElement('fill');
|
||||
this._container.appendChild(this._fill);
|
||||
} else {
|
||||
this._container.filled = false;
|
||||
fill = this._fill = this._createElement('fill');
|
||||
container.appendChild(fill);
|
||||
}
|
||||
|
||||
this._updateStyle();
|
||||
},
|
||||
|
||||
_updateStyle: function () {
|
||||
if (this.options.stroke) {
|
||||
this._stroke.weight = this.options.weight + 'px';
|
||||
this._stroke.color = this.options.color;
|
||||
this._stroke.opacity = this.options.opacity;
|
||||
var stroke = this._stroke,
|
||||
fill = this._fill,
|
||||
options = this.options,
|
||||
container = this._container;
|
||||
|
||||
container.stroked = options.stroke;
|
||||
container.filled = options.fill;
|
||||
|
||||
if (options.stroke) {
|
||||
stroke.weight = options.weight + 'px';
|
||||
stroke.color = options.color;
|
||||
stroke.opacity = options.opacity;
|
||||
}
|
||||
if (this.options.fill) {
|
||||
this._fill.color = this.options.fillColor || this.options.color;
|
||||
this._fill.opacity = this.options.fillOpacity;
|
||||
|
||||
if (options.fill) {
|
||||
fill.color = options.fillColor || options.color;
|
||||
fill.opacity = options.fillOpacity;
|
||||
}
|
||||
},
|
||||
|
||||
_updatePath: function () {
|
||||
this._container.style.display = 'none';
|
||||
var style = this._container.style;
|
||||
|
||||
style.display = 'none';
|
||||
this._path.v = this.getPathString() + ' '; // the space fixes IE empty path string bug
|
||||
this._container.style.display = '';
|
||||
style.display = '';
|
||||
}
|
||||
});
|
||||
|
||||
L.Map.include(L.Browser.svg || !L.Browser.vml ? {} : {
|
||||
_initPathRoot: function () {
|
||||
if (!this._pathRoot) {
|
||||
this._pathRoot = document.createElement('div');
|
||||
this._pathRoot.className = 'leaflet-vml-container';
|
||||
this._panes.overlayPane.appendChild(this._pathRoot);
|
||||
if (this._pathRoot) { return; }
|
||||
|
||||
this.on('moveend', this._updatePathViewport);
|
||||
this._updatePathViewport();
|
||||
}
|
||||
var root = this._pathRoot = document.createElement('div');
|
||||
root.className = 'leaflet-vml-container';
|
||||
this._panes.overlayPane.appendChild(root);
|
||||
|
||||
this.on('moveend', this._updatePathViewport);
|
||||
this._updatePathViewport();
|
||||
}
|
||||
});
|
||||
|
@ -21,10 +21,7 @@ L.Path = L.Class.extend({
|
||||
fillColor: null, //same as color by default
|
||||
fillOpacity: 0.2,
|
||||
|
||||
clickable: true,
|
||||
|
||||
// TODO remove this, as all paths now update on moveend
|
||||
updateOnMoveEnd: true
|
||||
clickable: true
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
@ -39,10 +36,9 @@ L.Path = L.Class.extend({
|
||||
this.projectLatlngs();
|
||||
this._updatePath();
|
||||
|
||||
map.on('viewreset', this.projectLatlngs, this);
|
||||
|
||||
this._updateTrigger = this.options.updateOnMoveEnd ? 'moveend' : 'viewreset';
|
||||
map.on(this._updateTrigger, this._updatePath, this);
|
||||
map
|
||||
.on('viewreset', this.projectLatlngs, this)
|
||||
.on('moveend', this._updatePath, this);
|
||||
},
|
||||
|
||||
onRemove: function (map) {
|
||||
@ -50,8 +46,9 @@ L.Path = L.Class.extend({
|
||||
|
||||
map._pathRoot.removeChild(this._container);
|
||||
|
||||
map.off('viewreset', this.projectLatlngs, this);
|
||||
map.off(this._updateTrigger, this._updatePath, this);
|
||||
map
|
||||
.off('viewreset', this.projectLatlngs, this)
|
||||
.off('moveend', this._updatePath, this);
|
||||
},
|
||||
|
||||
projectLatlngs: function () {
|
||||
@ -60,17 +57,20 @@ L.Path = L.Class.extend({
|
||||
|
||||
setStyle: function (style) {
|
||||
L.Util.setOptions(this, style);
|
||||
|
||||
if (this._container) {
|
||||
this._updateStyle();
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_redraw: function () {
|
||||
redraw: function () {
|
||||
if (this._map) {
|
||||
this.projectLatlngs();
|
||||
this._updatePath();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
@ -78,9 +78,8 @@ L.Map.include({
|
||||
_updatePathViewport: function () {
|
||||
var p = L.Path.CLIP_PADDING,
|
||||
size = this.getSize(),
|
||||
//TODO this._map._getMapPanePos()
|
||||
panePos = L.DomUtil.getPosition(this._mapPane),
|
||||
min = panePos.multiplyBy(-1).subtract(size.multiplyBy(p)),
|
||||
min = panePos.multiplyBy(-1)._subtract(size.multiplyBy(p)),
|
||||
max = min.add(size.multiplyBy(1 + p * 2));
|
||||
|
||||
this._pathViewport = new L.Bounds(min, max);
|
||||
|
210
src/layer/vector/Polyline.Edit.js
Normal file
210
src/layer/vector/Polyline.Edit.js
Normal file
@ -0,0 +1,210 @@
|
||||
L.Handler.PolyEdit = L.Handler.extend({
|
||||
options: {
|
||||
icon: new L.DivIcon({
|
||||
iconSize: new L.Point(8, 8),
|
||||
className: 'leaflet-div-icon leaflet-editing-icon'
|
||||
})
|
||||
},
|
||||
|
||||
initialize: function (poly, options) {
|
||||
this._poly = poly;
|
||||
L.Util.setOptions(this, options);
|
||||
},
|
||||
|
||||
addHooks: function () {
|
||||
if (this._poly._map) {
|
||||
if (!this._markerGroup) {
|
||||
this._initMarkers();
|
||||
}
|
||||
this._poly._map.addLayer(this._markerGroup);
|
||||
}
|
||||
},
|
||||
|
||||
removeHooks: function () {
|
||||
if (this._poly._map) {
|
||||
this._poly._map.removeLayer(this._markerGroup);
|
||||
delete this._markerGroup;
|
||||
delete this._markers;
|
||||
}
|
||||
},
|
||||
|
||||
updateMarkers: function () {
|
||||
this._markerGroup.clearLayers();
|
||||
this._initMarkers();
|
||||
},
|
||||
|
||||
_initMarkers: function () {
|
||||
if (!this._markerGroup) {
|
||||
this._markerGroup = new L.LayerGroup();
|
||||
}
|
||||
this._markers = [];
|
||||
|
||||
var latlngs = this._poly._latlngs,
|
||||
i, j, len, marker;
|
||||
|
||||
// TODO refactor holes implementation in Polygon to support it here
|
||||
|
||||
for (i = 0, len = latlngs.length; i < len; i++) {
|
||||
|
||||
marker = this._createMarker(latlngs[i], i);
|
||||
marker.on('click', this._onMarkerClick, this);
|
||||
this._markers.push(marker);
|
||||
}
|
||||
|
||||
var markerLeft, markerRight;
|
||||
|
||||
for (i = 0, j = len - 1; i < len; j = i++) {
|
||||
if (i === 0 && !(L.Polygon && (this._poly instanceof L.Polygon))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
markerLeft = this._markers[j];
|
||||
markerRight = this._markers[i];
|
||||
|
||||
this._createMiddleMarker(markerLeft, markerRight);
|
||||
this._updatePrevNext(markerLeft, markerRight);
|
||||
}
|
||||
},
|
||||
|
||||
_createMarker: function (latlng, index) {
|
||||
var marker = new L.Marker(latlng, {
|
||||
draggable: true,
|
||||
icon: this.options.icon
|
||||
});
|
||||
|
||||
marker._origLatLng = latlng;
|
||||
marker._index = index;
|
||||
|
||||
marker.on('drag', this._onMarkerDrag, this);
|
||||
marker.on('dragend', this._fireEdit, this);
|
||||
|
||||
this._markerGroup.addLayer(marker);
|
||||
|
||||
return marker;
|
||||
},
|
||||
|
||||
_fireEdit: function () {
|
||||
this._poly.fire('edit');
|
||||
},
|
||||
|
||||
_onMarkerDrag: function (e) {
|
||||
var marker = e.target;
|
||||
|
||||
L.Util.extend(marker._origLatLng, marker._latlng);
|
||||
|
||||
if (marker._middleLeft) {
|
||||
marker._middleLeft.setLatLng(this._getMiddleLatLng(marker._prev, marker));
|
||||
}
|
||||
if (marker._middleRight) {
|
||||
marker._middleRight.setLatLng(this._getMiddleLatLng(marker, marker._next));
|
||||
}
|
||||
|
||||
this._poly.redraw();
|
||||
},
|
||||
|
||||
_onMarkerClick: function (e) {
|
||||
// Default action on marker click is to remove that marker, but if we remove the marker when latlng count < 3, we don't have a valid polyline anymore
|
||||
if (this._poly._latlngs.length < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
var marker = e.target,
|
||||
i = marker._index;
|
||||
|
||||
// Check existence of previous and next markers since they wouldn't exist for edge points on the polyline
|
||||
if (marker._prev && marker._next) {
|
||||
this._createMiddleMarker(marker._prev, marker._next);
|
||||
this._updatePrevNext(marker._prev, marker._next);
|
||||
}
|
||||
|
||||
// The marker itself is guaranteed to exist and present in the layer, since we managed to click on it
|
||||
this._markerGroup.removeLayer(marker);
|
||||
// Check for the existence of middle left or middle right
|
||||
if (marker._middleLeft) {
|
||||
this._markerGroup.removeLayer(marker._middleLeft);
|
||||
}
|
||||
if (marker._middleRight) {
|
||||
this._markerGroup.removeLayer(marker._middleRight);
|
||||
}
|
||||
this._markers.splice(i, 1);
|
||||
this._poly.spliceLatLngs(i, 1);
|
||||
this._updateIndexes(i, -1);
|
||||
this._poly.fire('edit');
|
||||
},
|
||||
|
||||
_updateIndexes: function (index, delta) {
|
||||
this._markerGroup._iterateLayers(function (marker) {
|
||||
if (marker._index > index) {
|
||||
marker._index += delta;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_createMiddleMarker: function (marker1, marker2) {
|
||||
var latlng = this._getMiddleLatLng(marker1, marker2),
|
||||
marker = this._createMarker(latlng),
|
||||
onClick,
|
||||
onDragStart,
|
||||
onDragEnd;
|
||||
|
||||
marker.setOpacity(0.6);
|
||||
|
||||
marker1._middleRight = marker2._middleLeft = marker;
|
||||
|
||||
onDragStart = function () {
|
||||
var i = marker2._index;
|
||||
|
||||
marker._index = i;
|
||||
|
||||
marker
|
||||
.off('click', onClick)
|
||||
.on('click', this._onMarkerClick, this);
|
||||
|
||||
latlng.lat = marker.getLatLng().lat;
|
||||
latlng.lng = marker.getLatLng().lng;
|
||||
this._poly.spliceLatLngs(i, 0, latlng);
|
||||
this._markers.splice(i, 0, marker);
|
||||
|
||||
marker.setOpacity(1);
|
||||
|
||||
this._updateIndexes(i, 1);
|
||||
marker2._index++;
|
||||
this._updatePrevNext(marker1, marker);
|
||||
this._updatePrevNext(marker, marker2);
|
||||
};
|
||||
|
||||
onDragEnd = function () {
|
||||
marker.off('dragstart', onDragStart, this);
|
||||
marker.off('dragend', onDragEnd, this);
|
||||
|
||||
this._createMiddleMarker(marker1, marker);
|
||||
this._createMiddleMarker(marker, marker2);
|
||||
};
|
||||
|
||||
onClick = function () {
|
||||
onDragStart.call(this);
|
||||
onDragEnd.call(this);
|
||||
this._poly.fire('edit');
|
||||
};
|
||||
|
||||
marker
|
||||
.on('click', onClick, this)
|
||||
.on('dragstart', onDragStart, this)
|
||||
.on('dragend', onDragEnd, this);
|
||||
|
||||
this._markerGroup.addLayer(marker);
|
||||
},
|
||||
|
||||
_updatePrevNext: function (marker1, marker2) {
|
||||
marker1._next = marker2;
|
||||
marker2._prev = marker1;
|
||||
},
|
||||
|
||||
_getMiddleLatLng: function (marker1, marker2) {
|
||||
var map = this._poly._map,
|
||||
p1 = map.latLngToLayerPoint(marker1.getLatLng()),
|
||||
p2 = map.latLngToLayerPoint(marker2.getLatLng());
|
||||
|
||||
return map.layerPointToLatLng(p1._add(p2).divideBy(2));
|
||||
}
|
||||
});
|
@ -1,17 +1,23 @@
|
||||
|
||||
L.Polyline = L.Path.extend({
|
||||
initialize: function (latlngs, options) {
|
||||
L.Path.prototype.initialize.call(this, options);
|
||||
this._latlngs = latlngs;
|
||||
|
||||
// TODO refactor: move to Polyline.Edit.js
|
||||
if (L.Handler.PolyEdit) {
|
||||
this.editing = new L.Handler.PolyEdit(this);
|
||||
|
||||
if (this.options.editable) {
|
||||
this.editing.enable();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
options: {
|
||||
// how much to simplify the polyline on each zoom level
|
||||
// more = better performance and smoother look, less = more accurate
|
||||
smoothFactor: 1.0,
|
||||
noClip: false,
|
||||
|
||||
updateOnMoveEnd: true
|
||||
noClip: false
|
||||
},
|
||||
|
||||
projectLatlngs: function () {
|
||||
@ -35,19 +41,17 @@ L.Polyline = L.Path.extend({
|
||||
|
||||
setLatLngs: function (latlngs) {
|
||||
this._latlngs = latlngs;
|
||||
this._redraw();
|
||||
return this;
|
||||
return this.redraw();
|
||||
},
|
||||
|
||||
addLatLng: function (latlng) {
|
||||
this._latlngs.push(latlng);
|
||||
this._redraw();
|
||||
return this;
|
||||
return this.redraw();
|
||||
},
|
||||
|
||||
spliceLatLngs: function (index, howMany) {
|
||||
var removed = [].splice.apply(this._latlngs, arguments);
|
||||
this._redraw();
|
||||
this.redraw();
|
||||
return removed;
|
||||
},
|
||||
|
||||
@ -81,6 +85,27 @@ L.Polyline = L.Path.extend({
|
||||
return b;
|
||||
},
|
||||
|
||||
// TODO refactor: move to Polyline.Edit.js
|
||||
onAdd: function (map) {
|
||||
L.Path.prototype.onAdd.call(this, map);
|
||||
|
||||
if (this.editing && this.editing.enabled()) {
|
||||
this.editing.addHooks();
|
||||
}
|
||||
},
|
||||
|
||||
onRemove: function (map) {
|
||||
if (this.editing && this.editing.enabled()) {
|
||||
this.editing.removeHooks();
|
||||
}
|
||||
|
||||
L.Path.prototype.onRemove.call(this, map);
|
||||
},
|
||||
|
||||
_initEvents: function () {
|
||||
L.Path.prototype._initEvents.call(this);
|
||||
},
|
||||
|
||||
_getPathPartStr: function (points) {
|
||||
var round = L.Path.VML;
|
||||
|
||||
|
23
src/layer/vector/Rectangle.js
Normal file
23
src/layer/vector/Rectangle.js
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds
|
||||
*/
|
||||
|
||||
L.Rectangle = L.Polygon.extend({
|
||||
initialize: function (latLngBounds, options) {
|
||||
L.Polygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options);
|
||||
},
|
||||
|
||||
setBounds: function (latLngBounds) {
|
||||
this.setLatLngs(this._boundsToLatLngs(latLngBounds));
|
||||
},
|
||||
|
||||
_boundsToLatLngs: function (latLngBounds) {
|
||||
return [
|
||||
latLngBounds.getSouthWest(),
|
||||
latLngBounds.getNorthWest(),
|
||||
latLngBounds.getNorthEast(),
|
||||
latLngBounds.getSouthEast(),
|
||||
latLngBounds.getSouthWest()
|
||||
];
|
||||
}
|
||||
});
|
@ -6,7 +6,7 @@ L.Circle.include(!L.Path.CANVAS ? {} : {
|
||||
_drawPath: function () {
|
||||
var p = this._point;
|
||||
this._ctx.beginPath();
|
||||
this._ctx.arc(p.x, p.y, this._radius, 0, Math.PI * 2);
|
||||
this._ctx.arc(p.x, p.y, this._radius, 0, Math.PI * 2, false);
|
||||
},
|
||||
|
||||
_containsPoint: function (p) {
|
||||
|
@ -13,22 +13,20 @@ L.Path = (L.Path.SVG && !window.L_PREFER_CANVAS) || !L.Browser.canvas ? L.Path :
|
||||
SVG: false
|
||||
},
|
||||
|
||||
options: {
|
||||
updateOnMoveEnd: true
|
||||
},
|
||||
|
||||
_initElements: function () {
|
||||
this._map._initPathRoot();
|
||||
this._ctx = this._map._canvasCtx;
|
||||
},
|
||||
|
||||
_updateStyle: function () {
|
||||
if (this.options.stroke) {
|
||||
this._ctx.lineWidth = this.options.weight;
|
||||
this._ctx.strokeStyle = this.options.color;
|
||||
var options = this.options;
|
||||
|
||||
if (options.stroke) {
|
||||
this._ctx.lineWidth = options.weight;
|
||||
this._ctx.strokeStyle = options.color;
|
||||
}
|
||||
if (this.options.fill) {
|
||||
this._ctx.fillStyle = this.options.fillColor || this.options.color;
|
||||
if (options.fill) {
|
||||
this._ctx.fillStyle = options.fillColor || options.color;
|
||||
}
|
||||
},
|
||||
|
||||
@ -56,34 +54,30 @@ L.Path = (L.Path.SVG && !window.L_PREFER_CANVAS) || !L.Browser.canvas ? L.Path :
|
||||
},
|
||||
|
||||
_updatePath: function () {
|
||||
if (this._checkIfEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (this._checkIfEmpty()) { return; }
|
||||
|
||||
var ctx = this._ctx,
|
||||
options = this.options;
|
||||
|
||||
this._drawPath();
|
||||
|
||||
this._ctx.save();
|
||||
|
||||
ctx.save();
|
||||
this._updateStyle();
|
||||
|
||||
var opacity = this.options.opacity,
|
||||
fillOpacity = this.options.fillOpacity;
|
||||
|
||||
if (this.options.fill) {
|
||||
if (fillOpacity < 1) {
|
||||
this._ctx.globalAlpha = fillOpacity;
|
||||
if (options.fill) {
|
||||
if (options.fillOpacity < 1) {
|
||||
ctx.globalAlpha = options.fillOpacity;
|
||||
}
|
||||
this._ctx.fill();
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
if (this.options.stroke) {
|
||||
if (opacity < 1) {
|
||||
this._ctx.globalAlpha = opacity;
|
||||
if (options.stroke) {
|
||||
if (options.opacity < 1) {
|
||||
ctx.globalAlpha = options.opacity;
|
||||
}
|
||||
this._ctx.stroke();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
this._ctx.restore();
|
||||
ctx.restore();
|
||||
|
||||
// TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature
|
||||
},
|
||||
@ -103,9 +97,10 @@ L.Path = (L.Path.SVG && !window.L_PREFER_CANVAS) || !L.Browser.canvas ? L.Path :
|
||||
},
|
||||
|
||||
onRemove: function (map) {
|
||||
map.off('viewreset', this._projectLatlngs, this);
|
||||
map.off(this._updateTrigger, this._updatePath, this);
|
||||
map.fire(this._updateTrigger);
|
||||
map
|
||||
.off('viewreset', this._projectLatlngs, this)
|
||||
.off('moveend', this._updatePath, this)
|
||||
.fire('moveend');
|
||||
}
|
||||
});
|
||||
|
||||
@ -124,12 +119,21 @@ L.Map.include((L.Path.SVG && !window.L_PREFER_CANVAS) || !L.Browser.canvas ? {}
|
||||
|
||||
this._panes.overlayPane.appendChild(root);
|
||||
|
||||
if (this.options.zoomAnimation) {
|
||||
this._pathRoot.className = 'leaflet-zoom-animated';
|
||||
this.on('zoomanim', this._animatePathZoom);
|
||||
this.on('zoomend', this._endPathZoom);
|
||||
}
|
||||
this.on('moveend', this._updateCanvasViewport);
|
||||
this._updateCanvasViewport();
|
||||
}
|
||||
},
|
||||
|
||||
_updateCanvasViewport: function () {
|
||||
if (this._pathZooming) {
|
||||
//Don't redraw while zooming. See _updateSvgViewport for more details
|
||||
return;
|
||||
}
|
||||
this._updatePathViewport();
|
||||
|
||||
var vp = this._pathViewport,
|
||||
@ -137,7 +141,7 @@ L.Map.include((L.Path.SVG && !window.L_PREFER_CANVAS) || !L.Browser.canvas ? {}
|
||||
size = vp.max.subtract(min),
|
||||
root = this._pathRoot;
|
||||
|
||||
//TODO check if it's works properly on mobile webkit
|
||||
//TODO check if this works properly on mobile webkit
|
||||
L.DomUtil.setPosition(root, min);
|
||||
root.width = size.x;
|
||||
root.height = size.y;
|
||||
|
368
src/map/Map.js
368
src/map/Map.js
@ -6,78 +6,36 @@ L.Map = L.Class.extend({
|
||||
includes: L.Mixin.Events,
|
||||
|
||||
options: {
|
||||
// projection
|
||||
crs: L.CRS.EPSG3857 || L.CRS.EPSG4326,
|
||||
scale: function (zoom) {
|
||||
return 256 * Math.pow(2, zoom);
|
||||
},
|
||||
crs: L.CRS.EPSG3857,
|
||||
|
||||
// state
|
||||
center: null,
|
||||
zoom: null,
|
||||
layers: [],
|
||||
/*
|
||||
center: LatLng,
|
||||
zoom: Number,
|
||||
layers: Array,
|
||||
*/
|
||||
|
||||
// interaction
|
||||
dragging: true,
|
||||
touchZoom: L.Browser.touch && !L.Browser.android,
|
||||
scrollWheelZoom: !L.Browser.touch,
|
||||
doubleClickZoom: true,
|
||||
boxZoom: true,
|
||||
|
||||
// controls
|
||||
zoomControl: true,
|
||||
attributionControl: true,
|
||||
|
||||
// animation
|
||||
fadeAnimation: L.DomUtil.TRANSITION && !L.Browser.android,
|
||||
zoomAnimation: L.DomUtil.TRANSITION && !L.Browser.android && !L.Browser.mobileOpera,
|
||||
|
||||
// misc
|
||||
trackResize: true,
|
||||
closePopupOnClick: true,
|
||||
worldCopyJump: true
|
||||
animateMarkerZoom: true
|
||||
},
|
||||
|
||||
|
||||
// constructor
|
||||
|
||||
initialize: function (id, options) { // (HTMLElement or String, Object)
|
||||
L.Util.setOptions(this, options);
|
||||
|
||||
this._container = L.DomUtil.get(id);
|
||||
|
||||
if (this._container._leaflet) {
|
||||
throw new Error("Map container is already initialized.");
|
||||
}
|
||||
this._container._leaflet = true;
|
||||
options = L.Util.setOptions(this, options);
|
||||
|
||||
this._initContainer(id);
|
||||
this._initLayout();
|
||||
this._initHooks();
|
||||
this._initEvents();
|
||||
|
||||
if (L.DomEvent) {
|
||||
this._initEvents();
|
||||
if (L.Handler) {
|
||||
this._initInteraction();
|
||||
}
|
||||
if (L.Control) {
|
||||
this._initControls();
|
||||
}
|
||||
if (options.maxBounds) {
|
||||
this.setMaxBounds(options.maxBounds);
|
||||
}
|
||||
|
||||
if (this.options.maxBounds) {
|
||||
this.setMaxBounds(this.options.maxBounds);
|
||||
if (options.center && typeof options.zoom !== 'undefined') {
|
||||
this.setView(options.center, options.zoom, true);
|
||||
}
|
||||
|
||||
var center = this.options.center,
|
||||
zoom = this.options.zoom;
|
||||
|
||||
if (center !== null && zoom !== null) {
|
||||
this.setView(center, zoom, true);
|
||||
}
|
||||
|
||||
var layers = this.options.layers;
|
||||
layers = (layers instanceof Array ? layers : [layers]);
|
||||
this._tileLayersNum = 0;
|
||||
this._initLayers(layers);
|
||||
this._initLayers(options.layers);
|
||||
},
|
||||
|
||||
|
||||
@ -85,7 +43,6 @@ L.Map = L.Class.extend({
|
||||
|
||||
// replaced by animation-powered implementation in Map.PanAnimation.js
|
||||
setView: function (center, zoom) {
|
||||
// reset the map view
|
||||
this._resetView(center, this._limitZoom(zoom));
|
||||
return this;
|
||||
},
|
||||
@ -109,7 +66,8 @@ L.Map = L.Class.extend({
|
||||
|
||||
fitWorld: function () {
|
||||
var sw = new L.LatLng(-60, -170),
|
||||
ne = new L.LatLng(85, 179);
|
||||
ne = new L.LatLng(85, 179);
|
||||
|
||||
return this.fitBounds(new L.LatLngBounds(sw, ne));
|
||||
},
|
||||
|
||||
@ -124,9 +82,7 @@ L.Map = L.Class.extend({
|
||||
this._rawPanBy(offset);
|
||||
|
||||
this.fire('move');
|
||||
this.fire('moveend');
|
||||
|
||||
return this;
|
||||
return this.fire('moveend');
|
||||
},
|
||||
|
||||
setMaxBounds: function (bounds) {
|
||||
@ -148,17 +104,18 @@ L.Map = L.Class.extend({
|
||||
this.panInsideBounds(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
panInsideBounds: function (bounds) {
|
||||
var viewBounds = this.getBounds(),
|
||||
viewSw = this.project(viewBounds.getSouthWest()),
|
||||
viewNe = this.project(viewBounds.getNorthEast()),
|
||||
sw = this.project(bounds.getSouthWest()),
|
||||
ne = this.project(bounds.getNorthEast()),
|
||||
dx = 0,
|
||||
dy = 0;
|
||||
viewSw = this.project(viewBounds.getSouthWest()),
|
||||
viewNe = this.project(viewBounds.getNorthEast()),
|
||||
sw = this.project(bounds.getSouthWest()),
|
||||
ne = this.project(bounds.getNorthEast()),
|
||||
dx = 0,
|
||||
dy = 0;
|
||||
|
||||
if (viewNe.y < ne.y) { // north
|
||||
dy = ne.y - viewNe.y;
|
||||
@ -177,28 +134,27 @@ L.Map = L.Class.extend({
|
||||
},
|
||||
|
||||
addLayer: function (layer, insertAtTheBottom) {
|
||||
// TODO method is too big, refactor
|
||||
|
||||
var id = L.Util.stamp(layer);
|
||||
|
||||
if (this._layers[id]) {
|
||||
return this;
|
||||
}
|
||||
if (this._layers[id]) { return this; }
|
||||
|
||||
this._layers[id] = layer;
|
||||
|
||||
// TODO getMaxZoom, getMinZoom in ILayer (instead of options)
|
||||
if (layer.options && !isNaN(layer.options.maxZoom)) {
|
||||
this._layersMaxZoom = Math.max(this._layersMaxZoom || 0, layer.options.maxZoom);
|
||||
}
|
||||
if (layer.options && !isNaN(layer.options.minZoom)) {
|
||||
this._layersMinZoom = Math.min(this._layersMinZoom || Infinity, layer.options.minZoom);
|
||||
}
|
||||
//TODO getMaxZoom, getMinZoom in ILayer (instead of options)
|
||||
|
||||
// TODO looks ugly, refactor!!!
|
||||
if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) {
|
||||
this._tileLayersNum++;
|
||||
layer.on('load', this._onTileLayerLoad, this);
|
||||
}
|
||||
if (this.attributionControl && layer.getAttribution) {
|
||||
this.attributionControl.addAttribution(layer.getAttribution());
|
||||
this._tileLayersToLoad++;
|
||||
layer.on('load', this._onTileLayerLoad, this);
|
||||
}
|
||||
|
||||
var onMapLoad = function () {
|
||||
@ -218,21 +174,20 @@ L.Map = L.Class.extend({
|
||||
removeLayer: function (layer) {
|
||||
var id = L.Util.stamp(layer);
|
||||
|
||||
if (this._layers[id]) {
|
||||
layer.onRemove(this);
|
||||
delete this._layers[id];
|
||||
if (!this._layers[id]) { return; }
|
||||
|
||||
if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) {
|
||||
this._tileLayersNum--;
|
||||
layer.off('load', this._onTileLayerLoad, this);
|
||||
}
|
||||
if (this.attributionControl && layer.getAttribution) {
|
||||
this.attributionControl.removeAttribution(layer.getAttribution());
|
||||
}
|
||||
layer.onRemove(this);
|
||||
|
||||
this.fire('layerremove', {layer: layer});
|
||||
delete this._layers[id];
|
||||
|
||||
// TODO looks ugly, refactor
|
||||
if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) {
|
||||
this._tileLayersNum--;
|
||||
this._tileLayersToLoad--;
|
||||
layer.off('load', this._onTileLayerLoad, this);
|
||||
}
|
||||
return this;
|
||||
|
||||
return this.fire('layerremove', {layer: layer});
|
||||
},
|
||||
|
||||
hasLayer: function (layer) {
|
||||
@ -249,18 +204,28 @@ L.Map = L.Class.extend({
|
||||
this.setMaxBounds(this.options.maxBounds);
|
||||
}
|
||||
|
||||
if (!this._loaded) {
|
||||
return this;
|
||||
}
|
||||
if (!this._loaded) { return this; }
|
||||
|
||||
this._rawPanBy(oldSize.subtract(this.getSize()).divideBy(2, true));
|
||||
var offset = oldSize.subtract(this.getSize()).divideBy(2, true);
|
||||
this._rawPanBy(offset);
|
||||
|
||||
this.fire('move');
|
||||
|
||||
clearTimeout(this._sizeTimer);
|
||||
this._sizeTimer = setTimeout(L.Util.bind(function () {
|
||||
this.fire('moveend');
|
||||
}, this), 200);
|
||||
this._sizeTimer = setTimeout(L.Util.bind(this.fire, this, 'moveend'), 200);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
// TODO handler.addTo
|
||||
addHandler: function (name, HandlerClass) {
|
||||
if (!HandlerClass) { return; }
|
||||
|
||||
this[name] = new HandlerClass(this);
|
||||
|
||||
if (this.options[name]) {
|
||||
this[name].enable();
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
@ -268,9 +233,10 @@ L.Map = L.Class.extend({
|
||||
|
||||
// public methods for getting map state
|
||||
|
||||
getCenter: function (unbounded) { // (Boolean)
|
||||
getCenter: function (unbounded) { // (Boolean) -> LatLng
|
||||
var viewHalf = this.getSize().divideBy(2),
|
||||
centerPoint = this._getTopLeftPoint().add(viewHalf);
|
||||
centerPoint = this._getTopLeftPoint().add(viewHalf);
|
||||
|
||||
return this.unproject(centerPoint, this._zoom, unbounded);
|
||||
},
|
||||
|
||||
@ -280,36 +246,37 @@ L.Map = L.Class.extend({
|
||||
|
||||
getBounds: function () {
|
||||
var bounds = this.getPixelBounds(),
|
||||
sw = this.unproject(new L.Point(bounds.min.x, bounds.max.y), this._zoom, true),
|
||||
ne = this.unproject(new L.Point(bounds.max.x, bounds.min.y), this._zoom, true);
|
||||
sw = this.unproject(new L.Point(bounds.min.x, bounds.max.y), this._zoom, true),
|
||||
ne = this.unproject(new L.Point(bounds.max.x, bounds.min.y), this._zoom, true);
|
||||
|
||||
return new L.LatLngBounds(sw, ne);
|
||||
},
|
||||
|
||||
getMinZoom: function () {
|
||||
var z1 = this.options.minZoom || 0,
|
||||
z2 = this._layersMinZoom || 0,
|
||||
z3 = this._boundsMinZoom || 0;
|
||||
z2 = this._layersMinZoom || 0,
|
||||
z3 = this._boundsMinZoom || 0;
|
||||
|
||||
return Math.max(z1, z2, z3);
|
||||
},
|
||||
|
||||
getMaxZoom: function () {
|
||||
var z1 = isNaN(this.options.maxZoom) ? Infinity : this.options.maxZoom,
|
||||
z2 = this._layersMaxZoom || Infinity;
|
||||
var z1 = typeof this.options.maxZoom === 'undefined' ? Infinity : this.options.maxZoom,
|
||||
z2 = typeof this._layersMaxZoom === 'undefined' ? Infinity : this._layersMaxZoom;
|
||||
|
||||
return Math.min(z1, z2);
|
||||
},
|
||||
|
||||
getBoundsZoom: function (bounds, inside) { // (LatLngBounds)
|
||||
getBoundsZoom: function (bounds, inside) { // (LatLngBounds, Boolean) -> Number
|
||||
var size = this.getSize(),
|
||||
zoom = this.options.minZoom || 0,
|
||||
maxZoom = this.getMaxZoom(),
|
||||
ne = bounds.getNorthEast(),
|
||||
sw = bounds.getSouthWest(),
|
||||
boundsSize,
|
||||
nePoint,
|
||||
swPoint,
|
||||
zoomNotFound = true;
|
||||
zoom = this.options.minZoom || 0,
|
||||
maxZoom = this.getMaxZoom(),
|
||||
ne = bounds.getNorthEast(),
|
||||
sw = bounds.getSouthWest(),
|
||||
boundsSize,
|
||||
nePoint,
|
||||
swPoint,
|
||||
zoomNotFound = true;
|
||||
|
||||
if (inside) {
|
||||
zoom--;
|
||||
@ -322,11 +289,11 @@ L.Map = L.Class.extend({
|
||||
boundsSize = new L.Point(nePoint.x - swPoint.x, swPoint.y - nePoint.y);
|
||||
|
||||
if (!inside) {
|
||||
zoomNotFound = (boundsSize.x <= size.x) && (boundsSize.y <= size.y);
|
||||
zoomNotFound = boundsSize.x <= size.x && boundsSize.y <= size.y;
|
||||
} else {
|
||||
zoomNotFound = (boundsSize.x < size.x) || (boundsSize.y < size.y);
|
||||
zoomNotFound = boundsSize.x < size.x || boundsSize.y < size.y;
|
||||
}
|
||||
} while (zoomNotFound && (zoom <= maxZoom));
|
||||
} while (zoomNotFound && zoom <= maxZoom);
|
||||
|
||||
if (zoomNotFound && inside) {
|
||||
return null;
|
||||
@ -337,16 +304,18 @@ L.Map = L.Class.extend({
|
||||
|
||||
getSize: function () {
|
||||
if (!this._size || this._sizeChanged) {
|
||||
this._size = new L.Point(this._container.clientWidth, this._container.clientHeight);
|
||||
this._size = new L.Point(
|
||||
this._container.clientWidth,
|
||||
this._container.clientHeight);
|
||||
|
||||
this._sizeChanged = false;
|
||||
}
|
||||
return this._size;
|
||||
},
|
||||
|
||||
getPixelBounds: function () {
|
||||
var topLeftPoint = this._getTopLeftPoint(),
|
||||
size = this.getSize();
|
||||
return new L.Bounds(topLeftPoint, topLeftPoint.add(size));
|
||||
var topLeftPoint = this._getTopLeftPoint();
|
||||
return new L.Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
|
||||
},
|
||||
|
||||
getPixelOrigin: function () {
|
||||
@ -356,6 +325,10 @@ L.Map = L.Class.extend({
|
||||
getPanes: function () {
|
||||
return this._panes;
|
||||
},
|
||||
|
||||
getContainer: function () {
|
||||
return this._container;
|
||||
},
|
||||
|
||||
|
||||
// conversion methods
|
||||
@ -388,32 +361,55 @@ L.Map = L.Class.extend({
|
||||
return this.project(latlng)._round()._subtract(this._initialTopLeftPoint);
|
||||
},
|
||||
|
||||
containerPointToLatLng: function (point) {
|
||||
return this.layerPointToLatLng(this.containerPointToLayerPoint(point));
|
||||
},
|
||||
|
||||
latLngToContainerPoint: function (latlng) {
|
||||
return this.layerPointToContainerPoint(this.latLngToLayerPoint(latlng));
|
||||
},
|
||||
|
||||
project: function (latlng, zoom) { // (LatLng[, Number]) -> Point
|
||||
zoom = (typeof zoom === 'undefined' ? this._zoom : zoom);
|
||||
return this.options.crs.latLngToPoint(latlng, this.options.scale(zoom));
|
||||
zoom = typeof zoom === 'undefined' ? this._zoom : zoom;
|
||||
return this.options.crs.latLngToPoint(latlng, zoom);
|
||||
},
|
||||
|
||||
unproject: function (point, zoom, unbounded) { // (Point[, Number, Boolean]) -> LatLng
|
||||
zoom = (typeof zoom === 'undefined' ? this._zoom : zoom);
|
||||
return this.options.crs.pointToLatLng(point, this.options.scale(zoom), unbounded);
|
||||
// TODO remove unbounded, making it true all the time?
|
||||
zoom = typeof zoom === 'undefined' ? this._zoom : zoom;
|
||||
return this.options.crs.pointToLatLng(point, zoom, unbounded);
|
||||
},
|
||||
|
||||
|
||||
// private methods that modify map state
|
||||
|
||||
_initContainer: function (id) {
|
||||
var container = this._container = L.DomUtil.get(id);
|
||||
|
||||
if (container._leaflet) {
|
||||
throw new Error("Map container is already initialized.");
|
||||
}
|
||||
|
||||
container._leaflet = true;
|
||||
},
|
||||
|
||||
_initLayout: function () {
|
||||
var container = this._container;
|
||||
|
||||
container.innerHTML = '';
|
||||
|
||||
container.className += ' leaflet-container';
|
||||
|
||||
if (L.Browser.touch) {
|
||||
container.className += ' leaflet-touch';
|
||||
}
|
||||
|
||||
if (this.options.fadeAnimation) {
|
||||
container.className += ' leaflet-fade-anim';
|
||||
}
|
||||
|
||||
var position = L.DomUtil.getStyle(container, 'position');
|
||||
if (position !== 'absolute' && position !== 'relative') {
|
||||
|
||||
if (position !== 'absolute' && position !== 'relative' && position !== 'fixed') {
|
||||
container.style.position = 'relative';
|
||||
}
|
||||
|
||||
@ -436,13 +432,29 @@ L.Map = L.Class.extend({
|
||||
panes.overlayPane = this._createPane('leaflet-overlay-pane');
|
||||
panes.markerPane = this._createPane('leaflet-marker-pane');
|
||||
panes.popupPane = this._createPane('leaflet-popup-pane');
|
||||
|
||||
if (!this.options.animateMarkerZoom) {
|
||||
panes.markerPane.className += ' leaflet-zoom-hide';
|
||||
panes.shadowPane.className += ' leaflet-zoom-hide';
|
||||
panes.popupPane.className += ' leaflet-zoom-hide';
|
||||
}
|
||||
},
|
||||
|
||||
_createPane: function (className, container) {
|
||||
return L.DomUtil.create('div', className, container || this._objectsPane);
|
||||
},
|
||||
|
||||
_initializers: [],
|
||||
|
||||
_initHooks: function () {
|
||||
var i, len;
|
||||
for (i = 0, len = this._initializers.length; i < len; i++) {
|
||||
this._initializers[i].call(this);
|
||||
}
|
||||
},
|
||||
|
||||
_resetView: function (center, zoom, preserveMapOffset, afterZoomAnim) {
|
||||
|
||||
var zoomChanged = (this._zoom !== zoom);
|
||||
|
||||
if (!afterZoomAnim) {
|
||||
@ -460,17 +472,19 @@ L.Map = L.Class.extend({
|
||||
if (!preserveMapOffset) {
|
||||
L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0));
|
||||
} else {
|
||||
var offset = L.DomUtil.getPosition(this._mapPane);
|
||||
this._initialTopLeftPoint._add(offset);
|
||||
this._initialTopLeftPoint._add(L.DomUtil.getPosition(this._mapPane));
|
||||
}
|
||||
|
||||
this._tileLayersToLoad = this._tileLayersNum;
|
||||
|
||||
this.fire('viewreset', {hard: !preserveMapOffset});
|
||||
|
||||
this.fire('move');
|
||||
|
||||
if (zoomChanged || afterZoomAnim) {
|
||||
this.fire('zoomend');
|
||||
}
|
||||
|
||||
this.fire('moveend');
|
||||
|
||||
if (!this._loaded) {
|
||||
@ -480,7 +494,10 @@ L.Map = L.Class.extend({
|
||||
},
|
||||
|
||||
_initLayers: function (layers) {
|
||||
layers = layers ? (layers instanceof Array ? layers : [layers]) : [];
|
||||
|
||||
this._layers = {};
|
||||
this._tileLayersNum = 0;
|
||||
|
||||
var i, len;
|
||||
|
||||
@ -489,28 +506,17 @@ L.Map = L.Class.extend({
|
||||
}
|
||||
},
|
||||
|
||||
_initControls: function () {
|
||||
// TODO refactor, this should happen automatically
|
||||
|
||||
if (this.options.zoomControl) {
|
||||
this.zoomControl = new L.Control.Zoom();
|
||||
this.addControl(this.zoomControl);
|
||||
}
|
||||
if (this.options.attributionControl) {
|
||||
this.attributionControl = new L.Control.Attribution();
|
||||
this.addControl(this.attributionControl);
|
||||
}
|
||||
},
|
||||
|
||||
_rawPanBy: function (offset) {
|
||||
var mapPaneOffset = L.DomUtil.getPosition(this._mapPane);
|
||||
L.DomUtil.setPosition(this._mapPane, mapPaneOffset.subtract(offset));
|
||||
var newPos = L.DomUtil.getPosition(this._mapPane).subtract(offset);
|
||||
L.DomUtil.setPosition(this._mapPane, newPos);
|
||||
},
|
||||
|
||||
|
||||
// map events
|
||||
|
||||
_initEvents: function () {
|
||||
if (!L.DomEvent) { return; }
|
||||
|
||||
L.DomEvent.addListener(this._container, 'click', this._onMouseClick, this);
|
||||
|
||||
var events = ['dblclick', 'mousedown', 'mouseenter', 'mouseleave', 'mousemove', 'contextmenu'];
|
||||
@ -531,58 +537,39 @@ L.Map = L.Class.extend({
|
||||
},
|
||||
|
||||
_onMouseClick: function (e) {
|
||||
if (!this._loaded || (this.dragging && this.dragging.moved())) {
|
||||
return;
|
||||
}
|
||||
if (!this._loaded || (this.dragging && this.dragging.moved())) { return; }
|
||||
|
||||
this.fire('pre' + e.type);
|
||||
this._fireMouseEvent(e);
|
||||
},
|
||||
|
||||
_fireMouseEvent: function (e) {
|
||||
if (!this._loaded) {
|
||||
return;
|
||||
}
|
||||
if (!this._loaded) { return; }
|
||||
|
||||
var type = e.type;
|
||||
|
||||
type = (type === 'mouseenter' ? 'mouseover' : (type === 'mouseleave' ? 'mouseout' : type));
|
||||
|
||||
if (!this.hasEventListeners(type)) {
|
||||
return;
|
||||
}
|
||||
if (!this.hasEventListeners(type)) { return; }
|
||||
|
||||
if (type === 'contextmenu') {
|
||||
L.DomEvent.preventDefault(e);
|
||||
}
|
||||
|
||||
var containerPoint = this.mouseEventToContainerPoint(e),
|
||||
layerPoint = this.containerPointToLayerPoint(containerPoint),
|
||||
latlng = this.layerPointToLatLng(layerPoint);
|
||||
|
||||
this.fire(type, {
|
||||
latlng: this.mouseEventToLatLng(e),
|
||||
layerPoint: this.mouseEventToLayerPoint(e)
|
||||
latlng: latlng,
|
||||
layerPoint: layerPoint,
|
||||
containerPoint: containerPoint,
|
||||
originalEvent: e
|
||||
});
|
||||
},
|
||||
|
||||
_initInteraction: function () {
|
||||
var handlers = {
|
||||
dragging: L.Map.Drag,
|
||||
touchZoom: L.Map.TouchZoom,
|
||||
doubleClickZoom: L.Map.DoubleClickZoom,
|
||||
scrollWheelZoom: L.Map.ScrollWheelZoom,
|
||||
boxZoom: L.Map.BoxZoom
|
||||
};
|
||||
|
||||
var i;
|
||||
for (i in handlers) {
|
||||
if (handlers.hasOwnProperty(i) && handlers[i]) {
|
||||
this[i] = new handlers[i](this);
|
||||
if (this.options[i]) {
|
||||
this[i].enable();
|
||||
}
|
||||
// TODO move enabling to handler contructor
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onTileLayerLoad: function () {
|
||||
// TODO super-ugly, refactor!!!
|
||||
// clear scaled tiles after all new tiles are loaded (for performance)
|
||||
this._tileLayersToLoad--;
|
||||
if (this._tileLayersNum && !this._tileLayersToLoad && this._tileBg) {
|
||||
@ -599,18 +586,37 @@ L.Map = L.Class.extend({
|
||||
throw new Error('Set map center and zoom first.');
|
||||
}
|
||||
|
||||
var offset = L.DomUtil.getPosition(this._mapPane);
|
||||
return this._initialTopLeftPoint.subtract(offset);
|
||||
var mapPanePos = L.DomUtil.getPosition(this._mapPane);
|
||||
return this._initialTopLeftPoint.subtract(mapPanePos);
|
||||
},
|
||||
|
||||
_getNewTopLeftPoint: function (center) {
|
||||
_getNewTopLeftPoint: function (center, zoom) {
|
||||
var viewHalf = this.getSize().divideBy(2);
|
||||
return this.project(center).subtract(viewHalf).round();
|
||||
// TODO round on display, not calculation to increase precision?
|
||||
return this.project(center, zoom)._subtract(viewHalf)._round();
|
||||
},
|
||||
|
||||
_latLngToNewLayerPoint: function (latlng, newZoom, newCenter) {
|
||||
var mapPaneOffset = L.DomUtil.getPosition(this._mapPane),
|
||||
topLeft = this._getNewTopLeftPoint(newCenter, newZoom).add(mapPaneOffset);
|
||||
|
||||
return this.project(latlng, newZoom)._round()._subtract(topLeft);
|
||||
},
|
||||
|
||||
_limitZoom: function (zoom) {
|
||||
var min = this.getMinZoom();
|
||||
var max = this.getMaxZoom();
|
||||
var min = this.getMinZoom(),
|
||||
max = this.getMaxZoom();
|
||||
|
||||
return Math.max(min, Math.min(max, zoom));
|
||||
}
|
||||
});
|
||||
|
||||
L.Map.addInitHook = function (fn) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
|
||||
var init = typeof fn === 'function' ? fn : function () {
|
||||
this[fn].apply(this, args);
|
||||
};
|
||||
|
||||
this.prototype._initializers.push(init);
|
||||
};
|
@ -1,6 +1,8 @@
|
||||
|
||||
L.Map.include(!(L.Transition && L.Transition.implemented()) ? {} : {
|
||||
setView: function (center, zoom, forceReset) {
|
||||
zoom = this._limitZoom(zoom);
|
||||
|
||||
var zoomChanged = (this._zoom !== zoom);
|
||||
|
||||
if (this._loaded && !forceReset && this._layers) {
|
||||
@ -10,8 +12,8 @@ L.Map.include(!(L.Transition && L.Transition.implemented()) ? {} : {
|
||||
center = new L.LatLng(center.lat, center.lng);
|
||||
|
||||
var done = (zoomChanged ?
|
||||
!!this._zoomToIfCenterInView && this._zoomToIfCenterInView(center, zoom, offset) :
|
||||
this._panByIfClose(offset));
|
||||
this._zoomToIfCenterInView && this._zoomToIfCenterInView(center, zoom, offset) :
|
||||
this._panByIfClose(offset));
|
||||
|
||||
// exit if animated pan or zoom started
|
||||
if (done) {
|
||||
@ -25,19 +27,24 @@ L.Map.include(!(L.Transition && L.Transition.implemented()) ? {} : {
|
||||
return this;
|
||||
},
|
||||
|
||||
panBy: function (offset) {
|
||||
panBy: function (offset, options) {
|
||||
if (!(offset.x || offset.y)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (!this._panTransition) {
|
||||
this._panTransition = new L.Transition(this._mapPane, {duration: 0.3});
|
||||
this._panTransition = new L.Transition(this._mapPane);
|
||||
|
||||
this._panTransition.on('step', this._onPanTransitionStep, this);
|
||||
this._panTransition.on('end', this._onPanTransitionEnd, this);
|
||||
}
|
||||
|
||||
L.Util.setOptions(this._panTransition, L.Util.extend({duration: 0.25}, options));
|
||||
|
||||
this.fire('movestart');
|
||||
|
||||
this._mapPane.className += ' leaflet-pan-anim';
|
||||
|
||||
this._panTransition.run({
|
||||
position: L.DomUtil.getPosition(this._mapPane).subtract(offset)
|
||||
});
|
||||
@ -50,6 +57,7 @@ L.Map.include(!(L.Transition && L.Transition.implemented()) ? {} : {
|
||||
},
|
||||
|
||||
_onPanTransitionEnd: function () {
|
||||
this._mapPane.className = this._mapPane.className.replace(/ leaflet-pan-anim/g, '');
|
||||
this.fire('moveend');
|
||||
},
|
||||
|
||||
@ -64,6 +72,7 @@ L.Map.include(!(L.Transition && L.Transition.implemented()) ? {} : {
|
||||
_offsetIsWithinView: function (offset, multiplyFactor) {
|
||||
var m = multiplyFactor || 1,
|
||||
size = this.getSize();
|
||||
|
||||
return (Math.abs(offset.x) <= size.x * m) &&
|
||||
(Math.abs(offset.y) <= size.y * m);
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
L.Map.mergeOptions({
|
||||
zoomAnimation: L.DomUtil.TRANSITION && !L.Browser.android && !L.Browser.mobileOpera
|
||||
});
|
||||
|
||||
L.Map.include(!L.DomUtil.TRANSITION ? {} : {
|
||||
_zoomToIfCenterInView: function (center, zoom, centerOffset) {
|
||||
|
||||
@ -8,107 +12,146 @@ L.Map.include(!L.DomUtil.TRANSITION ? {} : {
|
||||
return false;
|
||||
}
|
||||
|
||||
var zoomDelta = zoom - this._zoom,
|
||||
scale = Math.pow(2, zoomDelta),
|
||||
var scale = Math.pow(2, zoom - this._zoom),
|
||||
offset = centerOffset.divideBy(1 - 1 / scale);
|
||||
|
||||
//if offset does not exceed half of the view
|
||||
// if offset does not exceed half of the view
|
||||
if (!this._offsetIsWithinView(offset, 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._mapPane.className += ' leaflet-zoom-anim';
|
||||
|
||||
this
|
||||
this
|
||||
.fire('movestart')
|
||||
.fire('zoomstart');
|
||||
|
||||
//Hack: Disable this for android due to it not supporting double translate (mentioned in _runAnimation below)
|
||||
//if Foreground layer doesn't have many tiles but bg layer does, keep the existing bg layer
|
||||
if (!L.Browser.android && this._tileBg && this._getLoadedTilesPercentage(this._tileBg) > 0.5 && this._getLoadedTilesPercentage(this._tilePane) < 0.5) {
|
||||
//Leave current bg and just zoom it some more
|
||||
|
||||
this._tilePane.style.visibility = 'hidden';
|
||||
this._tilePane.empty = true;
|
||||
this._stopLoadingImages(this._tilePane);
|
||||
} else {
|
||||
this._prepareTileBg();
|
||||
}
|
||||
|
||||
var centerPoint = this.containerPointToLayerPoint(this.getSize().divideBy(2)),
|
||||
origin = centerPoint.add(offset);
|
||||
|
||||
this._prepareTileBg();
|
||||
|
||||
this.fire('zoomanim', {
|
||||
center: center,
|
||||
zoom: zoom
|
||||
});
|
||||
|
||||
this._runAnimation(center, zoom, scale, origin);
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
|
||||
_runAnimation: function (center, zoom, scale, origin) {
|
||||
_runAnimation: function (center, zoom, scale, origin, backwardsTransform) {
|
||||
this._animatingZoom = true;
|
||||
|
||||
this._animateToCenter = center;
|
||||
this._animateToZoom = zoom;
|
||||
|
||||
var transform = L.DomUtil.TRANSFORM;
|
||||
var transform = L.DomUtil.TRANSFORM,
|
||||
tileBg = this._tileBg;
|
||||
|
||||
clearTimeout(this._clearTileBgTimer);
|
||||
|
||||
//dumb FireFox hack, I have no idea why this magic zero translate fixes the scale transition problem
|
||||
if (L.Browser.gecko || window.opera) {
|
||||
this._tileBg.style[transform] += ' translate(0,0)';
|
||||
tileBg.style[transform] += ' translate(0,0)';
|
||||
}
|
||||
|
||||
var scaleStr;
|
||||
|
||||
// Android doesn't like translate/scale chains, transformOrigin + scale works better but
|
||||
// Android 2.* doesn't like translate/scale chains, transformOrigin + scale works better but
|
||||
// it breaks touch zoom which Anroid doesn't support anyway, so that's a really ugly hack
|
||||
|
||||
// TODO work around this prettier
|
||||
if (L.Browser.android) {
|
||||
this._tileBg.style[transform + 'Origin'] = origin.x + 'px ' + origin.y + 'px';
|
||||
tileBg.style[transform + 'Origin'] = origin.x + 'px ' + origin.y + 'px';
|
||||
scaleStr = 'scale(' + scale + ')';
|
||||
} else {
|
||||
scaleStr = L.DomUtil.getScaleString(scale, origin);
|
||||
}
|
||||
|
||||
L.Util.falseFn(this._tileBg.offsetWidth); //hack to make sure transform is updated before running animation
|
||||
L.Util.falseFn(tileBg.offsetWidth); //hack to make sure transform is updated before running animation
|
||||
|
||||
var options = {};
|
||||
options[transform] = this._tileBg.style[transform] + ' ' + scaleStr;
|
||||
this._tileBg.transition.run(options);
|
||||
if (backwardsTransform) {
|
||||
options[transform] = tileBg.style[transform] + ' ' + scaleStr;
|
||||
} else {
|
||||
options[transform] = scaleStr + ' ' + tileBg.style[transform];
|
||||
}
|
||||
|
||||
tileBg.transition.run(options);
|
||||
},
|
||||
|
||||
_prepareTileBg: function () {
|
||||
if (!this._tileBg) {
|
||||
this._tileBg = this._createPane('leaflet-tile-pane', this._mapPane);
|
||||
this._tileBg.style.zIndex = 1;
|
||||
}
|
||||
|
||||
var tilePane = this._tilePane,
|
||||
tileBg = this._tileBg;
|
||||
|
||||
if (!tileBg) {
|
||||
tileBg = this._tileBg = this._createPane('leaflet-tile-pane', this._mapPane);
|
||||
tileBg.style.zIndex = 1;
|
||||
}
|
||||
|
||||
// prepare the background pane to become the main tile pane
|
||||
//tileBg.innerHTML = '';
|
||||
tileBg.style[L.DomUtil.TRANSFORM] = '';
|
||||
tileBg.style.visibility = 'hidden';
|
||||
|
||||
// tells tile layers to reinitialize their containers
|
||||
tileBg.empty = true;
|
||||
tilePane.empty = false;
|
||||
tileBg.empty = true; //new FG
|
||||
tilePane.empty = false; //new BG
|
||||
|
||||
//Switch out the current layer to be the new bg layer (And vice-versa)
|
||||
this._tilePane = this._panes.tilePane = tileBg;
|
||||
this._tileBg = tilePane;
|
||||
var newTileBg = this._tileBg = tilePane;
|
||||
|
||||
if (!this._tileBg.transition) {
|
||||
this._tileBg.transition = new L.Transition(this._tileBg, {duration: 0.3, easing: 'cubic-bezier(0.25,0.1,0.25,0.75)'});
|
||||
this._tileBg.transition.on('end', this._onZoomTransitionEnd, this);
|
||||
if (!newTileBg.transition) {
|
||||
// TODO move to Map options
|
||||
newTileBg.transition = new L.Transition(newTileBg, {
|
||||
duration: 0.25,
|
||||
easing: 'cubic-bezier(0.25,0.1,0.25,0.75)'
|
||||
});
|
||||
newTileBg.transition.on('end', this._onZoomTransitionEnd, this);
|
||||
}
|
||||
|
||||
this._stopLoadingBgTiles();
|
||||
this._stopLoadingImages(newTileBg);
|
||||
},
|
||||
|
||||
_getLoadedTilesPercentage: function (container) {
|
||||
var tiles = Array.prototype.slice.call(container.getElementsByTagName('img')),
|
||||
i, len, count = 0;
|
||||
|
||||
for (i = 0, len = tiles.length; i < len; i++) {
|
||||
if (tiles[i].complete) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count / len;
|
||||
},
|
||||
|
||||
// stops loading all tiles in the background layer
|
||||
_stopLoadingBgTiles: function () {
|
||||
var tiles = [].slice.call(this._tileBg.getElementsByTagName('img'));
|
||||
_stopLoadingImages: function (container) {
|
||||
var tiles = Array.prototype.slice.call(container.getElementsByTagName('img')),
|
||||
i, len, tile;
|
||||
|
||||
for (var i = 0, len = tiles.length; i < len; i++) {
|
||||
if (!tiles[i].complete) {
|
||||
tiles[i].onload = L.Util.falseFn;
|
||||
tiles[i].onerror = L.Util.falseFn;
|
||||
tiles[i].src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
|
||||
for (i = 0, len = tiles.length; i < len; i++) {
|
||||
tile = tiles[i];
|
||||
|
||||
tiles[i].parentNode.removeChild(tiles[i]);
|
||||
tiles[i] = null;
|
||||
if (!tile.complete) {
|
||||
tile.onload = L.Util.falseFn;
|
||||
tile.onerror = L.Util.falseFn;
|
||||
tile.src = L.Util.emptyImageUrl;
|
||||
|
||||
tile.parentNode.removeChild(tile);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1,52 +1,30 @@
|
||||
L.Map.include({
|
||||
addControl: function (control) {
|
||||
var container = control.onAdd(this);
|
||||
|
||||
control._container = container;
|
||||
control._map = this;
|
||||
|
||||
var pos = control.getPosition(),
|
||||
corner = this._controlCorners[pos];
|
||||
|
||||
L.DomUtil.addClass(container, 'leaflet-control');
|
||||
|
||||
if (pos.indexOf('bottom') !== -1) {
|
||||
corner.insertBefore(container, corner.firstChild);
|
||||
} else {
|
||||
corner.appendChild(container);
|
||||
}
|
||||
control.addTo(this);
|
||||
return this;
|
||||
},
|
||||
|
||||
removeControl: function (control) {
|
||||
var pos = control.getPosition(),
|
||||
corner = this._controlCorners[pos];
|
||||
|
||||
corner.removeChild(control._container);
|
||||
control._map = null;
|
||||
|
||||
if (control.onRemove) {
|
||||
control.onRemove(this);
|
||||
}
|
||||
control.removeFrom(this);
|
||||
return this;
|
||||
},
|
||||
|
||||
_initControlPos: function () {
|
||||
var corners = this._controlCorners = {},
|
||||
classPart = 'leaflet-',
|
||||
top = classPart + 'top',
|
||||
bottom = classPart + 'bottom',
|
||||
left = classPart + 'left',
|
||||
right = classPart + 'right',
|
||||
controlContainer = L.DomUtil.create('div', classPart + 'control-container', this._container);
|
||||
l = 'leaflet-',
|
||||
container = this._controlContainer =
|
||||
L.DomUtil.create('div', l + 'control-container', this._container);
|
||||
|
||||
if (L.Browser.touch) {
|
||||
controlContainer.className += ' ' + classPart + 'big-buttons';
|
||||
function createCorner(vSide, hSide) {
|
||||
var className = l + vSide + ' ' + l + hSide;
|
||||
|
||||
corners[vSide + hSide] =
|
||||
L.DomUtil.create('div', className, container);
|
||||
}
|
||||
|
||||
corners.topleft = L.DomUtil.create('div', top + ' ' + left, controlContainer);
|
||||
corners.topright = L.DomUtil.create('div', top + ' ' + right, controlContainer);
|
||||
corners.bottomleft = L.DomUtil.create('div', bottom + ' ' + left, controlContainer);
|
||||
corners.bottomright = L.DomUtil.create('div', bottom + ' ' + right, controlContainer);
|
||||
createCorner('top', 'left');
|
||||
createCorner('top', 'right');
|
||||
createCorner('bottom', 'left');
|
||||
createCorner('bottom', 'right');
|
||||
}
|
||||
});
|
||||
|
@ -3,16 +3,18 @@
|
||||
*/
|
||||
|
||||
L.Map.include({
|
||||
_defaultLocateOptions: {
|
||||
watch: false,
|
||||
setView: false,
|
||||
maxZoom: Infinity,
|
||||
timeout: 10000,
|
||||
maximumAge: 0,
|
||||
enableHighAccuracy: false
|
||||
},
|
||||
|
||||
locate: function (/*Object*/ options) {
|
||||
|
||||
this._locationOptions = options = L.Util.extend({
|
||||
watch: false,
|
||||
setView: false,
|
||||
maxZoom: Infinity,
|
||||
timeout: 10000,
|
||||
maximumAge: 0,
|
||||
enableHighAccuracy: false
|
||||
}, options);
|
||||
options = this._locationOptions = L.Util.extend(this._defaultLocateOptions, options);
|
||||
|
||||
if (!navigator.geolocation) {
|
||||
return this.fire('locationerror', {
|
||||
@ -36,19 +38,13 @@ L.Map.include({
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.clearWatch(this._locationWatchId);
|
||||
}
|
||||
},
|
||||
|
||||
locateAndSetView: function (maxZoom, options) {
|
||||
options = L.Util.extend({
|
||||
maxZoom: maxZoom || Infinity,
|
||||
setView: true
|
||||
}, options);
|
||||
return this.locate(options);
|
||||
return this;
|
||||
},
|
||||
|
||||
_handleGeolocationError: function (error) {
|
||||
var c = error.code,
|
||||
message = (c === 1 ? "permission denied" :
|
||||
message =
|
||||
(c === 1 ? "permission denied" :
|
||||
(c === 2 ? "position unavailable" : "timeout"));
|
||||
|
||||
if (this._locationOptions.setView && !this._loaded) {
|
||||
@ -64,16 +60,19 @@ L.Map.include({
|
||||
_handleGeolocationResponse: function (pos) {
|
||||
var latAccuracy = 180 * pos.coords.accuracy / 4e7,
|
||||
lngAccuracy = latAccuracy * 2,
|
||||
|
||||
lat = pos.coords.latitude,
|
||||
lng = pos.coords.longitude,
|
||||
latlng = new L.LatLng(lat, lng);
|
||||
latlng = new L.LatLng(lat, lng),
|
||||
|
||||
var sw = new L.LatLng(lat - latAccuracy, lng - lngAccuracy),
|
||||
sw = new L.LatLng(lat - latAccuracy, lng - lngAccuracy),
|
||||
ne = new L.LatLng(lat + latAccuracy, lng + lngAccuracy),
|
||||
bounds = new L.LatLngBounds(sw, ne);
|
||||
bounds = new L.LatLngBounds(sw, ne),
|
||||
|
||||
if (this._locationOptions.setView) {
|
||||
var zoom = Math.min(this.getBoundsZoom(bounds), this._locationOptions.maxZoom);
|
||||
options = this._locationOptions;
|
||||
|
||||
if (options.setView) {
|
||||
var zoom = Math.min(this.getBoundsZoom(bounds), options.maxZoom);
|
||||
this.setView(latlng, zoom);
|
||||
}
|
||||
|
||||
|
@ -2,19 +2,18 @@
|
||||
L.Map.include({
|
||||
openPopup: function (popup) {
|
||||
this.closePopup();
|
||||
|
||||
this._popup = popup;
|
||||
this.addLayer(popup);
|
||||
this.fire('popupopen', { popup: this._popup });
|
||||
|
||||
return this;
|
||||
|
||||
return this
|
||||
.addLayer(popup)
|
||||
.fire('popupopen', {popup: this._popup});
|
||||
},
|
||||
|
||||
closePopup: function () {
|
||||
if (this._popup) {
|
||||
this.removeLayer(this._popup);
|
||||
this.fire('popupclose', { popup: this._popup });
|
||||
this._popup = null;
|
||||
this._popup._close();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
});
|
||||
});
|
@ -2,6 +2,10 @@
|
||||
* L.Handler.ShiftDragZoom is used internally by L.Map to add shift-drag zoom (zoom to a selected bounding box).
|
||||
*/
|
||||
|
||||
L.Map.mergeOptions({
|
||||
boxZoom: true
|
||||
});
|
||||
|
||||
L.Map.BoxZoom = L.Handler.extend({
|
||||
initialize: function (map) {
|
||||
this._map = map;
|
||||
@ -18,9 +22,7 @@ L.Map.BoxZoom = L.Handler.extend({
|
||||
},
|
||||
|
||||
_onMouseDown: function (e) {
|
||||
if (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) {
|
||||
return false;
|
||||
}
|
||||
if (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; }
|
||||
|
||||
L.DomUtil.disableTextSelection();
|
||||
|
||||
@ -29,28 +31,33 @@ L.Map.BoxZoom = L.Handler.extend({
|
||||
this._box = L.DomUtil.create('div', 'leaflet-zoom-box', this._pane);
|
||||
L.DomUtil.setPosition(this._box, this._startLayerPoint);
|
||||
|
||||
//TODO move cursor to styles
|
||||
//TODO refactor: move cursor to styles
|
||||
this._container.style.cursor = 'crosshair';
|
||||
|
||||
L.DomEvent.addListener(document, 'mousemove', this._onMouseMove, this);
|
||||
L.DomEvent.addListener(document, 'mouseup', this._onMouseUp, this);
|
||||
|
||||
L.DomEvent.preventDefault(e);
|
||||
L.DomEvent
|
||||
.addListener(document, 'mousemove', this._onMouseMove, this)
|
||||
.addListener(document, 'mouseup', this._onMouseUp, this)
|
||||
.preventDefault(e);
|
||||
|
||||
this._map.fire("boxzoomstart");
|
||||
},
|
||||
|
||||
_onMouseMove: function (e) {
|
||||
var layerPoint = this._map.mouseEventToLayerPoint(e),
|
||||
dx = layerPoint.x - this._startLayerPoint.x,
|
||||
dy = layerPoint.y - this._startLayerPoint.y;
|
||||
var startPoint = this._startLayerPoint,
|
||||
box = this._box,
|
||||
|
||||
var newX = Math.min(layerPoint.x, this._startLayerPoint.x),
|
||||
newY = Math.min(layerPoint.y, this._startLayerPoint.y),
|
||||
newPos = new L.Point(newX, newY);
|
||||
layerPoint = this._map.mouseEventToLayerPoint(e),
|
||||
offset = layerPoint.subtract(startPoint),
|
||||
|
||||
L.DomUtil.setPosition(this._box, newPos);
|
||||
newPos = new L.Point(
|
||||
Math.min(layerPoint.x, startPoint.x),
|
||||
Math.min(layerPoint.y, startPoint.y));
|
||||
|
||||
this._box.style.width = (Math.abs(dx) - 4) + 'px';
|
||||
this._box.style.height = (Math.abs(dy) - 4) + 'px';
|
||||
L.DomUtil.setPosition(box, newPos);
|
||||
|
||||
// TODO refactor: remove hardcoded 4 pixels
|
||||
box.style.width = (Math.abs(offset.x) - 4) + 'px';
|
||||
box.style.height = (Math.abs(offset.y) - 4) + 'px';
|
||||
},
|
||||
|
||||
_onMouseUp: function (e) {
|
||||
@ -59,15 +66,23 @@ L.Map.BoxZoom = L.Handler.extend({
|
||||
|
||||
L.DomUtil.enableTextSelection();
|
||||
|
||||
L.DomEvent.removeListener(document, 'mousemove', this._onMouseMove);
|
||||
L.DomEvent.removeListener(document, 'mouseup', this._onMouseUp);
|
||||
L.DomEvent
|
||||
.removeListener(document, 'mousemove', this._onMouseMove)
|
||||
.removeListener(document, 'mouseup', this._onMouseUp);
|
||||
|
||||
var layerPoint = this._map.mouseEventToLayerPoint(e);
|
||||
var map = this._map,
|
||||
layerPoint = map.mouseEventToLayerPoint(e);
|
||||
|
||||
var bounds = new L.LatLngBounds(
|
||||
this._map.layerPointToLatLng(this._startLayerPoint),
|
||||
this._map.layerPointToLatLng(layerPoint));
|
||||
map.layerPointToLatLng(this._startLayerPoint),
|
||||
map.layerPointToLatLng(layerPoint));
|
||||
|
||||
this._map.fitBounds(bounds);
|
||||
map.fitBounds(bounds);
|
||||
|
||||
map.fire("boxzoomend", {
|
||||
boxZoomBounds: bounds
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
L.Map.addInitHook('addHandler', 'boxZoom', L.Map.BoxZoom);
|
||||
|
@ -2,10 +2,13 @@
|
||||
* L.Handler.DoubleClickZoom is used internally by L.Map to add double-click zooming.
|
||||
*/
|
||||
|
||||
L.Map.mergeOptions({
|
||||
doubleClickZoom: true
|
||||
});
|
||||
|
||||
L.Map.DoubleClickZoom = L.Handler.extend({
|
||||
addHooks: function () {
|
||||
this._map.on('dblclick', this._onDoubleClick);
|
||||
// TODO remove 3d argument?
|
||||
},
|
||||
|
||||
removeHooks: function () {
|
||||
@ -16,3 +19,5 @@ L.Map.DoubleClickZoom = L.Handler.extend({
|
||||
this.setView(e.latlng, this._zoom + 1);
|
||||
}
|
||||
});
|
||||
|
||||
L.Map.addInitHook('addHandler', 'doubleClickZoom', L.Map.DoubleClickZoom);
|
@ -2,6 +2,19 @@
|
||||
* L.Handler.MapDrag is used internally by L.Map to make the map draggable.
|
||||
*/
|
||||
|
||||
L.Map.mergeOptions({
|
||||
dragging: true,
|
||||
|
||||
inertia: !L.Browser.android,
|
||||
inertiaDeceleration: L.Browser.touch ? 3000 : 2000, // px/s^2
|
||||
inertiaMaxSpeed: L.Browser.touch ? 1500 : 1000, // px/s
|
||||
inertiaThreshold: L.Browser.touch ? 32 : 16, // ms
|
||||
|
||||
// TODO refactor, move to CRS
|
||||
worldCopyJump: true,
|
||||
continuousWorld: false
|
||||
});
|
||||
|
||||
L.Map.Drag = L.Handler.extend({
|
||||
addHooks: function () {
|
||||
if (!this._draggable) {
|
||||
@ -31,12 +44,36 @@ L.Map.Drag = L.Handler.extend({
|
||||
},
|
||||
|
||||
_onDragStart: function () {
|
||||
this._map
|
||||
var map = this._map;
|
||||
|
||||
map
|
||||
.fire('movestart')
|
||||
.fire('dragstart');
|
||||
|
||||
if (map._panTransition) {
|
||||
map._panTransition._onTransitionEnd(true);
|
||||
}
|
||||
|
||||
if (map.options.inertia) {
|
||||
this._positions = [];
|
||||
this._times = [];
|
||||
}
|
||||
},
|
||||
|
||||
_onDrag: function () {
|
||||
if (this._map.options.inertia) {
|
||||
var time = this._lastTime = +new Date(),
|
||||
pos = this._lastPos = this._draggable._newPos;
|
||||
|
||||
this._positions.push(pos);
|
||||
this._times.push(time);
|
||||
|
||||
if (time - this._times[0] > 200) {
|
||||
this._positions.shift();
|
||||
this._times.shift();
|
||||
}
|
||||
}
|
||||
|
||||
this._map
|
||||
.fire('move')
|
||||
.fire('drag');
|
||||
@ -51,7 +88,7 @@ L.Map.Drag = L.Handler.extend({
|
||||
|
||||
_onPreDrag: function () {
|
||||
var map = this._map,
|
||||
worldWidth = map.options.scale(map.getZoom()),
|
||||
worldWidth = map.options.crs.scale(map.getZoom()),
|
||||
halfWidth = Math.round(worldWidth / 2),
|
||||
dx = this._initialWorldOffset.x,
|
||||
x = this._draggable._newPos.x,
|
||||
@ -63,13 +100,44 @@ L.Map.Drag = L.Handler.extend({
|
||||
},
|
||||
|
||||
_onDragEnd: function () {
|
||||
var map = this._map;
|
||||
var map = this._map,
|
||||
options = map.options,
|
||||
delay = +new Date() - this._lastTime,
|
||||
|
||||
map
|
||||
.fire('moveend')
|
||||
.fire('dragend');
|
||||
noInertia = !options.inertia ||
|
||||
delay > options.inertiaThreshold ||
|
||||
typeof this._positions[0] === 'undefined';
|
||||
|
||||
if (map.options.maxBounds) {
|
||||
if (noInertia) {
|
||||
map.fire('moveend');
|
||||
|
||||
} else {
|
||||
|
||||
var direction = this._lastPos.subtract(this._positions[0]),
|
||||
duration = (this._lastTime + delay - this._times[0]) / 1000,
|
||||
|
||||
speedVector = direction.multiplyBy(0.58 / duration),
|
||||
speed = speedVector.distanceTo(new L.Point(0, 0)),
|
||||
|
||||
limitedSpeed = Math.min(options.inertiaMaxSpeed, speed),
|
||||
limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed),
|
||||
|
||||
decelerationDuration = limitedSpeed / options.inertiaDeceleration,
|
||||
offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round();
|
||||
|
||||
var panOptions = {
|
||||
duration: decelerationDuration,
|
||||
easing: 'ease-out'
|
||||
};
|
||||
|
||||
L.Util.requestAnimFrame(L.Util.bind(function () {
|
||||
this._map.panBy(offset, panOptions);
|
||||
}, this));
|
||||
}
|
||||
|
||||
map.fire('dragend');
|
||||
|
||||
if (options.maxBounds) {
|
||||
// TODO predrag validation instead of animation
|
||||
L.Util.requestAnimFrame(this._panInsideMaxBounds, map, true, map._container);
|
||||
}
|
||||
@ -79,3 +147,5 @@ L.Map.Drag = L.Handler.extend({
|
||||
this.panInsideBounds(this.options.maxBounds);
|
||||
}
|
||||
});
|
||||
|
||||
L.Map.addInitHook('addHandler', 'dragging', L.Map.Drag);
|
@ -2,6 +2,10 @@
|
||||
* L.Handler.ScrollWheelZoom is used internally by L.Map to enable mouse scroll wheel zooming on the map.
|
||||
*/
|
||||
|
||||
L.Map.mergeOptions({
|
||||
scrollWheelZoom: !L.Browser.touch
|
||||
});
|
||||
|
||||
L.Map.ScrollWheelZoom = L.Handler.extend({
|
||||
addHooks: function () {
|
||||
L.DomEvent.addListener(this._map._container, 'mousewheel', this._onWheelScroll, this);
|
||||
@ -14,6 +18,7 @@ L.Map.ScrollWheelZoom = L.Handler.extend({
|
||||
|
||||
_onWheelScroll: function (e) {
|
||||
var delta = L.DomEvent.getWheelDelta(e);
|
||||
|
||||
this._delta += delta;
|
||||
this._lastMousePos = this._map.mouseEventToContainerPoint(e);
|
||||
|
||||
@ -33,9 +38,7 @@ L.Map.ScrollWheelZoom = L.Handler.extend({
|
||||
|
||||
this._delta = 0;
|
||||
|
||||
if (!delta) {
|
||||
return;
|
||||
}
|
||||
if (!delta) { return; }
|
||||
|
||||
var newCenter = this._getCenterForScrollWheelZoom(this._lastMousePos, delta),
|
||||
newZoom = zoom + delta;
|
||||
@ -53,3 +56,5 @@ L.Map.ScrollWheelZoom = L.Handler.extend({
|
||||
return map.unproject(newCenterPoint, map._zoom, true);
|
||||
}
|
||||
});
|
||||
|
||||
L.Map.addInitHook('addHandler', 'scrollWheelZoom', L.Map.ScrollWheelZoom);
|
@ -2,6 +2,10 @@
|
||||
* L.Handler.TouchZoom is used internally by L.Map to add touch-zooming on Webkit-powered mobile browsers.
|
||||
*/
|
||||
|
||||
L.Map.mergeOptions({
|
||||
touchZoom: L.Browser.touch && !L.Browser.android
|
||||
});
|
||||
|
||||
L.Map.TouchZoom = L.Handler.extend({
|
||||
addHooks: function () {
|
||||
L.DomEvent.addListener(this._map._container, 'touchstart', this._onTouchStart, this);
|
||||
@ -12,82 +16,101 @@ L.Map.TouchZoom = L.Handler.extend({
|
||||
},
|
||||
|
||||
_onTouchStart: function (e) {
|
||||
if (!e.touches || e.touches.length !== 2 || this._map._animatingZoom) {
|
||||
return;
|
||||
}
|
||||
var map = this._map;
|
||||
|
||||
var p1 = this._map.mouseEventToLayerPoint(e.touches[0]),
|
||||
p2 = this._map.mouseEventToLayerPoint(e.touches[1]),
|
||||
viewCenter = this._map.containerPointToLayerPoint(this._map.getSize().divideBy(2));
|
||||
if (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming) { return; }
|
||||
|
||||
var p1 = map.mouseEventToLayerPoint(e.touches[0]),
|
||||
p2 = map.mouseEventToLayerPoint(e.touches[1]),
|
||||
viewCenter = map.containerPointToLayerPoint(map.getSize().divideBy(2));
|
||||
|
||||
this._startCenter = p1.add(p2).divideBy(2, true);
|
||||
this._startDist = p1.distanceTo(p2);
|
||||
//this._startTransform = this._map._mapPane.style.webkitTransform;
|
||||
|
||||
this._moved = false;
|
||||
this._zooming = true;
|
||||
|
||||
this._centerOffset = viewCenter.subtract(this._startCenter);
|
||||
|
||||
L.DomEvent.addListener(document, 'touchmove', this._onTouchMove, this);
|
||||
L.DomEvent.addListener(document, 'touchend', this._onTouchEnd, this);
|
||||
L.DomEvent
|
||||
.addListener(document, 'touchmove', this._onTouchMove, this)
|
||||
.addListener(document, 'touchend', this._onTouchEnd, this);
|
||||
|
||||
L.DomEvent.preventDefault(e);
|
||||
},
|
||||
|
||||
_onTouchMove: function (e) {
|
||||
if (!e.touches || e.touches.length !== 2) {
|
||||
return;
|
||||
}
|
||||
if (!e.touches || e.touches.length !== 2) { return; }
|
||||
|
||||
var map = this._map;
|
||||
|
||||
var p1 = map.mouseEventToLayerPoint(e.touches[0]),
|
||||
p2 = map.mouseEventToLayerPoint(e.touches[1]);
|
||||
|
||||
this._scale = p1.distanceTo(p2) / this._startDist;
|
||||
this._delta = p1.add(p2).divideBy(2, true).subtract(this._startCenter);
|
||||
|
||||
if (this._scale === 1) { return; }
|
||||
|
||||
var zoom = this._map._zoom + Math.log(this._scale) / Math.LN2;
|
||||
|
||||
var centerOffset = this._centerOffset.subtract(this._delta).divideBy(this._scale),
|
||||
centerPoint = this._map.getPixelOrigin().add(this._startCenter).add(centerOffset),
|
||||
center = this._map.unproject(centerPoint);
|
||||
|
||||
if (!this._moved) {
|
||||
this._map._mapPane.className += ' leaflet-zoom-anim';
|
||||
map._mapPane.className += ' leaflet-zoom-anim leaflet-touching';
|
||||
|
||||
this._map
|
||||
.fire('zoomstart')
|
||||
map
|
||||
.fire('movestart')
|
||||
.fire('zoomstart')
|
||||
._prepareTileBg();
|
||||
|
||||
this._moved = true;
|
||||
}
|
||||
|
||||
var p1 = this._map.mouseEventToLayerPoint(e.touches[0]),
|
||||
p2 = this._map.mouseEventToLayerPoint(e.touches[1]);
|
||||
|
||||
this._scale = p1.distanceTo(p2) / this._startDist;
|
||||
this._delta = p1.add(p2).divideBy(2, true).subtract(this._startCenter);
|
||||
map.fire('zoomanim', {
|
||||
center: center,
|
||||
zoom: zoom
|
||||
});
|
||||
|
||||
// Used 2 translates instead of transform-origin because of a very strange bug -
|
||||
// it didn't count the origin on the first touch-zoom but worked correctly afterwards
|
||||
|
||||
this._map._tileBg.style.webkitTransform = [
|
||||
L.DomUtil.getTranslateString(this._delta),
|
||||
L.DomUtil.getScaleString(this._scale, this._startCenter)
|
||||
].join(" ");
|
||||
map._tileBg.style[L.DomUtil.TRANSFORM] =
|
||||
L.DomUtil.getTranslateString(this._delta) + ' ' +
|
||||
L.DomUtil.getScaleString(this._scale, this._startCenter);
|
||||
|
||||
L.DomEvent.preventDefault(e);
|
||||
},
|
||||
|
||||
_onTouchEnd: function (e) {
|
||||
if (!this._moved || !this._zooming) {
|
||||
return;
|
||||
}
|
||||
this._zooming = false;
|
||||
if (!this._moved || !this._zooming) { return; }
|
||||
|
||||
var oldZoom = this._map.getZoom(),
|
||||
this._zooming = false;
|
||||
this._map._mapPane.className = this._map._mapPane.className.replace(' leaflet-touching', ''); //TODO toggleClass util
|
||||
|
||||
L.DomEvent
|
||||
.removeListener(document, 'touchmove', this._onTouchMove)
|
||||
.removeListener(document, 'touchend', this._onTouchEnd);
|
||||
|
||||
var centerOffset = this._centerOffset.subtract(this._delta).divideBy(this._scale),
|
||||
centerPoint = this._map.getPixelOrigin().add(this._startCenter).add(centerOffset),
|
||||
center = this._map.unproject(centerPoint),
|
||||
|
||||
oldZoom = this._map.getZoom(),
|
||||
floatZoomDelta = Math.log(this._scale) / Math.LN2,
|
||||
roundZoomDelta = (floatZoomDelta > 0 ? Math.ceil(floatZoomDelta) : Math.floor(floatZoomDelta)),
|
||||
zoom = this._map._limitZoom(oldZoom + roundZoomDelta),
|
||||
zoomDelta = zoom - oldZoom,
|
||||
centerOffset = this._centerOffset.subtract(this._delta).divideBy(this._scale),
|
||||
centerPoint = this._map.getPixelOrigin().add(this._startCenter).add(centerOffset),
|
||||
center = this._map.unproject(centerPoint);
|
||||
finalScale = Math.pow(2, zoom - oldZoom);
|
||||
|
||||
L.DomEvent.removeListener(document, 'touchmove', this._onTouchMove);
|
||||
L.DomEvent.removeListener(document, 'touchend', this._onTouchEnd);
|
||||
this._map.fire('zoomanim', {
|
||||
center: center,
|
||||
zoom: zoom
|
||||
});
|
||||
|
||||
var finalScale = Math.pow(2, zoomDelta);
|
||||
|
||||
this._map._runAnimation(center, zoom, finalScale / this._scale, this._startCenter.add(centerOffset));
|
||||
this._map._runAnimation(center, zoom, finalScale / this._scale, this._startCenter.add(centerOffset), true);
|
||||
}
|
||||
});
|
||||
|
||||
L.Map.addInitHook('addHandler', 'touchZoom', L.Map.TouchZoom);
|
Loading…
Reference in New Issue
Block a user