Commit 15167bf3d4eb6b85d6e9f6dbe032ff1fd87e58a8
Merge branch 'master' of http://service.routetopa.eu:7480/WebCompDev/COMPONENTS
Showing
16 changed files
with
9923 additions
and
5 deletions
controllets/data-table-controllet/data-table-controllet.html
@@ -335,13 +335,14 @@ | @@ -335,13 +335,14 @@ | ||
335 | 335 | ||
336 | this._resize(); | 336 | this._resize(); |
337 | 337 | ||
338 | - this.$.tooltip_wornings.show(); | 338 | + this.async(function() { |
339 | + this.$.tooltip_wornings.show(); | ||
340 | + }, 100); | ||
339 | }, | 341 | }, |
340 | 342 | ||
341 | reset : function(){ | 343 | reset : function(){ |
342 | this.setData([]); | 344 | this.setData([]); |
343 | $(this.$.tbody).animate({ scrollTop: 0}, 0); | 345 | $(this.$.tbody).animate({ scrollTop: 0}, 0); |
344 | -// this.filter = ""; | ||
345 | }, | 346 | }, |
346 | 347 | ||
347 | _onPrevClick : function(){ | 348 | _onPrevClick : function(){ |
@@ -478,7 +479,7 @@ | @@ -478,7 +479,7 @@ | ||
478 | var w = $(this.$.data_table_container).width(); | 479 | var w = $(this.$.data_table_container).width(); |
479 | $(this.$.tbody).width(w).height(h); | 480 | $(this.$.tbody).width(w).height(h); |
480 | $(this.$.tbody).perfectScrollbar('update'); | 481 | $(this.$.tbody).perfectScrollbar('update'); |
481 | - }, 1); | 482 | + }, 0); |
482 | } | 483 | } |
483 | 484 | ||
484 | }); | 485 | }); |
controllets/select-visualization-controllet/select-datalet-inputs.html
@@ -276,7 +276,11 @@ | @@ -276,7 +276,11 @@ | ||
276 | 276 | ||
277 | setInputs : function(inputs) { | 277 | setInputs : function(inputs) { |
278 | var temp = this._copy(inputs); | 278 | var temp = this._copy(inputs); |
279 | - if (inputs.constructor != Array) {//table --> 1 input | 279 | + if (inputs.constructor != Array && inputs.name == "GEOJSON") { |
280 | + temp = []; | ||
281 | + temp.push(inputs); | ||
282 | + } | ||
283 | + else if (inputs.constructor != Array) {//table --> 1 input | ||
280 | var name = inputs.name; | 284 | var name = inputs.name; |
281 | var description = inputs.description; | 285 | var description = inputs.description; |
282 | var selection = inputs.selection; | 286 | var selection = inputs.selection; |
datalets/base-ajax-json-alasql-datalet/base-ajax-json-alasql-datalet.html
@@ -34,7 +34,7 @@ | @@ -34,7 +34,7 @@ | ||
34 | <script type="text/javascript" src="../../alasql-utility/alasql.min.js"></script> | 34 | <script type="text/javascript" src="../../alasql-utility/alasql.min.js"></script> |
35 | <script type="text/javascript" src="../../alasql-utility/alasql-utility.js"></script> | 35 | <script type="text/javascript" src="../../alasql-utility/alasql-utility.js"></script> |
36 | 36 | ||
37 | -<script type="text/javascript" src="../../bower_components/JSDataChecker/jsdatachecker.min.js"></script> | 37 | +<script type="text/javascript" src="../../bower_components/jsdatachecker/jsdatachecker.min.js"></script> |
38 | 38 | ||
39 | <!-- | 39 | <!-- |
40 | The `base-ajax-json-jsonpath-datalet` extend the base component and define the mechanism to access and select data. | 40 | The `base-ajax-json-jsonpath-datalet` extend the base component and define the mechanism to access and select data. |
datalets/leafletjs-geojson-datalet/demo/index.html
0 โ 100755
1 | +<!DOCTYPE html> | ||
2 | +<html lang="en"> | ||
3 | +<head> | ||
4 | + <meta charset="UTF-8"> | ||
5 | + <title></title> | ||
6 | + | ||
7 | + <script> | ||
8 | + </script> | ||
9 | + | ||
10 | +</head> | ||
11 | +<body> | ||
12 | + | ||
13 | +<script src="https://code.jquery.com/jquery-2.1.4.min.js" type="text/javascript"></script> | ||
14 | +<link rel="import" href="../leafletjs-datalet.html" /> | ||
15 | + | ||
16 | +<leafletjs-datalet data-url="http://ckan.routetopa.eu/api/action/datastore_search?resource_id=73e02092-85a1-434e-85fe-0c9a43aa9a52&limit=10000" | ||
17 | + fields='["result,records,Lat","result,records,Lng", "result,records,Link"]'></leafletjs-datalet> | ||
18 | + | ||
19 | + | ||
20 | +</body> | ||
21 | +</html> | ||
0 | \ No newline at end of file | 22 | \ No newline at end of file |
datalets/leafletjs-geojson-datalet/docs.html
0 โ 100755
1 | +<!DOCTYPE html> | ||
2 | +<html lang="en"> | ||
3 | +<head> | ||
4 | + <link rel="import" href="../../bower_components/iron-component-page/iron-component-page.html"> | ||
5 | + <meta charset="UTF-8"> | ||
6 | +</head> | ||
7 | +<body> | ||
8 | + | ||
9 | +<iron-component-page src="leafletjs-datalet.html"></iron-component-page> | ||
10 | + | ||
11 | +</body> | ||
12 | +</html> | ||
0 | \ No newline at end of file | 13 | \ No newline at end of file |
datalets/leafletjs-geojson-datalet/leafletjs-geojson-datalet.html
0 โ 100755
1 | +<!-- | ||
2 | +@license | ||
3 | + The MIT License (MIT) | ||
4 | + | ||
5 | + Copyright (c) 2015 Dipartimento di Informatica - Universitร di Salerno - Italy | ||
6 | + | ||
7 | + Permission is hereby granted, free of charge, to any person obtaining a copy | ||
8 | + of this software and associated documentation files (the "Software"), to deal | ||
9 | + in the Software without restriction, including without limitation the rights | ||
10 | + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
11 | + copies of the Software, and to permit persons to whom the Software is | ||
12 | + furnished to do so, subject to the following conditions: | ||
13 | + | ||
14 | + The above copyright notice and this permission notice shall be included in | ||
15 | + all copies or substantial portions of the Software. | ||
16 | + | ||
17 | + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
18 | + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
19 | + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
20 | + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
21 | + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
22 | + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
23 | + THE SOFTWARE. | ||
24 | +--> | ||
25 | + | ||
26 | +<!-- | ||
27 | +* Developed by : | ||
28 | +* ROUTE-TO-PA Project - grant No 645860. - www.routetopa.eu | ||
29 | +* | ||
30 | +--> | ||
31 | + | ||
32 | +<link rel="import" href="../base-ajax-json-alasql-datalet/base-ajax-json-alasql-datalet.html"> | ||
33 | + | ||
34 | +<!-- | ||
35 | + | ||
36 | +`leafletjs-datalet` is a map datalet based on open source project leafletjs <http://leafletjs.com/> | ||
37 | + | ||
38 | +Example: | ||
39 | + | ||
40 | + <leafletjs-datalet | ||
41 | + data-url="http://ckan.routetopa.eu/api/action/datastore_search?resource_id=#" | ||
42 | + fields='["field1","field2"]'> | ||
43 | + </leafletjs-datalet> | ||
44 | + | ||
45 | +@element leafletjs-datalet | ||
46 | +@status v0.1 | ||
47 | +@demo demo/index.html | ||
48 | +@group datalets | ||
49 | +--> | ||
50 | + | ||
51 | +<dom-module name="leafletjs-geojson-datalet"> | ||
52 | + <template> | ||
53 | + <link rel="stylesheet" href="leafletsjs/leaflet.css" /> | ||
54 | + <style> | ||
55 | + #leafletjs {height: 600px;} | ||
56 | + </style> | ||
57 | + | ||
58 | + <div id="leafletjs"></div> | ||
59 | + <base-ajax-json-alasql-datalet data-url="{{dataUrl}}" fields="{{fields}}" data="{{data}}" title="{{title}}" description="{{description}}" export_menu="{{export_menu}}"></base-ajax-json-alasql-datalet> | ||
60 | + | ||
61 | + </template> | ||
62 | + | ||
63 | + <script src="leafletsjs/leaflet.js"></script> | ||
64 | + | ||
65 | + <script> | ||
66 | + | ||
67 | + var leafletjsBehavior = { | ||
68 | + | ||
69 | + /** | ||
70 | + * Read markers coordinates from the data object and add the marker to the map. | ||
71 | + * Call a method for the map redraw and set the viewport in order to fit all the markers in the viewport.. | ||
72 | + * | ||
73 | + * @method transformData | ||
74 | + */ | ||
75 | + presentData: function(){ | ||
76 | + | ||
77 | + var t = this; | ||
78 | + try{ | ||
79 | + this._component.map = L.map(this._component.$.leafletjs).setView([0, 0], 13, {reset:true}); | ||
80 | + }catch(e){} | ||
81 | + | ||
82 | + | ||
83 | + L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { | ||
84 | + maxZoom: 18, | ||
85 | + attribution: 'Map data ยฉ <a href="http://openstreetmap.org">OpenStreetMap</a> contributors' | ||
86 | + }).addTo(this._component.map); | ||
87 | + | ||
88 | + | ||
89 | + L.Icon.Default.imagePath = 'http://services.routetopa.eu/DEEalerProvider/COMPONENTS/datalets/leafletjs-datalet/leafletsjs/images'; | ||
90 | + | ||
91 | + var coordinates = []; | ||
92 | + var coordinates_index = 0; | ||
93 | + var isArray = t.data[0].data[0].constructor === Array; | ||
94 | + | ||
95 | + for(var i=0; i<t.data[0].data.length; i++) | ||
96 | + { | ||
97 | + if(isArray) | ||
98 | + { | ||
99 | + if(!isNaN(t.data[0].data[i][0]) && !isNaN(t.data[0].data[i][1])) | ||
100 | + coordinates.push([parseFloat(t.data[0].data[i][0]), parseFloat(t.data[0].data[i][1])]); | ||
101 | + else | ||
102 | + continue; | ||
103 | + } | ||
104 | + else | ||
105 | + { | ||
106 | + if(!isNaN(t.data[0].data[i]) && !isNaN(t.data[1].data[i])) | ||
107 | + coordinates.push([parseFloat(t.data[0].data[i]), parseFloat(t.data[1].data[i])]); | ||
108 | + else | ||
109 | + continue; | ||
110 | + } | ||
111 | + | ||
112 | + var marker = L.marker([coordinates[coordinates_index][0], coordinates[coordinates_index][1]]).addTo(t._component.map); | ||
113 | + coordinates_index++; | ||
114 | + | ||
115 | + if(t.data.length > 2) | ||
116 | + { | ||
117 | + var popupText = ""; | ||
118 | + for(var j=2; j<t.data.length; j++) | ||
119 | + { | ||
120 | + if(typeof t.data[j] != 'undefined' && typeof t.data[j].data[i] != 'undefined') | ||
121 | + { | ||
122 | + if (t.data[j].data[i].toString().match(new RegExp("^(http[s]?:\\/\\/(www\\.)?|ftp:\\/\\/(www\\.)?|www\\.){1}([0-9A-Za-z-\\.@:%_\+~#=]+)+((\\.[a-zA-Z]{2,3})+)(/(.)*)?(\\?(.)*)?"))) | ||
123 | + popupText += '<image height="100" width="100" src="' + t.data[j].data[i] + '" /><br/>'; | ||
124 | + else | ||
125 | + popupText += '<span>' + t.data[j].name + ' : ' + t.data[j].data[i] + '</span><br/>' | ||
126 | + } | ||
127 | + } | ||
128 | + | ||
129 | + var popup = L.popup().setContent(popupText); | ||
130 | + marker.bindPopup(popup); | ||
131 | + } | ||
132 | + } | ||
133 | + | ||
134 | + t._component.map._onResize(); | ||
135 | + t._component.map.invalidateSize(false); | ||
136 | + t._component.map.fitBounds(coordinates); | ||
137 | + | ||
138 | + } | ||
139 | + }; | ||
140 | + | ||
141 | + | ||
142 | + Polymer({ | ||
143 | + | ||
144 | + is : 'leafletjs-geojson-datalet', | ||
145 | + | ||
146 | + properties : { | ||
147 | + /** | ||
148 | + * Store a reference to the leafletjs map object created in 'ready' callback | ||
149 | + * @attribute map | ||
150 | + * @type Object | ||
151 | + */ | ||
152 | + map : | ||
153 | + { | ||
154 | + type: Object, | ||
155 | + value:null | ||
156 | + }, | ||
157 | + /** | ||
158 | + * An Array with all the markers extracted from the dataset | ||
159 | + * @attribute markers | ||
160 | + * @type Array | ||
161 | + */ | ||
162 | + markers : | ||
163 | + { | ||
164 | + type : Array, | ||
165 | + value : [] | ||
166 | + }, | ||
167 | + /** | ||
168 | + * It's the component behavior | ||
169 | + * | ||
170 | + * @attribute behavior | ||
171 | + * @type Object | ||
172 | + * @default {} | ||
173 | + */ | ||
174 | + behavior : { | ||
175 | + type : Object, | ||
176 | + value : {} | ||
177 | + }, | ||
178 | + /** | ||
179 | + * Control the export menu | ||
180 | + * xxxx BITMASK. FROM RIGHT : HTML, PNG, RTF, MY SPACE (eg. 1111 show all, 0000 hide all) | ||
181 | + * | ||
182 | + * @attribute export_menu | ||
183 | + * @type Number | ||
184 | + * @default 15 | ||
185 | + */ | ||
186 | + export_menu : { | ||
187 | + type : Number, | ||
188 | + value : 9 // xxxx BITMASK. FROM RIGHT : HTML, PNG, RTF, MY SPACE (eg. 1111 show all, 0000 hide all) | ||
189 | + } | ||
190 | + }, | ||
191 | + | ||
192 | + /** | ||
193 | + * 'ready' callback create the map object, set the tileLayer to openstreetmap and the default icon image path. | ||
194 | + * Moreover extend the leafletjsComponentBehavior with BaseDataletBehavior, WorkcycleBehavior and leafletjsBehavior | ||
195 | + * and run the Datalet workcycle. | ||
196 | + * | ||
197 | + * @method ready | ||
198 | + */ | ||
199 | + ready: function(){ | ||
200 | + this.behavior = $.extend(true, {}, BaseDataletBehavior, WorkcycleBehavior, AjaxJsonAlasqlBehavior, leafletjsBehavior); | ||
201 | + this.async(function(){this.behavior.init(this)},100); | ||
202 | + } | ||
203 | + }); | ||
204 | + </script> | ||
205 | +</dom-module> | ||
206 | + |
datalets/leafletjs-geojson-datalet/leafletjs-geojson-datalet.png
0 โ 100644
5.32 KB
datalets/leafletjs-geojson-datalet/leafletsjs/images/layers-2x.png
0 โ 100755
2.83 KB
datalets/leafletjs-geojson-datalet/leafletsjs/images/layers.png
0 โ 100755
1.47 KB
datalets/leafletjs-geojson-datalet/leafletsjs/images/marker-icon-2x.png
0 โ 100755
3.94 KB
datalets/leafletjs-geojson-datalet/leafletsjs/images/marker-icon.png
0 โ 100755
1.71 KB
datalets/leafletjs-geojson-datalet/leafletsjs/images/marker-shadow.png
0 โ 100755
797 Bytes
datalets/leafletjs-geojson-datalet/leafletsjs/leaflet-src.js
0 โ 100755
1 | +/* | ||
2 | + Leaflet, a JavaScript library for mobile-friendly interactive maps. http://leafletjs.com | ||
3 | + (c) 2010-2013, Vladimir Agafonkin | ||
4 | + (c) 2010-2011, CloudMade | ||
5 | +*/ | ||
6 | +(function (window, document, undefined) { | ||
7 | +var oldL = window.L, | ||
8 | + L = {}; | ||
9 | + | ||
10 | +L.version = '0.7.3'; | ||
11 | + | ||
12 | +// define Leaflet for Node module pattern loaders, including Browserify | ||
13 | +if (typeof module === 'object' && typeof module.exports === 'object') { | ||
14 | + module.exports = L; | ||
15 | + | ||
16 | +// define Leaflet as an AMD module | ||
17 | +} else if (typeof define === 'function' && define.amd) { | ||
18 | + define(L); | ||
19 | +} | ||
20 | + | ||
21 | +// define Leaflet as a global L variable, saving the original L to restore later if needed | ||
22 | + | ||
23 | +L.noConflict = function () { | ||
24 | + window.L = oldL; | ||
25 | + return this; | ||
26 | +}; | ||
27 | + | ||
28 | +window.L = L; | ||
29 | + | ||
30 | + | ||
31 | +/* | ||
32 | + * L.Util contains various utility functions used throughout Leaflet code. | ||
33 | + */ | ||
34 | + | ||
35 | +L.Util = { | ||
36 | + extend: function (dest) { // (Object[, Object, ...]) -> | ||
37 | + var sources = Array.prototype.slice.call(arguments, 1), | ||
38 | + i, j, len, src; | ||
39 | + | ||
40 | + for (j = 0, len = sources.length; j < len; j++) { | ||
41 | + src = sources[j] || {}; | ||
42 | + for (i in src) { | ||
43 | + if (src.hasOwnProperty(i)) { | ||
44 | + dest[i] = src[i]; | ||
45 | + } | ||
46 | + } | ||
47 | + } | ||
48 | + return dest; | ||
49 | + }, | ||
50 | + | ||
51 | + bind: function (fn, obj) { // (Function, Object) -> Function | ||
52 | + var args = arguments.length > 2 ? Array.prototype.slice.call(arguments, 2) : null; | ||
53 | + return function () { | ||
54 | + return fn.apply(obj, args || arguments); | ||
55 | + }; | ||
56 | + }, | ||
57 | + | ||
58 | + stamp: (function () { | ||
59 | + var lastId = 0, | ||
60 | + key = '_leaflet_id'; | ||
61 | + return function (obj) { | ||
62 | + obj[key] = obj[key] || ++lastId; | ||
63 | + return obj[key]; | ||
64 | + }; | ||
65 | + }()), | ||
66 | + | ||
67 | + invokeEach: function (obj, method, context) { | ||
68 | + var i, args; | ||
69 | + | ||
70 | + if (typeof obj === 'object') { | ||
71 | + args = Array.prototype.slice.call(arguments, 3); | ||
72 | + | ||
73 | + for (i in obj) { | ||
74 | + method.apply(context, [i, obj[i]].concat(args)); | ||
75 | + } | ||
76 | + return true; | ||
77 | + } | ||
78 | + | ||
79 | + return false; | ||
80 | + }, | ||
81 | + | ||
82 | + limitExecByInterval: function (fn, time, context) { | ||
83 | + var lock, execOnUnlock; | ||
84 | + | ||
85 | + return function wrapperFn() { | ||
86 | + var args = arguments; | ||
87 | + | ||
88 | + if (lock) { | ||
89 | + execOnUnlock = true; | ||
90 | + return; | ||
91 | + } | ||
92 | + | ||
93 | + lock = true; | ||
94 | + | ||
95 | + setTimeout(function () { | ||
96 | + lock = false; | ||
97 | + | ||
98 | + if (execOnUnlock) { | ||
99 | + wrapperFn.apply(context, args); | ||
100 | + execOnUnlock = false; | ||
101 | + } | ||
102 | + }, time); | ||
103 | + | ||
104 | + fn.apply(context, args); | ||
105 | + }; | ||
106 | + }, | ||
107 | + | ||
108 | + falseFn: function () { | ||
109 | + return false; | ||
110 | + }, | ||
111 | + | ||
112 | + formatNum: function (num, digits) { | ||
113 | + var pow = Math.pow(10, digits || 5); | ||
114 | + return Math.round(num * pow) / pow; | ||
115 | + }, | ||
116 | + | ||
117 | + trim: function (str) { | ||
118 | + return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, ''); | ||
119 | + }, | ||
120 | + | ||
121 | + splitWords: function (str) { | ||
122 | + return L.Util.trim(str).split(/\s+/); | ||
123 | + }, | ||
124 | + | ||
125 | + setOptions: function (obj, options) { | ||
126 | + obj.options = L.extend({}, obj.options, options); | ||
127 | + return obj.options; | ||
128 | + }, | ||
129 | + | ||
130 | + getParamString: function (obj, existingUrl, uppercase) { | ||
131 | + var params = []; | ||
132 | + for (var i in obj) { | ||
133 | + params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i])); | ||
134 | + } | ||
135 | + return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&'); | ||
136 | + }, | ||
137 | + template: function (str, data) { | ||
138 | + return str.replace(/\{ *([\w_]+) *\}/g, function (str, key) { | ||
139 | + var value = data[key]; | ||
140 | + if (value === undefined) { | ||
141 | + throw new Error('No value provided for variable ' + str); | ||
142 | + } else if (typeof value === 'function') { | ||
143 | + value = value(data); | ||
144 | + } | ||
145 | + return value; | ||
146 | + }); | ||
147 | + }, | ||
148 | + | ||
149 | + isArray: Array.isArray || function (obj) { | ||
150 | + return (Object.prototype.toString.call(obj) === '[object Array]'); | ||
151 | + }, | ||
152 | + | ||
153 | + emptyImageUrl: 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=' | ||
154 | +}; | ||
155 | + | ||
156 | +(function () { | ||
157 | + | ||
158 | + // inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/ | ||
159 | + | ||
160 | + function getPrefixed(name) { | ||
161 | + var i, fn, | ||
162 | + prefixes = ['webkit', 'moz', 'o', 'ms']; | ||
163 | + | ||
164 | + for (i = 0; i < prefixes.length && !fn; i++) { | ||
165 | + fn = window[prefixes[i] + name]; | ||
166 | + } | ||
167 | + | ||
168 | + return fn; | ||
169 | + } | ||
170 | + | ||
171 | + var lastTime = 0; | ||
172 | + | ||
173 | + function timeoutDefer(fn) { | ||
174 | + var time = +new Date(), | ||
175 | + timeToCall = Math.max(0, 16 - (time - lastTime)); | ||
176 | + | ||
177 | + lastTime = time + timeToCall; | ||
178 | + return window.setTimeout(fn, timeToCall); | ||
179 | + } | ||
180 | + | ||
181 | + var requestFn = window.requestAnimationFrame || | ||
182 | + getPrefixed('RequestAnimationFrame') || timeoutDefer; | ||
183 | + | ||
184 | + var cancelFn = window.cancelAnimationFrame || | ||
185 | + getPrefixed('CancelAnimationFrame') || | ||
186 | + getPrefixed('CancelRequestAnimationFrame') || | ||
187 | + function (id) { window.clearTimeout(id); }; | ||
188 | + | ||
189 | + | ||
190 | + L.Util.requestAnimFrame = function (fn, context, immediate, element) { | ||
191 | + fn = L.bind(fn, context); | ||
192 | + | ||
193 | + if (immediate && requestFn === timeoutDefer) { | ||
194 | + fn(); | ||
195 | + } else { | ||
196 | + return requestFn.call(window, fn, element); | ||
197 | + } | ||
198 | + }; | ||
199 | + | ||
200 | + L.Util.cancelAnimFrame = function (id) { | ||
201 | + if (id) { | ||
202 | + cancelFn.call(window, id); | ||
203 | + } | ||
204 | + }; | ||
205 | + | ||
206 | +}()); | ||
207 | + | ||
208 | +// shortcuts for most used utility functions | ||
209 | +L.extend = L.Util.extend; | ||
210 | +L.bind = L.Util.bind; | ||
211 | +L.stamp = L.Util.stamp; | ||
212 | +L.setOptions = L.Util.setOptions; | ||
213 | + | ||
214 | + | ||
215 | +/* | ||
216 | + * L.Class powers the OOP facilities of the library. | ||
217 | + * Thanks to John Resig and Dean Edwards for inspiration! | ||
218 | + */ | ||
219 | + | ||
220 | +L.Class = function () {}; | ||
221 | + | ||
222 | +L.Class.extend = function (props) { | ||
223 | + | ||
224 | + // extended class with the new prototype | ||
225 | + var NewClass = function () { | ||
226 | + | ||
227 | + // call the constructor | ||
228 | + if (this.initialize) { | ||
229 | + this.initialize.apply(this, arguments); | ||
230 | + } | ||
231 | + | ||
232 | + // call all constructor hooks | ||
233 | + if (this._initHooks) { | ||
234 | + this.callInitHooks(); | ||
235 | + } | ||
236 | + }; | ||
237 | + | ||
238 | + // instantiate class without calling constructor | ||
239 | + var F = function () {}; | ||
240 | + F.prototype = this.prototype; | ||
241 | + | ||
242 | + var proto = new F(); | ||
243 | + proto.constructor = NewClass; | ||
244 | + | ||
245 | + NewClass.prototype = proto; | ||
246 | + | ||
247 | + //inherit parent's statics | ||
248 | + for (var i in this) { | ||
249 | + if (this.hasOwnProperty(i) && i !== 'prototype') { | ||
250 | + NewClass[i] = this[i]; | ||
251 | + } | ||
252 | + } | ||
253 | + | ||
254 | + // mix static properties into the class | ||
255 | + if (props.statics) { | ||
256 | + L.extend(NewClass, props.statics); | ||
257 | + delete props.statics; | ||
258 | + } | ||
259 | + | ||
260 | + // mix includes into the prototype | ||
261 | + if (props.includes) { | ||
262 | + L.Util.extend.apply(null, [proto].concat(props.includes)); | ||
263 | + delete props.includes; | ||
264 | + } | ||
265 | + | ||
266 | + // merge options | ||
267 | + if (props.options && proto.options) { | ||
268 | + props.options = L.extend({}, proto.options, props.options); | ||
269 | + } | ||
270 | + | ||
271 | + // mix given properties into the prototype | ||
272 | + L.extend(proto, props); | ||
273 | + | ||
274 | + proto._initHooks = []; | ||
275 | + | ||
276 | + var parent = this; | ||
277 | + // jshint camelcase: false | ||
278 | + NewClass.__super__ = parent.prototype; | ||
279 | + | ||
280 | + // add method for calling all hooks | ||
281 | + proto.callInitHooks = function () { | ||
282 | + | ||
283 | + if (this._initHooksCalled) { return; } | ||
284 | + | ||
285 | + if (parent.prototype.callInitHooks) { | ||
286 | + parent.prototype.callInitHooks.call(this); | ||
287 | + } | ||
288 | + | ||
289 | + this._initHooksCalled = true; | ||
290 | + | ||
291 | + for (var i = 0, len = proto._initHooks.length; i < len; i++) { | ||
292 | + proto._initHooks[i].call(this); | ||
293 | + } | ||
294 | + }; | ||
295 | + | ||
296 | + return NewClass; | ||
297 | +}; | ||
298 | + | ||
299 | + | ||
300 | +// method for adding properties to prototype | ||
301 | +L.Class.include = function (props) { | ||
302 | + L.extend(this.prototype, props); | ||
303 | +}; | ||
304 | + | ||
305 | +// merge new default options to the Class | ||
306 | +L.Class.mergeOptions = function (options) { | ||
307 | + L.extend(this.prototype.options, options); | ||
308 | +}; | ||
309 | + | ||
310 | +// add a constructor hook | ||
311 | +L.Class.addInitHook = function (fn) { // (Function) || (String, args...) | ||
312 | + var args = Array.prototype.slice.call(arguments, 1); | ||
313 | + | ||
314 | + var init = typeof fn === 'function' ? fn : function () { | ||
315 | + this[fn].apply(this, args); | ||
316 | + }; | ||
317 | + | ||
318 | + this.prototype._initHooks = this.prototype._initHooks || []; | ||
319 | + this.prototype._initHooks.push(init); | ||
320 | +}; | ||
321 | + | ||
322 | + | ||
323 | +/* | ||
324 | + * L.Mixin.Events is used to add custom events functionality to Leaflet classes. | ||
325 | + */ | ||
326 | + | ||
327 | +var eventsKey = '_leaflet_events'; | ||
328 | + | ||
329 | +L.Mixin = {}; | ||
330 | + | ||
331 | +L.Mixin.Events = { | ||
332 | + | ||
333 | + addEventListener: function (types, fn, context) { // (String, Function[, Object]) or (Object[, Object]) | ||
334 | + | ||
335 | + // types can be a map of types/handlers | ||
336 | + if (L.Util.invokeEach(types, this.addEventListener, this, fn, context)) { return this; } | ||
337 | + | ||
338 | + var events = this[eventsKey] = this[eventsKey] || {}, | ||
339 | + contextId = context && context !== this && L.stamp(context), | ||
340 | + i, len, event, type, indexKey, indexLenKey, typeIndex; | ||
341 | + | ||
342 | + // types can be a string of space-separated words | ||
343 | + types = L.Util.splitWords(types); | ||
344 | + | ||
345 | + for (i = 0, len = types.length; i < len; i++) { | ||
346 | + event = { | ||
347 | + action: fn, | ||
348 | + context: context || this | ||
349 | + }; | ||
350 | + type = types[i]; | ||
351 | + | ||
352 | + if (contextId) { | ||
353 | + // store listeners of a particular context in a separate hash (if it has an id) | ||
354 | + // gives a major performance boost when removing thousands of map layers | ||
355 | + | ||
356 | + indexKey = type + '_idx'; | ||
357 | + indexLenKey = indexKey + '_len'; | ||
358 | + | ||
359 | + typeIndex = events[indexKey] = events[indexKey] || {}; | ||
360 | + | ||
361 | + if (!typeIndex[contextId]) { | ||
362 | + typeIndex[contextId] = []; | ||
363 | + | ||
364 | + // keep track of the number of keys in the index to quickly check if it's empty | ||
365 | + events[indexLenKey] = (events[indexLenKey] || 0) + 1; | ||
366 | + } | ||
367 | + | ||
368 | + typeIndex[contextId].push(event); | ||
369 | + | ||
370 | + | ||
371 | + } else { | ||
372 | + events[type] = events[type] || []; | ||
373 | + events[type].push(event); | ||
374 | + } | ||
375 | + } | ||
376 | + | ||
377 | + return this; | ||
378 | + }, | ||
379 | + | ||
380 | + hasEventListeners: function (type) { // (String) -> Boolean | ||
381 | + var events = this[eventsKey]; | ||
382 | + return !!events && ((type in events && events[type].length > 0) || | ||
383 | + (type + '_idx' in events && events[type + '_idx_len'] > 0)); | ||
384 | + }, | ||
385 | + | ||
386 | + removeEventListener: function (types, fn, context) { // ([String, Function, Object]) or (Object[, Object]) | ||
387 | + | ||
388 | + if (!this[eventsKey]) { | ||
389 | + return this; | ||
390 | + } | ||
391 | + | ||
392 | + if (!types) { | ||
393 | + return this.clearAllEventListeners(); | ||
394 | + } | ||
395 | + | ||
396 | + if (L.Util.invokeEach(types, this.removeEventListener, this, fn, context)) { return this; } | ||
397 | + | ||
398 | + var events = this[eventsKey], | ||
399 | + contextId = context && context !== this && L.stamp(context), | ||
400 | + i, len, type, listeners, j, indexKey, indexLenKey, typeIndex, removed; | ||
401 | + | ||
402 | + types = L.Util.splitWords(types); | ||
403 | + | ||
404 | + for (i = 0, len = types.length; i < len; i++) { | ||
405 | + type = types[i]; | ||
406 | + indexKey = type + '_idx'; | ||
407 | + indexLenKey = indexKey + '_len'; | ||
408 | + | ||
409 | + typeIndex = events[indexKey]; | ||
410 | + | ||
411 | + if (!fn) { | ||
412 | + // clear all listeners for a type if function isn't specified | ||
413 | + delete events[type]; | ||
414 | + delete events[indexKey]; | ||
415 | + delete events[indexLenKey]; | ||
416 | + | ||
417 | + } else { | ||
418 | + listeners = contextId && typeIndex ? typeIndex[contextId] : events[type]; | ||
419 | + | ||
420 | + if (listeners) { | ||
421 | + for (j = listeners.length - 1; j >= 0; j--) { | ||
422 | + if ((listeners[j].action === fn) && (!context || (listeners[j].context === context))) { | ||
423 | + removed = listeners.splice(j, 1); | ||
424 | + // set the old action to a no-op, because it is possible | ||
425 | + // that the listener is being iterated over as part of a dispatch | ||
426 | + removed[0].action = L.Util.falseFn; | ||
427 | + } | ||
428 | + } | ||
429 | + | ||
430 | + if (context && typeIndex && (listeners.length === 0)) { | ||
431 | + delete typeIndex[contextId]; | ||
432 | + events[indexLenKey]--; | ||
433 | + } | ||
434 | + } | ||
435 | + } | ||
436 | + } | ||
437 | + | ||
438 | + return this; | ||
439 | + }, | ||
440 | + | ||
441 | + clearAllEventListeners: function () { | ||
442 | + delete this[eventsKey]; | ||
443 | + return this; | ||
444 | + }, | ||
445 | + | ||
446 | + fireEvent: function (type, data) { // (String[, Object]) | ||
447 | + if (!this.hasEventListeners(type)) { | ||
448 | + return this; | ||
449 | + } | ||
450 | + | ||
451 | + var event = L.Util.extend({}, data, { type: type, target: this }); | ||
452 | + | ||
453 | + var events = this[eventsKey], | ||
454 | + listeners, i, len, typeIndex, contextId; | ||
455 | + | ||
456 | + if (events[type]) { | ||
457 | + // make sure adding/removing listeners inside other listeners won't cause infinite loop | ||
458 | + listeners = events[type].slice(); | ||
459 | + | ||
460 | + for (i = 0, len = listeners.length; i < len; i++) { | ||
461 | + listeners[i].action.call(listeners[i].context, event); | ||
462 | + } | ||
463 | + } | ||
464 | + | ||
465 | + // fire event for the context-indexed listeners as well | ||
466 | + typeIndex = events[type + '_idx']; | ||
467 | + | ||
468 | + for (contextId in typeIndex) { | ||
469 | + listeners = typeIndex[contextId].slice(); | ||
470 | + | ||
471 | + if (listeners) { | ||
472 | + for (i = 0, len = listeners.length; i < len; i++) { | ||
473 | + listeners[i].action.call(listeners[i].context, event); | ||
474 | + } | ||
475 | + } | ||
476 | + } | ||
477 | + | ||
478 | + return this; | ||
479 | + }, | ||
480 | + | ||
481 | + addOneTimeEventListener: function (types, fn, context) { | ||
482 | + | ||
483 | + if (L.Util.invokeEach(types, this.addOneTimeEventListener, this, fn, context)) { return this; } | ||
484 | + | ||
485 | + var handler = L.bind(function () { | ||
486 | + this | ||
487 | + .removeEventListener(types, fn, context) | ||
488 | + .removeEventListener(types, handler, context); | ||
489 | + }, this); | ||
490 | + | ||
491 | + return this | ||
492 | + .addEventListener(types, fn, context) | ||
493 | + .addEventListener(types, handler, context); | ||
494 | + } | ||
495 | +}; | ||
496 | + | ||
497 | +L.Mixin.Events.on = L.Mixin.Events.addEventListener; | ||
498 | +L.Mixin.Events.off = L.Mixin.Events.removeEventListener; | ||
499 | +L.Mixin.Events.once = L.Mixin.Events.addOneTimeEventListener; | ||
500 | +L.Mixin.Events.fire = L.Mixin.Events.fireEvent; | ||
501 | + | ||
502 | + | ||
503 | +/* | ||
504 | + * L.Browser handles different browser and feature detections for internal Leaflet use. | ||
505 | + */ | ||
506 | + | ||
507 | +(function () { | ||
508 | + | ||
509 | + var ie = 'ActiveXObject' in window, | ||
510 | + ielt9 = ie && !document.addEventListener, | ||
511 | + | ||
512 | + // terrible browser detection to work around Safari / iOS / Android browser bugs | ||
513 | + ua = navigator.userAgent.toLowerCase(), | ||
514 | + webkit = ua.indexOf('webkit') !== -1, | ||
515 | + chrome = ua.indexOf('chrome') !== -1, | ||
516 | + phantomjs = ua.indexOf('phantom') !== -1, | ||
517 | + android = ua.indexOf('android') !== -1, | ||
518 | + android23 = ua.search('android [23]') !== -1, | ||
519 | + gecko = ua.indexOf('gecko') !== -1, | ||
520 | + | ||
521 | + mobile = typeof orientation !== undefined + '', | ||
522 | + msPointer = window.navigator && window.navigator.msPointerEnabled && | ||
523 | + window.navigator.msMaxTouchPoints && !window.PointerEvent, | ||
524 | + pointer = (window.PointerEvent && window.navigator.pointerEnabled && window.navigator.maxTouchPoints) || | ||
525 | + msPointer, | ||
526 | + retina = ('devicePixelRatio' in window && window.devicePixelRatio > 1) || | ||
527 | + ('matchMedia' in window && window.matchMedia('(min-resolution:144dpi)') && | ||
528 | + window.matchMedia('(min-resolution:144dpi)').matches), | ||
529 | + | ||
530 | + doc = document.documentElement, | ||
531 | + ie3d = ie && ('transition' in doc.style), | ||
532 | + webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23, | ||
533 | + gecko3d = 'MozPerspective' in doc.style, | ||
534 | + opera3d = 'OTransition' in doc.style, | ||
535 | + any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d || opera3d) && !phantomjs; | ||
536 | + | ||
537 | + | ||
538 | + // PhantomJS has 'ontouchstart' in document.documentElement, but doesn't actually support touch. | ||
539 | + // https://github.com/Leaflet/Leaflet/pull/1434#issuecomment-13843151 | ||
540 | + | ||
541 | + var touch = !window.L_NO_TOUCH && !phantomjs && (function () { | ||
542 | + | ||
543 | + var startName = 'ontouchstart'; | ||
544 | + | ||
545 | + // IE10+ (We simulate these into touch* events in L.DomEvent and L.DomEvent.Pointer) or WebKit, etc. | ||
546 | + if (pointer || (startName in doc)) { | ||
547 | + return true; | ||
548 | + } | ||
549 | + | ||
550 | + // Firefox/Gecko | ||
551 | + var div = document.createElement('div'), | ||
552 | + supported = false; | ||
553 | + | ||
554 | + if (!div.setAttribute) { | ||
555 | + return false; | ||
556 | + } | ||
557 | + div.setAttribute(startName, 'return;'); | ||
558 | + | ||
559 | + if (typeof div[startName] === 'function') { | ||
560 | + supported = true; | ||
561 | + } | ||
562 | + | ||
563 | + div.removeAttribute(startName); | ||
564 | + div = null; | ||
565 | + | ||
566 | + return supported; | ||
567 | + }()); | ||
568 | + | ||
569 | + | ||
570 | + L.Browser = { | ||
571 | + ie: ie, | ||
572 | + ielt9: ielt9, | ||
573 | + webkit: webkit, | ||
574 | + gecko: gecko && !webkit && !window.opera && !ie, | ||
575 | + | ||
576 | + android: android, | ||
577 | + android23: android23, | ||
578 | + | ||
579 | + chrome: chrome, | ||
580 | + | ||
581 | + ie3d: ie3d, | ||
582 | + webkit3d: webkit3d, | ||
583 | + gecko3d: gecko3d, | ||
584 | + opera3d: opera3d, | ||
585 | + any3d: any3d, | ||
586 | + | ||
587 | + mobile: mobile, | ||
588 | + mobileWebkit: mobile && webkit, | ||
589 | + mobileWebkit3d: mobile && webkit3d, | ||
590 | + mobileOpera: mobile && window.opera, | ||
591 | + | ||
592 | + touch: touch, | ||
593 | + msPointer: msPointer, | ||
594 | + pointer: pointer, | ||
595 | + | ||
596 | + retina: retina | ||
597 | + }; | ||
598 | + | ||
599 | +}()); | ||
600 | + | ||
601 | + | ||
602 | +/* | ||
603 | + * L.Point represents a point with x and y coordinates. | ||
604 | + */ | ||
605 | + | ||
606 | +L.Point = function (/*Number*/ x, /*Number*/ y, /*Boolean*/ round) { | ||
607 | + this.x = (round ? Math.round(x) : x); | ||
608 | + this.y = (round ? Math.round(y) : y); | ||
609 | +}; | ||
610 | + | ||
611 | +L.Point.prototype = { | ||
612 | + | ||
613 | + clone: function () { | ||
614 | + return new L.Point(this.x, this.y); | ||
615 | + }, | ||
616 | + | ||
617 | + // non-destructive, returns a new point | ||
618 | + add: function (point) { | ||
619 | + return this.clone()._add(L.point(point)); | ||
620 | + }, | ||
621 | + | ||
622 | + // destructive, used directly for performance in situations where it's safe to modify existing point | ||
623 | + _add: function (point) { | ||
624 | + this.x += point.x; | ||
625 | + this.y += point.y; | ||
626 | + return this; | ||
627 | + }, | ||
628 | + | ||
629 | + subtract: function (point) { | ||
630 | + return this.clone()._subtract(L.point(point)); | ||
631 | + }, | ||
632 | + | ||
633 | + _subtract: function (point) { | ||
634 | + this.x -= point.x; | ||
635 | + this.y -= point.y; | ||
636 | + return this; | ||
637 | + }, | ||
638 | + | ||
639 | + divideBy: function (num) { | ||
640 | + return this.clone()._divideBy(num); | ||
641 | + }, | ||
642 | + | ||
643 | + _divideBy: function (num) { | ||
644 | + this.x /= num; | ||
645 | + this.y /= num; | ||
646 | + return this; | ||
647 | + }, | ||
648 | + | ||
649 | + multiplyBy: function (num) { | ||
650 | + return this.clone()._multiplyBy(num); | ||
651 | + }, | ||
652 | + | ||
653 | + _multiplyBy: function (num) { | ||
654 | + this.x *= num; | ||
655 | + this.y *= num; | ||
656 | + return this; | ||
657 | + }, | ||
658 | + | ||
659 | + round: function () { | ||
660 | + return this.clone()._round(); | ||
661 | + }, | ||
662 | + | ||
663 | + _round: function () { | ||
664 | + this.x = Math.round(this.x); | ||
665 | + this.y = Math.round(this.y); | ||
666 | + return this; | ||
667 | + }, | ||
668 | + | ||
669 | + floor: function () { | ||
670 | + return this.clone()._floor(); | ||
671 | + }, | ||
672 | + | ||
673 | + _floor: function () { | ||
674 | + this.x = Math.floor(this.x); | ||
675 | + this.y = Math.floor(this.y); | ||
676 | + return this; | ||
677 | + }, | ||
678 | + | ||
679 | + distanceTo: function (point) { | ||
680 | + point = L.point(point); | ||
681 | + | ||
682 | + var x = point.x - this.x, | ||
683 | + y = point.y - this.y; | ||
684 | + | ||
685 | + return Math.sqrt(x * x + y * y); | ||
686 | + }, | ||
687 | + | ||
688 | + equals: function (point) { | ||
689 | + point = L.point(point); | ||
690 | + | ||
691 | + return point.x === this.x && | ||
692 | + point.y === this.y; | ||
693 | + }, | ||
694 | + | ||
695 | + contains: function (point) { | ||
696 | + point = L.point(point); | ||
697 | + | ||
698 | + return Math.abs(point.x) <= Math.abs(this.x) && | ||
699 | + Math.abs(point.y) <= Math.abs(this.y); | ||
700 | + }, | ||
701 | + | ||
702 | + toString: function () { | ||
703 | + return 'Point(' + | ||
704 | + L.Util.formatNum(this.x) + ', ' + | ||
705 | + L.Util.formatNum(this.y) + ')'; | ||
706 | + } | ||
707 | +}; | ||
708 | + | ||
709 | +L.point = function (x, y, round) { | ||
710 | + if (x instanceof L.Point) { | ||
711 | + return x; | ||
712 | + } | ||
713 | + if (L.Util.isArray(x)) { | ||
714 | + return new L.Point(x[0], x[1]); | ||
715 | + } | ||
716 | + if (x === undefined || x === null) { | ||
717 | + return x; | ||
718 | + } | ||
719 | + return new L.Point(x, y, round); | ||
720 | +}; | ||
721 | + | ||
722 | + | ||
723 | +/* | ||
724 | + * L.Bounds represents a rectangular area on the screen in pixel coordinates. | ||
725 | + */ | ||
726 | + | ||
727 | +L.Bounds = function (a, b) { //(Point, Point) or Point[] | ||
728 | + if (!a) { return; } | ||
729 | + | ||
730 | + var points = b ? [a, b] : a; | ||
731 | + | ||
732 | + for (var i = 0, len = points.length; i < len; i++) { | ||
733 | + this.extend(points[i]); | ||
734 | + } | ||
735 | +}; | ||
736 | + | ||
737 | +L.Bounds.prototype = { | ||
738 | + // extend the bounds to contain the given point | ||
739 | + extend: function (point) { // (Point) | ||
740 | + point = L.point(point); | ||
741 | + | ||
742 | + if (!this.min && !this.max) { | ||
743 | + this.min = point.clone(); | ||
744 | + this.max = point.clone(); | ||
745 | + } else { | ||
746 | + this.min.x = Math.min(point.x, this.min.x); | ||
747 | + this.max.x = Math.max(point.x, this.max.x); | ||
748 | + this.min.y = Math.min(point.y, this.min.y); | ||
749 | + this.max.y = Math.max(point.y, this.max.y); | ||
750 | + } | ||
751 | + return this; | ||
752 | + }, | ||
753 | + | ||
754 | + getCenter: function (round) { // (Boolean) -> Point | ||
755 | + return new L.Point( | ||
756 | + (this.min.x + this.max.x) / 2, | ||
757 | + (this.min.y + this.max.y) / 2, round); | ||
758 | + }, | ||
759 | + | ||
760 | + getBottomLeft: function () { // -> Point | ||
761 | + return new L.Point(this.min.x, this.max.y); | ||
762 | + }, | ||
763 | + | ||
764 | + getTopRight: function () { // -> Point | ||
765 | + return new L.Point(this.max.x, this.min.y); | ||
766 | + }, | ||
767 | + | ||
768 | + getSize: function () { | ||
769 | + return this.max.subtract(this.min); | ||
770 | + }, | ||
771 | + | ||
772 | + contains: function (obj) { // (Bounds) or (Point) -> Boolean | ||
773 | + var min, max; | ||
774 | + | ||
775 | + if (typeof obj[0] === 'number' || obj instanceof L.Point) { | ||
776 | + obj = L.point(obj); | ||
777 | + } else { | ||
778 | + obj = L.bounds(obj); | ||
779 | + } | ||
780 | + | ||
781 | + if (obj instanceof L.Bounds) { | ||
782 | + min = obj.min; | ||
783 | + max = obj.max; | ||
784 | + } else { | ||
785 | + min = max = obj; | ||
786 | + } | ||
787 | + | ||
788 | + return (min.x >= this.min.x) && | ||
789 | + (max.x <= this.max.x) && | ||
790 | + (min.y >= this.min.y) && | ||
791 | + (max.y <= this.max.y); | ||
792 | + }, | ||
793 | + | ||
794 | + intersects: function (bounds) { // (Bounds) -> Boolean | ||
795 | + bounds = L.bounds(bounds); | ||
796 | + | ||
797 | + var min = this.min, | ||
798 | + max = this.max, | ||
799 | + min2 = bounds.min, | ||
800 | + max2 = bounds.max, | ||
801 | + xIntersects = (max2.x >= min.x) && (min2.x <= max.x), | ||
802 | + yIntersects = (max2.y >= min.y) && (min2.y <= max.y); | ||
803 | + | ||
804 | + return xIntersects && yIntersects; | ||
805 | + }, | ||
806 | + | ||
807 | + isValid: function () { | ||
808 | + return !!(this.min && this.max); | ||
809 | + } | ||
810 | +}; | ||
811 | + | ||
812 | +L.bounds = function (a, b) { // (Bounds) or (Point, Point) or (Point[]) | ||
813 | + if (!a || a instanceof L.Bounds) { | ||
814 | + return a; | ||
815 | + } | ||
816 | + return new L.Bounds(a, b); | ||
817 | +}; | ||
818 | + | ||
819 | + | ||
820 | +/* | ||
821 | + * L.Transformation is an utility class to perform simple point transformations through a 2d-matrix. | ||
822 | + */ | ||
823 | + | ||
824 | +L.Transformation = function (a, b, c, d) { | ||
825 | + this._a = a; | ||
826 | + this._b = b; | ||
827 | + this._c = c; | ||
828 | + this._d = d; | ||
829 | +}; | ||
830 | + | ||
831 | +L.Transformation.prototype = { | ||
832 | + transform: function (point, scale) { // (Point, Number) -> Point | ||
833 | + return this._transform(point.clone(), scale); | ||
834 | + }, | ||
835 | + | ||
836 | + // destructive transform (faster) | ||
837 | + _transform: function (point, scale) { | ||
838 | + scale = scale || 1; | ||
839 | + point.x = scale * (this._a * point.x + this._b); | ||
840 | + point.y = scale * (this._c * point.y + this._d); | ||
841 | + return point; | ||
842 | + }, | ||
843 | + | ||
844 | + untransform: function (point, scale) { | ||
845 | + scale = scale || 1; | ||
846 | + return new L.Point( | ||
847 | + (point.x / scale - this._b) / this._a, | ||
848 | + (point.y / scale - this._d) / this._c); | ||
849 | + } | ||
850 | +}; | ||
851 | + | ||
852 | + | ||
853 | +/* | ||
854 | + * L.DomUtil contains various utility functions for working with DOM. | ||
855 | + */ | ||
856 | + | ||
857 | +L.DomUtil = { | ||
858 | + get: function (id) { | ||
859 | + return (typeof id === 'string' ? document.getElementById(id) : id); | ||
860 | + }, | ||
861 | + | ||
862 | + getStyle: function (el, style) { | ||
863 | + | ||
864 | + var value = el.style[style]; | ||
865 | + | ||
866 | + if (!value && el.currentStyle) { | ||
867 | + value = el.currentStyle[style]; | ||
868 | + } | ||
869 | + | ||
870 | + if ((!value || value === 'auto') && document.defaultView) { | ||
871 | + var css = document.defaultView.getComputedStyle(el, null); | ||
872 | + value = css ? css[style] : null; | ||
873 | + } | ||
874 | + | ||
875 | + return value === 'auto' ? null : value; | ||
876 | + }, | ||
877 | + | ||
878 | + getViewportOffset: function (element) { | ||
879 | + | ||
880 | + var top = 0, | ||
881 | + left = 0, | ||
882 | + el = element, | ||
883 | + docBody = document.body, | ||
884 | + docEl = document.documentElement, | ||
885 | + pos; | ||
886 | + | ||
887 | + do { | ||
888 | + top += el.offsetTop || 0; | ||
889 | + left += el.offsetLeft || 0; | ||
890 | + | ||
891 | + //add borders | ||
892 | + top += parseInt(L.DomUtil.getStyle(el, 'borderTopWidth'), 10) || 0; | ||
893 | + left += parseInt(L.DomUtil.getStyle(el, 'borderLeftWidth'), 10) || 0; | ||
894 | + | ||
895 | + pos = L.DomUtil.getStyle(el, 'position'); | ||
896 | + | ||
897 | + if (el.offsetParent === docBody && pos === 'absolute') { break; } | ||
898 | + | ||
899 | + if (pos === 'fixed') { | ||
900 | + top += docBody.scrollTop || docEl.scrollTop || 0; | ||
901 | + left += docBody.scrollLeft || docEl.scrollLeft || 0; | ||
902 | + break; | ||
903 | + } | ||
904 | + | ||
905 | + if (pos === 'relative' && !el.offsetLeft) { | ||
906 | + var width = L.DomUtil.getStyle(el, 'width'), | ||
907 | + maxWidth = L.DomUtil.getStyle(el, 'max-width'), | ||
908 | + r = el.getBoundingClientRect(); | ||
909 | + | ||
910 | + if (width !== 'none' || maxWidth !== 'none') { | ||
911 | + left += r.left + el.clientLeft; | ||
912 | + } | ||
913 | + | ||
914 | + //calculate full y offset since we're breaking out of the loop | ||
915 | + top += r.top + (docBody.scrollTop || docEl.scrollTop || 0); | ||
916 | + | ||
917 | + break; | ||
918 | + } | ||
919 | + | ||
920 | + el = el.offsetParent; | ||
921 | + | ||
922 | + } while (el); | ||
923 | + | ||
924 | + el = element; | ||
925 | + | ||
926 | + do { | ||
927 | + if (el === docBody) { break; } | ||
928 | + | ||
929 | + top -= el.scrollTop || 0; | ||
930 | + left -= el.scrollLeft || 0; | ||
931 | + | ||
932 | + el = el.parentNode; | ||
933 | + } while (el); | ||
934 | + | ||
935 | + return new L.Point(left, top); | ||
936 | + }, | ||
937 | + | ||
938 | + documentIsLtr: function () { | ||
939 | + if (!L.DomUtil._docIsLtrCached) { | ||
940 | + L.DomUtil._docIsLtrCached = true; | ||
941 | + L.DomUtil._docIsLtr = L.DomUtil.getStyle(document.body, 'direction') === 'ltr'; | ||
942 | + } | ||
943 | + return L.DomUtil._docIsLtr; | ||
944 | + }, | ||
945 | + | ||
946 | + create: function (tagName, className, container) { | ||
947 | + | ||
948 | + var el = document.createElement(tagName); | ||
949 | + el.className = className; | ||
950 | + | ||
951 | + if (container) { | ||
952 | + container.appendChild(el); | ||
953 | + } | ||
954 | + | ||
955 | + return el; | ||
956 | + }, | ||
957 | + | ||
958 | + hasClass: function (el, name) { | ||
959 | + if (el.classList !== undefined) { | ||
960 | + return el.classList.contains(name); | ||
961 | + } | ||
962 | + var className = L.DomUtil._getClass(el); | ||
963 | + return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className); | ||
964 | + }, | ||
965 | + | ||
966 | + addClass: function (el, name) { | ||
967 | + if (el.classList !== undefined) { | ||
968 | + var classes = L.Util.splitWords(name); | ||
969 | + for (var i = 0, len = classes.length; i < len; i++) { | ||
970 | + el.classList.add(classes[i]); | ||
971 | + } | ||
972 | + } else if (!L.DomUtil.hasClass(el, name)) { | ||
973 | + var className = L.DomUtil._getClass(el); | ||
974 | + L.DomUtil._setClass(el, (className ? className + ' ' : '') + name); | ||
975 | + } | ||
976 | + }, | ||
977 | + | ||
978 | + removeClass: function (el, name) { | ||
979 | + if (el.classList !== undefined) { | ||
980 | + el.classList.remove(name); | ||
981 | + } else { | ||
982 | + L.DomUtil._setClass(el, L.Util.trim((' ' + L.DomUtil._getClass(el) + ' ').replace(' ' + name + ' ', ' '))); | ||
983 | + } | ||
984 | + }, | ||
985 | + | ||
986 | + _setClass: function (el, name) { | ||
987 | + if (el.className.baseVal === undefined) { | ||
988 | + el.className = name; | ||
989 | + } else { | ||
990 | + // in case of SVG element | ||
991 | + el.className.baseVal = name; | ||
992 | + } | ||
993 | + }, | ||
994 | + | ||
995 | + _getClass: function (el) { | ||
996 | + return el.className.baseVal === undefined ? el.className : el.className.baseVal; | ||
997 | + }, | ||
998 | + | ||
999 | + setOpacity: function (el, value) { | ||
1000 | + | ||
1001 | + if ('opacity' in el.style) { | ||
1002 | + el.style.opacity = value; | ||
1003 | + | ||
1004 | + } else if ('filter' in el.style) { | ||
1005 | + | ||
1006 | + var filter = false, | ||
1007 | + filterName = 'DXImageTransform.Microsoft.Alpha'; | ||
1008 | + | ||
1009 | + // filters collection throws an error if we try to retrieve a filter that doesn't exist | ||
1010 | + try { | ||
1011 | + filter = el.filters.item(filterName); | ||
1012 | + } catch (e) { | ||
1013 | + // don't set opacity to 1 if we haven't already set an opacity, | ||
1014 | + // it isn't needed and breaks transparent pngs. | ||
1015 | + if (value === 1) { return; } | ||
1016 | + } | ||
1017 | + | ||
1018 | + value = Math.round(value * 100); | ||
1019 | + | ||
1020 | + if (filter) { | ||
1021 | + filter.Enabled = (value !== 100); | ||
1022 | + filter.Opacity = value; | ||
1023 | + } else { | ||
1024 | + el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')'; | ||
1025 | + } | ||
1026 | + } | ||
1027 | + }, | ||
1028 | + | ||
1029 | + testProp: function (props) { | ||
1030 | + | ||
1031 | + var style = document.documentElement.style; | ||
1032 | + | ||
1033 | + for (var i = 0; i < props.length; i++) { | ||
1034 | + if (props[i] in style) { | ||
1035 | + return props[i]; | ||
1036 | + } | ||
1037 | + } | ||
1038 | + return false; | ||
1039 | + }, | ||
1040 | + | ||
1041 | + getTranslateString: function (point) { | ||
1042 | + // on WebKit browsers (Chrome/Safari/iOS Safari/Android) using translate3d instead of translate | ||
1043 | + // makes animation smoother as it ensures HW accel is used. Firefox 13 doesn't care | ||
1044 | + // (same speed either way), Opera 12 doesn't support translate3d | ||
1045 | + | ||
1046 | + var is3d = L.Browser.webkit3d, | ||
1047 | + open = 'translate' + (is3d ? '3d' : '') + '(', | ||
1048 | + close = (is3d ? ',0' : '') + ')'; | ||
1049 | + | ||
1050 | + return open + point.x + 'px,' + point.y + 'px' + close; | ||
1051 | + }, | ||
1052 | + | ||
1053 | + getScaleString: function (scale, origin) { | ||
1054 | + | ||
1055 | + var preTranslateStr = L.DomUtil.getTranslateString(origin.add(origin.multiplyBy(-1 * scale))), | ||
1056 | + scaleStr = ' scale(' + scale + ') '; | ||
1057 | + | ||
1058 | + return preTranslateStr + scaleStr; | ||
1059 | + }, | ||
1060 | + | ||
1061 | + setPosition: function (el, point, disable3D) { // (HTMLElement, Point[, Boolean]) | ||
1062 | + | ||
1063 | + // jshint camelcase: false | ||
1064 | + el._leaflet_pos = point; | ||
1065 | + | ||
1066 | + if (!disable3D && L.Browser.any3d) { | ||
1067 | + el.style[L.DomUtil.TRANSFORM] = L.DomUtil.getTranslateString(point); | ||
1068 | + } else { | ||
1069 | + el.style.left = point.x + 'px'; | ||
1070 | + el.style.top = point.y + 'px'; | ||
1071 | + } | ||
1072 | + }, | ||
1073 | + | ||
1074 | + getPosition: function (el) { | ||
1075 | + // this method is only used for elements previously positioned using setPosition, | ||
1076 | + // so it's safe to cache the position for performance | ||
1077 | + | ||
1078 | + // jshint camelcase: false | ||
1079 | + return el._leaflet_pos; | ||
1080 | + } | ||
1081 | +}; | ||
1082 | + | ||
1083 | + | ||
1084 | +// prefix style property names | ||
1085 | + | ||
1086 | +L.DomUtil.TRANSFORM = L.DomUtil.testProp( | ||
1087 | + ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']); | ||
1088 | + | ||
1089 | +// webkitTransition comes first because some browser versions that drop vendor prefix don't do | ||
1090 | +// the same for the transitionend event, in particular the Android 4.1 stock browser | ||
1091 | + | ||
1092 | +L.DomUtil.TRANSITION = L.DomUtil.testProp( | ||
1093 | + ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']); | ||
1094 | + | ||
1095 | +L.DomUtil.TRANSITION_END = | ||
1096 | + L.DomUtil.TRANSITION === 'webkitTransition' || L.DomUtil.TRANSITION === 'OTransition' ? | ||
1097 | + L.DomUtil.TRANSITION + 'End' : 'transitionend'; | ||
1098 | + | ||
1099 | +(function () { | ||
1100 | + if ('onselectstart' in document) { | ||
1101 | + L.extend(L.DomUtil, { | ||
1102 | + disableTextSelection: function () { | ||
1103 | + L.DomEvent.on(window, 'selectstart', L.DomEvent.preventDefault); | ||
1104 | + }, | ||
1105 | + | ||
1106 | + enableTextSelection: function () { | ||
1107 | + L.DomEvent.off(window, 'selectstart', L.DomEvent.preventDefault); | ||
1108 | + } | ||
1109 | + }); | ||
1110 | + } else { | ||
1111 | + var userSelectProperty = L.DomUtil.testProp( | ||
1112 | + ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']); | ||
1113 | + | ||
1114 | + L.extend(L.DomUtil, { | ||
1115 | + disableTextSelection: function () { | ||
1116 | + if (userSelectProperty) { | ||
1117 | + var style = document.documentElement.style; | ||
1118 | + this._userSelect = style[userSelectProperty]; | ||
1119 | + style[userSelectProperty] = 'none'; | ||
1120 | + } | ||
1121 | + }, | ||
1122 | + | ||
1123 | + enableTextSelection: function () { | ||
1124 | + if (userSelectProperty) { | ||
1125 | + document.documentElement.style[userSelectProperty] = this._userSelect; | ||
1126 | + delete this._userSelect; | ||
1127 | + } | ||
1128 | + } | ||
1129 | + }); | ||
1130 | + } | ||
1131 | + | ||
1132 | + L.extend(L.DomUtil, { | ||
1133 | + disableImageDrag: function () { | ||
1134 | + L.DomEvent.on(window, 'dragstart', L.DomEvent.preventDefault); | ||
1135 | + }, | ||
1136 | + | ||
1137 | + enableImageDrag: function () { | ||
1138 | + L.DomEvent.off(window, 'dragstart', L.DomEvent.preventDefault); | ||
1139 | + } | ||
1140 | + }); | ||
1141 | +})(); | ||
1142 | + | ||
1143 | + | ||
1144 | +/* | ||
1145 | + * L.LatLng represents a geographical point with latitude and longitude coordinates. | ||
1146 | + */ | ||
1147 | + | ||
1148 | +L.LatLng = function (lat, lng, alt) { // (Number, Number, Number) | ||
1149 | + lat = parseFloat(lat); | ||
1150 | + lng = parseFloat(lng); | ||
1151 | + | ||
1152 | + if (isNaN(lat) || isNaN(lng)) { | ||
1153 | + throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')'); | ||
1154 | + } | ||
1155 | + | ||
1156 | + this.lat = lat; | ||
1157 | + this.lng = lng; | ||
1158 | + | ||
1159 | + if (alt !== undefined) { | ||
1160 | + this.alt = parseFloat(alt); | ||
1161 | + } | ||
1162 | +}; | ||
1163 | + | ||
1164 | +L.extend(L.LatLng, { | ||
1165 | + DEG_TO_RAD: Math.PI / 180, | ||
1166 | + RAD_TO_DEG: 180 / Math.PI, | ||
1167 | + MAX_MARGIN: 1.0E-9 // max margin of error for the "equals" check | ||
1168 | +}); | ||
1169 | + | ||
1170 | +L.LatLng.prototype = { | ||
1171 | + equals: function (obj) { // (LatLng) -> Boolean | ||
1172 | + if (!obj) { return false; } | ||
1173 | + | ||
1174 | + obj = L.latLng(obj); | ||
1175 | + | ||
1176 | + var margin = Math.max( | ||
1177 | + Math.abs(this.lat - obj.lat), | ||
1178 | + Math.abs(this.lng - obj.lng)); | ||
1179 | + | ||
1180 | + return margin <= L.LatLng.MAX_MARGIN; | ||
1181 | + }, | ||
1182 | + | ||
1183 | + toString: function (precision) { // (Number) -> String | ||
1184 | + return 'LatLng(' + | ||
1185 | + L.Util.formatNum(this.lat, precision) + ', ' + | ||
1186 | + L.Util.formatNum(this.lng, precision) + ')'; | ||
1187 | + }, | ||
1188 | + | ||
1189 | + // Haversine distance formula, see http://en.wikipedia.org/wiki/Haversine_formula | ||
1190 | + // TODO move to projection code, LatLng shouldn't know about Earth | ||
1191 | + distanceTo: function (other) { // (LatLng) -> Number | ||
1192 | + other = L.latLng(other); | ||
1193 | + | ||
1194 | + var R = 6378137, // earth radius in meters | ||
1195 | + d2r = L.LatLng.DEG_TO_RAD, | ||
1196 | + dLat = (other.lat - this.lat) * d2r, | ||
1197 | + dLon = (other.lng - this.lng) * d2r, | ||
1198 | + lat1 = this.lat * d2r, | ||
1199 | + lat2 = other.lat * d2r, | ||
1200 | + sin1 = Math.sin(dLat / 2), | ||
1201 | + sin2 = Math.sin(dLon / 2); | ||
1202 | + | ||
1203 | + var a = sin1 * sin1 + sin2 * sin2 * Math.cos(lat1) * Math.cos(lat2); | ||
1204 | + | ||
1205 | + return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); | ||
1206 | + }, | ||
1207 | + | ||
1208 | + wrap: function (a, b) { // (Number, Number) -> LatLng | ||
1209 | + var lng = this.lng; | ||
1210 | + | ||
1211 | + a = a || -180; | ||
1212 | + b = b || 180; | ||
1213 | + | ||
1214 | + lng = (lng + b) % (b - a) + (lng < a || lng === b ? b : a); | ||
1215 | + | ||
1216 | + return new L.LatLng(this.lat, lng); | ||
1217 | + } | ||
1218 | +}; | ||
1219 | + | ||
1220 | +L.latLng = function (a, b) { // (LatLng) or ([Number, Number]) or (Number, Number) | ||
1221 | + if (a instanceof L.LatLng) { | ||
1222 | + return a; | ||
1223 | + } | ||
1224 | + if (L.Util.isArray(a)) { | ||
1225 | + if (typeof a[0] === 'number' || typeof a[0] === 'string') { | ||
1226 | + return new L.LatLng(a[0], a[1], a[2]); | ||
1227 | + } else { | ||
1228 | + return null; | ||
1229 | + } | ||
1230 | + } | ||
1231 | + if (a === undefined || a === null) { | ||
1232 | + return a; | ||
1233 | + } | ||
1234 | + if (typeof a === 'object' && 'lat' in a) { | ||
1235 | + return new L.LatLng(a.lat, 'lng' in a ? a.lng : a.lon); | ||
1236 | + } | ||
1237 | + if (b === undefined) { | ||
1238 | + return null; | ||
1239 | + } | ||
1240 | + return new L.LatLng(a, b); | ||
1241 | +}; | ||
1242 | + | ||
1243 | + | ||
1244 | + | ||
1245 | +/* | ||
1246 | + * L.LatLngBounds represents a rectangular area on the map in geographical coordinates. | ||
1247 | + */ | ||
1248 | + | ||
1249 | +L.LatLngBounds = function (southWest, northEast) { // (LatLng, LatLng) or (LatLng[]) | ||
1250 | + if (!southWest) { return; } | ||
1251 | + | ||
1252 | + var latlngs = northEast ? [southWest, northEast] : southWest; | ||
1253 | + | ||
1254 | + for (var i = 0, len = latlngs.length; i < len; i++) { | ||
1255 | + this.extend(latlngs[i]); | ||
1256 | + } | ||
1257 | +}; | ||
1258 | + | ||
1259 | +L.LatLngBounds.prototype = { | ||
1260 | + // extend the bounds to contain the given point or bounds | ||
1261 | + extend: function (obj) { // (LatLng) or (LatLngBounds) | ||
1262 | + if (!obj) { return this; } | ||
1263 | + | ||
1264 | + var latLng = L.latLng(obj); | ||
1265 | + if (latLng !== null) { | ||
1266 | + obj = latLng; | ||
1267 | + } else { | ||
1268 | + obj = L.latLngBounds(obj); | ||
1269 | + } | ||
1270 | + | ||
1271 | + if (obj instanceof L.LatLng) { | ||
1272 | + if (!this._southWest && !this._northEast) { | ||
1273 | + this._southWest = new L.LatLng(obj.lat, obj.lng); | ||
1274 | + this._northEast = new L.LatLng(obj.lat, obj.lng); | ||
1275 | + } else { | ||
1276 | + this._southWest.lat = Math.min(obj.lat, this._southWest.lat); | ||
1277 | + this._southWest.lng = Math.min(obj.lng, this._southWest.lng); | ||
1278 | + | ||
1279 | + this._northEast.lat = Math.max(obj.lat, this._northEast.lat); | ||
1280 | + this._northEast.lng = Math.max(obj.lng, this._northEast.lng); | ||
1281 | + } | ||
1282 | + } else if (obj instanceof L.LatLngBounds) { | ||
1283 | + this.extend(obj._southWest); | ||
1284 | + this.extend(obj._northEast); | ||
1285 | + } | ||
1286 | + return this; | ||
1287 | + }, | ||
1288 | + | ||
1289 | + // extend the bounds by a percentage | ||
1290 | + pad: function (bufferRatio) { // (Number) -> LatLngBounds | ||
1291 | + var sw = this._southWest, | ||
1292 | + ne = this._northEast, | ||
1293 | + heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio, | ||
1294 | + widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio; | ||
1295 | + | ||
1296 | + return new L.LatLngBounds( | ||
1297 | + new L.LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer), | ||
1298 | + new L.LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer)); | ||
1299 | + }, | ||
1300 | + | ||
1301 | + getCenter: function () { // -> LatLng | ||
1302 | + return new L.LatLng( | ||
1303 | + (this._southWest.lat + this._northEast.lat) / 2, | ||
1304 | + (this._southWest.lng + this._northEast.lng) / 2); | ||
1305 | + }, | ||
1306 | + | ||
1307 | + getSouthWest: function () { | ||
1308 | + return this._southWest; | ||
1309 | + }, | ||
1310 | + | ||
1311 | + getNorthEast: function () { | ||
1312 | + return this._northEast; | ||
1313 | + }, | ||
1314 | + | ||
1315 | + getNorthWest: function () { | ||
1316 | + return new L.LatLng(this.getNorth(), this.getWest()); | ||
1317 | + }, | ||
1318 | + | ||
1319 | + getSouthEast: function () { | ||
1320 | + return new L.LatLng(this.getSouth(), this.getEast()); | ||
1321 | + }, | ||
1322 | + | ||
1323 | + getWest: function () { | ||
1324 | + return this._southWest.lng; | ||
1325 | + }, | ||
1326 | + | ||
1327 | + getSouth: function () { | ||
1328 | + return this._southWest.lat; | ||
1329 | + }, | ||
1330 | + | ||
1331 | + getEast: function () { | ||
1332 | + return this._northEast.lng; | ||
1333 | + }, | ||
1334 | + | ||
1335 | + getNorth: function () { | ||
1336 | + return this._northEast.lat; | ||
1337 | + }, | ||
1338 | + | ||
1339 | + contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean | ||
1340 | + if (typeof obj[0] === 'number' || obj instanceof L.LatLng) { | ||
1341 | + obj = L.latLng(obj); | ||
1342 | + } else { | ||
1343 | + obj = L.latLngBounds(obj); | ||
1344 | + } | ||
1345 | + | ||
1346 | + var sw = this._southWest, | ||
1347 | + ne = this._northEast, | ||
1348 | + sw2, ne2; | ||
1349 | + | ||
1350 | + if (obj instanceof L.LatLngBounds) { | ||
1351 | + sw2 = obj.getSouthWest(); | ||
1352 | + ne2 = obj.getNorthEast(); | ||
1353 | + } else { | ||
1354 | + sw2 = ne2 = obj; | ||
1355 | + } | ||
1356 | + | ||
1357 | + return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) && | ||
1358 | + (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng); | ||
1359 | + }, | ||
1360 | + | ||
1361 | + intersects: function (bounds) { // (LatLngBounds) | ||
1362 | + bounds = L.latLngBounds(bounds); | ||
1363 | + | ||
1364 | + var sw = this._southWest, | ||
1365 | + ne = this._northEast, | ||
1366 | + sw2 = bounds.getSouthWest(), | ||
1367 | + ne2 = bounds.getNorthEast(), | ||
1368 | + | ||
1369 | + latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat), | ||
1370 | + lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng); | ||
1371 | + | ||
1372 | + return latIntersects && lngIntersects; | ||
1373 | + }, | ||
1374 | + | ||
1375 | + toBBoxString: function () { | ||
1376 | + return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(','); | ||
1377 | + }, | ||
1378 | + | ||
1379 | + equals: function (bounds) { // (LatLngBounds) | ||
1380 | + if (!bounds) { return false; } | ||
1381 | + | ||
1382 | + bounds = L.latLngBounds(bounds); | ||
1383 | + | ||
1384 | + return this._southWest.equals(bounds.getSouthWest()) && | ||
1385 | + this._northEast.equals(bounds.getNorthEast()); | ||
1386 | + }, | ||
1387 | + | ||
1388 | + isValid: function () { | ||
1389 | + return !!(this._southWest && this._northEast); | ||
1390 | + } | ||
1391 | +}; | ||
1392 | + | ||
1393 | +//TODO International date line? | ||
1394 | + | ||
1395 | +L.latLngBounds = function (a, b) { // (LatLngBounds) or (LatLng, LatLng) | ||
1396 | + if (!a || a instanceof L.LatLngBounds) { | ||
1397 | + return a; | ||
1398 | + } | ||
1399 | + return new L.LatLngBounds(a, b); | ||
1400 | +}; | ||
1401 | + | ||
1402 | + | ||
1403 | +/* | ||
1404 | + * L.Projection contains various geographical projections used by CRS classes. | ||
1405 | + */ | ||
1406 | + | ||
1407 | +L.Projection = {}; | ||
1408 | + | ||
1409 | + | ||
1410 | +/* | ||
1411 | + * Spherical Mercator is the most popular map projection, used by EPSG:3857 CRS used by default. | ||
1412 | + */ | ||
1413 | + | ||
1414 | +L.Projection.SphericalMercator = { | ||
1415 | + MAX_LATITUDE: 85.0511287798, | ||
1416 | + | ||
1417 | + project: function (latlng) { // (LatLng) -> Point | ||
1418 | + var d = L.LatLng.DEG_TO_RAD, | ||
1419 | + max = this.MAX_LATITUDE, | ||
1420 | + lat = Math.max(Math.min(max, latlng.lat), -max), | ||
1421 | + x = latlng.lng * d, | ||
1422 | + y = lat * d; | ||
1423 | + | ||
1424 | + y = Math.log(Math.tan((Math.PI / 4) + (y / 2))); | ||
1425 | + | ||
1426 | + return new L.Point(x, y); | ||
1427 | + }, | ||
1428 | + | ||
1429 | + unproject: function (point) { // (Point, Boolean) -> LatLng | ||
1430 | + var d = L.LatLng.RAD_TO_DEG, | ||
1431 | + lng = point.x * d, | ||
1432 | + lat = (2 * Math.atan(Math.exp(point.y)) - (Math.PI / 2)) * d; | ||
1433 | + | ||
1434 | + return new L.LatLng(lat, lng); | ||
1435 | + } | ||
1436 | +}; | ||
1437 | + | ||
1438 | + | ||
1439 | +/* | ||
1440 | + * Simple equirectangular (Plate Carree) projection, used by CRS like EPSG:4326 and Simple. | ||
1441 | + */ | ||
1442 | + | ||
1443 | +L.Projection.LonLat = { | ||
1444 | + project: function (latlng) { | ||
1445 | + return new L.Point(latlng.lng, latlng.lat); | ||
1446 | + }, | ||
1447 | + | ||
1448 | + unproject: function (point) { | ||
1449 | + return new L.LatLng(point.y, point.x); | ||
1450 | + } | ||
1451 | +}; | ||
1452 | + | ||
1453 | + | ||
1454 | +/* | ||
1455 | + * L.CRS is a base object for all defined CRS (Coordinate Reference Systems) in Leaflet. | ||
1456 | + */ | ||
1457 | + | ||
1458 | +L.CRS = { | ||
1459 | + latLngToPoint: function (latlng, zoom) { // (LatLng, Number) -> Point | ||
1460 | + var projectedPoint = this.projection.project(latlng), | ||
1461 | + scale = this.scale(zoom); | ||
1462 | + | ||
1463 | + return this.transformation._transform(projectedPoint, scale); | ||
1464 | + }, | ||
1465 | + | ||
1466 | + pointToLatLng: function (point, zoom) { // (Point, Number[, Boolean]) -> LatLng | ||
1467 | + var scale = this.scale(zoom), | ||
1468 | + untransformedPoint = this.transformation.untransform(point, scale); | ||
1469 | + | ||
1470 | + return this.projection.unproject(untransformedPoint); | ||
1471 | + }, | ||
1472 | + | ||
1473 | + project: function (latlng) { | ||
1474 | + return this.projection.project(latlng); | ||
1475 | + }, | ||
1476 | + | ||
1477 | + scale: function (zoom) { | ||
1478 | + return 256 * Math.pow(2, zoom); | ||
1479 | + }, | ||
1480 | + | ||
1481 | + getSize: function (zoom) { | ||
1482 | + var s = this.scale(zoom); | ||
1483 | + return L.point(s, s); | ||
1484 | + } | ||
1485 | +}; | ||
1486 | + | ||
1487 | + | ||
1488 | +/* | ||
1489 | + * A simple CRS that can be used for flat non-Earth maps like panoramas or game maps. | ||
1490 | + */ | ||
1491 | + | ||
1492 | +L.CRS.Simple = L.extend({}, L.CRS, { | ||
1493 | + projection: L.Projection.LonLat, | ||
1494 | + transformation: new L.Transformation(1, 0, -1, 0), | ||
1495 | + | ||
1496 | + scale: function (zoom) { | ||
1497 | + return Math.pow(2, zoom); | ||
1498 | + } | ||
1499 | +}); | ||
1500 | + | ||
1501 | + | ||
1502 | +/* | ||
1503 | + * L.CRS.EPSG3857 (Spherical Mercator) is the most common CRS for web mapping | ||
1504 | + * and is used by Leaflet by default. | ||
1505 | + */ | ||
1506 | + | ||
1507 | +L.CRS.EPSG3857 = L.extend({}, L.CRS, { | ||
1508 | + code: 'EPSG:3857', | ||
1509 | + | ||
1510 | + projection: L.Projection.SphericalMercator, | ||
1511 | + transformation: new L.Transformation(0.5 / Math.PI, 0.5, -0.5 / Math.PI, 0.5), | ||
1512 | + | ||
1513 | + project: function (latlng) { // (LatLng) -> Point | ||
1514 | + var projectedPoint = this.projection.project(latlng), | ||
1515 | + earthRadius = 6378137; | ||
1516 | + return projectedPoint.multiplyBy(earthRadius); | ||
1517 | + } | ||
1518 | +}); | ||
1519 | + | ||
1520 | +L.CRS.EPSG900913 = L.extend({}, L.CRS.EPSG3857, { | ||
1521 | + code: 'EPSG:900913' | ||
1522 | +}); | ||
1523 | + | ||
1524 | + | ||
1525 | +/* | ||
1526 | + * L.CRS.EPSG4326 is a CRS popular among advanced GIS specialists. | ||
1527 | + */ | ||
1528 | + | ||
1529 | +L.CRS.EPSG4326 = L.extend({}, L.CRS, { | ||
1530 | + code: 'EPSG:4326', | ||
1531 | + | ||
1532 | + projection: L.Projection.LonLat, | ||
1533 | + transformation: new L.Transformation(1 / 360, 0.5, -1 / 360, 0.5) | ||
1534 | +}); | ||
1535 | + | ||
1536 | + | ||
1537 | +/* | ||
1538 | + * L.Map is the central class of the API - it is used to create a map. | ||
1539 | + */ | ||
1540 | + | ||
1541 | +L.Map = L.Class.extend({ | ||
1542 | + | ||
1543 | + includes: L.Mixin.Events, | ||
1544 | + | ||
1545 | + options: { | ||
1546 | + crs: L.CRS.EPSG3857, | ||
1547 | + | ||
1548 | + /* | ||
1549 | + center: LatLng, | ||
1550 | + zoom: Number, | ||
1551 | + layers: Array, | ||
1552 | + */ | ||
1553 | + | ||
1554 | + fadeAnimation: L.DomUtil.TRANSITION && !L.Browser.android23, | ||
1555 | + trackResize: true, | ||
1556 | + markerZoomAnimation: L.DomUtil.TRANSITION && L.Browser.any3d | ||
1557 | + }, | ||
1558 | + | ||
1559 | + initialize: function (id, options) { // (HTMLElement or String, Object) | ||
1560 | + options = L.setOptions(this, options); | ||
1561 | + | ||
1562 | + | ||
1563 | + this._initContainer(id); | ||
1564 | + this._initLayout(); | ||
1565 | + | ||
1566 | + // hack for https://github.com/Leaflet/Leaflet/issues/1980 | ||
1567 | + this._onResize = L.bind(this._onResize, this); | ||
1568 | + | ||
1569 | + this._initEvents(); | ||
1570 | + | ||
1571 | + if (options.maxBounds) { | ||
1572 | + this.setMaxBounds(options.maxBounds); | ||
1573 | + } | ||
1574 | + | ||
1575 | + if (options.center && options.zoom !== undefined) { | ||
1576 | + this.setView(L.latLng(options.center), options.zoom, {reset: true}); | ||
1577 | + } | ||
1578 | + | ||
1579 | + this._handlers = []; | ||
1580 | + | ||
1581 | + this._layers = {}; | ||
1582 | + this._zoomBoundLayers = {}; | ||
1583 | + this._tileLayersNum = 0; | ||
1584 | + | ||
1585 | + this.callInitHooks(); | ||
1586 | + | ||
1587 | + this._addLayers(options.layers); | ||
1588 | + }, | ||
1589 | + | ||
1590 | + | ||
1591 | + // public methods that modify map state | ||
1592 | + | ||
1593 | + // replaced by animation-powered implementation in Map.PanAnimation.js | ||
1594 | + setView: function (center, zoom) { | ||
1595 | + zoom = zoom === undefined ? this.getZoom() : zoom; | ||
1596 | + this._resetView(L.latLng(center), this._limitZoom(zoom)); | ||
1597 | + return this; | ||
1598 | + }, | ||
1599 | + | ||
1600 | + setZoom: function (zoom, options) { | ||
1601 | + if (!this._loaded) { | ||
1602 | + this._zoom = this._limitZoom(zoom); | ||
1603 | + return this; | ||
1604 | + } | ||
1605 | + return this.setView(this.getCenter(), zoom, {zoom: options}); | ||
1606 | + }, | ||
1607 | + | ||
1608 | + zoomIn: function (delta, options) { | ||
1609 | + return this.setZoom(this._zoom + (delta || 1), options); | ||
1610 | + }, | ||
1611 | + | ||
1612 | + zoomOut: function (delta, options) { | ||
1613 | + return this.setZoom(this._zoom - (delta || 1), options); | ||
1614 | + }, | ||
1615 | + | ||
1616 | + setZoomAround: function (latlng, zoom, options) { | ||
1617 | + var scale = this.getZoomScale(zoom), | ||
1618 | + viewHalf = this.getSize().divideBy(2), | ||
1619 | + containerPoint = latlng instanceof L.Point ? latlng : this.latLngToContainerPoint(latlng), | ||
1620 | + | ||
1621 | + centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale), | ||
1622 | + newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset)); | ||
1623 | + | ||
1624 | + return this.setView(newCenter, zoom, {zoom: options}); | ||
1625 | + }, | ||
1626 | + | ||
1627 | + fitBounds: function (bounds, options) { | ||
1628 | + | ||
1629 | + options = options || {}; | ||
1630 | + bounds = bounds.getBounds ? bounds.getBounds() : L.latLngBounds(bounds); | ||
1631 | + | ||
1632 | + var paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]), | ||
1633 | + paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]), | ||
1634 | + | ||
1635 | + zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR)), | ||
1636 | + paddingOffset = paddingBR.subtract(paddingTL).divideBy(2), | ||
1637 | + | ||
1638 | + swPoint = this.project(bounds.getSouthWest(), zoom), | ||
1639 | + nePoint = this.project(bounds.getNorthEast(), zoom), | ||
1640 | + center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom); | ||
1641 | + | ||
1642 | + zoom = options && options.maxZoom ? Math.min(options.maxZoom, zoom) : zoom; | ||
1643 | + | ||
1644 | + return this.setView(center, zoom, options); | ||
1645 | + }, | ||
1646 | + | ||
1647 | + fitWorld: function (options) { | ||
1648 | + return this.fitBounds([[-90, -180], [90, 180]], options); | ||
1649 | + }, | ||
1650 | + | ||
1651 | + panTo: function (center, options) { // (LatLng) | ||
1652 | + return this.setView(center, this._zoom, {pan: options}); | ||
1653 | + }, | ||
1654 | + | ||
1655 | + panBy: function (offset) { // (Point) | ||
1656 | + // replaced with animated panBy in Map.PanAnimation.js | ||
1657 | + this.fire('movestart'); | ||
1658 | + | ||
1659 | + this._rawPanBy(L.point(offset)); | ||
1660 | + | ||
1661 | + this.fire('move'); | ||
1662 | + return this.fire('moveend'); | ||
1663 | + }, | ||
1664 | + | ||
1665 | + setMaxBounds: function (bounds) { | ||
1666 | + bounds = L.latLngBounds(bounds); | ||
1667 | + | ||
1668 | + this.options.maxBounds = bounds; | ||
1669 | + | ||
1670 | + if (!bounds) { | ||
1671 | + return this.off('moveend', this._panInsideMaxBounds, this); | ||
1672 | + } | ||
1673 | + | ||
1674 | + if (this._loaded) { | ||
1675 | + this._panInsideMaxBounds(); | ||
1676 | + } | ||
1677 | + | ||
1678 | + return this.on('moveend', this._panInsideMaxBounds, this); | ||
1679 | + }, | ||
1680 | + | ||
1681 | + panInsideBounds: function (bounds, options) { | ||
1682 | + var center = this.getCenter(), | ||
1683 | + newCenter = this._limitCenter(center, this._zoom, bounds); | ||
1684 | + | ||
1685 | + if (center.equals(newCenter)) { return this; } | ||
1686 | + | ||
1687 | + return this.panTo(newCenter, options); | ||
1688 | + }, | ||
1689 | + | ||
1690 | + addLayer: function (layer) { | ||
1691 | + // TODO method is too big, refactor | ||
1692 | + | ||
1693 | + var id = L.stamp(layer); | ||
1694 | + | ||
1695 | + if (this._layers[id]) { return this; } | ||
1696 | + | ||
1697 | + this._layers[id] = layer; | ||
1698 | + | ||
1699 | + // TODO getMaxZoom, getMinZoom in ILayer (instead of options) | ||
1700 | + if (layer.options && (!isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom))) { | ||
1701 | + this._zoomBoundLayers[id] = layer; | ||
1702 | + this._updateZoomLevels(); | ||
1703 | + } | ||
1704 | + | ||
1705 | + // TODO looks ugly, refactor!!! | ||
1706 | + if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) { | ||
1707 | + this._tileLayersNum++; | ||
1708 | + this._tileLayersToLoad++; | ||
1709 | + layer.on('load', this._onTileLayerLoad, this); | ||
1710 | + } | ||
1711 | + | ||
1712 | + if (this._loaded) { | ||
1713 | + this._layerAdd(layer); | ||
1714 | + } | ||
1715 | + | ||
1716 | + return this; | ||
1717 | + }, | ||
1718 | + | ||
1719 | + removeLayer: function (layer) { | ||
1720 | + var id = L.stamp(layer); | ||
1721 | + | ||
1722 | + if (!this._layers[id]) { return this; } | ||
1723 | + | ||
1724 | + if (this._loaded) { | ||
1725 | + layer.onRemove(this); | ||
1726 | + } | ||
1727 | + | ||
1728 | + delete this._layers[id]; | ||
1729 | + | ||
1730 | + if (this._loaded) { | ||
1731 | + this.fire('layerremove', {layer: layer}); | ||
1732 | + } | ||
1733 | + | ||
1734 | + if (this._zoomBoundLayers[id]) { | ||
1735 | + delete this._zoomBoundLayers[id]; | ||
1736 | + this._updateZoomLevels(); | ||
1737 | + } | ||
1738 | + | ||
1739 | + // TODO looks ugly, refactor | ||
1740 | + if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) { | ||
1741 | + this._tileLayersNum--; | ||
1742 | + this._tileLayersToLoad--; | ||
1743 | + layer.off('load', this._onTileLayerLoad, this); | ||
1744 | + } | ||
1745 | + | ||
1746 | + return this; | ||
1747 | + }, | ||
1748 | + | ||
1749 | + hasLayer: function (layer) { | ||
1750 | + if (!layer) { return false; } | ||
1751 | + | ||
1752 | + return (L.stamp(layer) in this._layers); | ||
1753 | + }, | ||
1754 | + | ||
1755 | + eachLayer: function (method, context) { | ||
1756 | + for (var i in this._layers) { | ||
1757 | + method.call(context, this._layers[i]); | ||
1758 | + } | ||
1759 | + return this; | ||
1760 | + }, | ||
1761 | + | ||
1762 | + invalidateSize: function (options) { | ||
1763 | + if (!this._loaded) { return this; } | ||
1764 | + | ||
1765 | + options = L.extend({ | ||
1766 | + animate: false, | ||
1767 | + pan: true | ||
1768 | + }, options === true ? {animate: true} : options); | ||
1769 | + | ||
1770 | + var oldSize = this.getSize(); | ||
1771 | + this._sizeChanged = true; | ||
1772 | + this._initialCenter = null; | ||
1773 | + | ||
1774 | + var newSize = this.getSize(), | ||
1775 | + oldCenter = oldSize.divideBy(2).round(), | ||
1776 | + newCenter = newSize.divideBy(2).round(), | ||
1777 | + offset = oldCenter.subtract(newCenter); | ||
1778 | + | ||
1779 | + if (!offset.x && !offset.y) { return this; } | ||
1780 | + | ||
1781 | + if (options.animate && options.pan) { | ||
1782 | + this.panBy(offset); | ||
1783 | + | ||
1784 | + } else { | ||
1785 | + if (options.pan) { | ||
1786 | + this._rawPanBy(offset); | ||
1787 | + } | ||
1788 | + | ||
1789 | + this.fire('move'); | ||
1790 | + | ||
1791 | + if (options.debounceMoveend) { | ||
1792 | + clearTimeout(this._sizeTimer); | ||
1793 | + this._sizeTimer = setTimeout(L.bind(this.fire, this, 'moveend'), 200); | ||
1794 | + } else { | ||
1795 | + this.fire('moveend'); | ||
1796 | + } | ||
1797 | + } | ||
1798 | + | ||
1799 | + return this.fire('resize', { | ||
1800 | + oldSize: oldSize, | ||
1801 | + newSize: newSize | ||
1802 | + }); | ||
1803 | + }, | ||
1804 | + | ||
1805 | + // TODO handler.addTo | ||
1806 | + addHandler: function (name, HandlerClass) { | ||
1807 | + if (!HandlerClass) { return this; } | ||
1808 | + | ||
1809 | + var handler = this[name] = new HandlerClass(this); | ||
1810 | + | ||
1811 | + this._handlers.push(handler); | ||
1812 | + | ||
1813 | + if (this.options[name]) { | ||
1814 | + handler.enable(); | ||
1815 | + } | ||
1816 | + | ||
1817 | + return this; | ||
1818 | + }, | ||
1819 | + | ||
1820 | + remove: function () { | ||
1821 | + if (this._loaded) { | ||
1822 | + this.fire('unload'); | ||
1823 | + } | ||
1824 | + | ||
1825 | + this._initEvents('off'); | ||
1826 | + | ||
1827 | + try { | ||
1828 | + // throws error in IE6-8 | ||
1829 | + delete this._container._leaflet; | ||
1830 | + } catch (e) { | ||
1831 | + this._container._leaflet = undefined; | ||
1832 | + } | ||
1833 | + | ||
1834 | + this._clearPanes(); | ||
1835 | + if (this._clearControlPos) { | ||
1836 | + this._clearControlPos(); | ||
1837 | + } | ||
1838 | + | ||
1839 | + this._clearHandlers(); | ||
1840 | + | ||
1841 | + return this; | ||
1842 | + }, | ||
1843 | + | ||
1844 | + | ||
1845 | + // public methods for getting map state | ||
1846 | + | ||
1847 | + getCenter: function () { // (Boolean) -> LatLng | ||
1848 | + this._checkIfLoaded(); | ||
1849 | + | ||
1850 | + if (this._initialCenter && !this._moved()) { | ||
1851 | + return this._initialCenter; | ||
1852 | + } | ||
1853 | + return this.layerPointToLatLng(this._getCenterLayerPoint()); | ||
1854 | + }, | ||
1855 | + | ||
1856 | + getZoom: function () { | ||
1857 | + return this._zoom; | ||
1858 | + }, | ||
1859 | + | ||
1860 | + getBounds: function () { | ||
1861 | + var bounds = this.getPixelBounds(), | ||
1862 | + sw = this.unproject(bounds.getBottomLeft()), | ||
1863 | + ne = this.unproject(bounds.getTopRight()); | ||
1864 | + | ||
1865 | + return new L.LatLngBounds(sw, ne); | ||
1866 | + }, | ||
1867 | + | ||
1868 | + getMinZoom: function () { | ||
1869 | + return this.options.minZoom === undefined ? | ||
1870 | + (this._layersMinZoom === undefined ? 0 : this._layersMinZoom) : | ||
1871 | + this.options.minZoom; | ||
1872 | + }, | ||
1873 | + | ||
1874 | + getMaxZoom: function () { | ||
1875 | + return this.options.maxZoom === undefined ? | ||
1876 | + (this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom) : | ||
1877 | + this.options.maxZoom; | ||
1878 | + }, | ||
1879 | + | ||
1880 | + getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number | ||
1881 | + bounds = L.latLngBounds(bounds); | ||
1882 | + | ||
1883 | + var zoom = this.getMinZoom() - (inside ? 1 : 0), | ||
1884 | + maxZoom = this.getMaxZoom(), | ||
1885 | + size = this.getSize(), | ||
1886 | + | ||
1887 | + nw = bounds.getNorthWest(), | ||
1888 | + se = bounds.getSouthEast(), | ||
1889 | + | ||
1890 | + zoomNotFound = true, | ||
1891 | + boundsSize; | ||
1892 | + | ||
1893 | + padding = L.point(padding || [0, 0]); | ||
1894 | + | ||
1895 | + do { | ||
1896 | + zoom++; | ||
1897 | + boundsSize = this.project(se, zoom).subtract(this.project(nw, zoom)).add(padding); | ||
1898 | + zoomNotFound = !inside ? size.contains(boundsSize) : boundsSize.x < size.x || boundsSize.y < size.y; | ||
1899 | + | ||
1900 | + } while (zoomNotFound && zoom <= maxZoom); | ||
1901 | + | ||
1902 | + if (zoomNotFound && inside) { | ||
1903 | + return null; | ||
1904 | + } | ||
1905 | + | ||
1906 | + return inside ? zoom : zoom - 1; | ||
1907 | + }, | ||
1908 | + | ||
1909 | + getSize: function () { | ||
1910 | + if (!this._size || this._sizeChanged) { | ||
1911 | + this._size = new L.Point( | ||
1912 | + this._container.clientWidth, | ||
1913 | + this._container.clientHeight); | ||
1914 | + | ||
1915 | + this._sizeChanged = false; | ||
1916 | + } | ||
1917 | + return this._size.clone(); | ||
1918 | + }, | ||
1919 | + | ||
1920 | + getPixelBounds: function () { | ||
1921 | + var topLeftPoint = this._getTopLeftPoint(); | ||
1922 | + return new L.Bounds(topLeftPoint, topLeftPoint.add(this.getSize())); | ||
1923 | + }, | ||
1924 | + | ||
1925 | + getPixelOrigin: function () { | ||
1926 | + this._checkIfLoaded(); | ||
1927 | + return this._initialTopLeftPoint; | ||
1928 | + }, | ||
1929 | + | ||
1930 | + getPanes: function () { | ||
1931 | + return this._panes; | ||
1932 | + }, | ||
1933 | + | ||
1934 | + getContainer: function () { | ||
1935 | + return this._container; | ||
1936 | + }, | ||
1937 | + | ||
1938 | + | ||
1939 | + // TODO replace with universal implementation after refactoring projections | ||
1940 | + | ||
1941 | + getZoomScale: function (toZoom) { | ||
1942 | + var crs = this.options.crs; | ||
1943 | + return crs.scale(toZoom) / crs.scale(this._zoom); | ||
1944 | + }, | ||
1945 | + | ||
1946 | + getScaleZoom: function (scale) { | ||
1947 | + return this._zoom + (Math.log(scale) / Math.LN2); | ||
1948 | + }, | ||
1949 | + | ||
1950 | + | ||
1951 | + // conversion methods | ||
1952 | + | ||
1953 | + project: function (latlng, zoom) { // (LatLng[, Number]) -> Point | ||
1954 | + zoom = zoom === undefined ? this._zoom : zoom; | ||
1955 | + return this.options.crs.latLngToPoint(L.latLng(latlng), zoom); | ||
1956 | + }, | ||
1957 | + | ||
1958 | + unproject: function (point, zoom) { // (Point[, Number]) -> LatLng | ||
1959 | + zoom = zoom === undefined ? this._zoom : zoom; | ||
1960 | + return this.options.crs.pointToLatLng(L.point(point), zoom); | ||
1961 | + }, | ||
1962 | + | ||
1963 | + layerPointToLatLng: function (point) { // (Point) | ||
1964 | + var projectedPoint = L.point(point).add(this.getPixelOrigin()); | ||
1965 | + return this.unproject(projectedPoint); | ||
1966 | + }, | ||
1967 | + | ||
1968 | + latLngToLayerPoint: function (latlng) { // (LatLng) | ||
1969 | + var projectedPoint = this.project(L.latLng(latlng))._round(); | ||
1970 | + return projectedPoint._subtract(this.getPixelOrigin()); | ||
1971 | + }, | ||
1972 | + | ||
1973 | + containerPointToLayerPoint: function (point) { // (Point) | ||
1974 | + return L.point(point).subtract(this._getMapPanePos()); | ||
1975 | + }, | ||
1976 | + | ||
1977 | + layerPointToContainerPoint: function (point) { // (Point) | ||
1978 | + return L.point(point).add(this._getMapPanePos()); | ||
1979 | + }, | ||
1980 | + | ||
1981 | + containerPointToLatLng: function (point) { | ||
1982 | + var layerPoint = this.containerPointToLayerPoint(L.point(point)); | ||
1983 | + return this.layerPointToLatLng(layerPoint); | ||
1984 | + }, | ||
1985 | + | ||
1986 | + latLngToContainerPoint: function (latlng) { | ||
1987 | + return this.layerPointToContainerPoint(this.latLngToLayerPoint(L.latLng(latlng))); | ||
1988 | + }, | ||
1989 | + | ||
1990 | + mouseEventToContainerPoint: function (e) { // (MouseEvent) | ||
1991 | + return L.DomEvent.getMousePosition(e, this._container); | ||
1992 | + }, | ||
1993 | + | ||
1994 | + mouseEventToLayerPoint: function (e) { // (MouseEvent) | ||
1995 | + return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e)); | ||
1996 | + }, | ||
1997 | + | ||
1998 | + mouseEventToLatLng: function (e) { // (MouseEvent) | ||
1999 | + return this.layerPointToLatLng(this.mouseEventToLayerPoint(e)); | ||
2000 | + }, | ||
2001 | + | ||
2002 | + | ||
2003 | + // map initialization methods | ||
2004 | + | ||
2005 | + _initContainer: function (id) { | ||
2006 | + var container = this._container = L.DomUtil.get(id); | ||
2007 | + | ||
2008 | + if (!container) { | ||
2009 | + throw new Error('Map container not found.'); | ||
2010 | + } else if (container._leaflet) { | ||
2011 | + throw new Error('Map container is already initialized.'); | ||
2012 | + } | ||
2013 | + | ||
2014 | + container._leaflet = true; | ||
2015 | + }, | ||
2016 | + | ||
2017 | + _initLayout: function () { | ||
2018 | + var container = this._container; | ||
2019 | + | ||
2020 | + L.DomUtil.addClass(container, 'leaflet-container' + | ||
2021 | + (L.Browser.touch ? ' leaflet-touch' : '') + | ||
2022 | + (L.Browser.retina ? ' leaflet-retina' : '') + | ||
2023 | + (L.Browser.ielt9 ? ' leaflet-oldie' : '') + | ||
2024 | + (this.options.fadeAnimation ? ' leaflet-fade-anim' : '')); | ||
2025 | + | ||
2026 | + var position = L.DomUtil.getStyle(container, 'position'); | ||
2027 | + | ||
2028 | + if (position !== 'absolute' && position !== 'relative' && position !== 'fixed') { | ||
2029 | + container.style.position = 'relative'; | ||
2030 | + } | ||
2031 | + | ||
2032 | + this._initPanes(); | ||
2033 | + | ||
2034 | + if (this._initControlPos) { | ||
2035 | + this._initControlPos(); | ||
2036 | + } | ||
2037 | + }, | ||
2038 | + | ||
2039 | + _initPanes: function () { | ||
2040 | + var panes = this._panes = {}; | ||
2041 | + | ||
2042 | + this._mapPane = panes.mapPane = this._createPane('leaflet-map-pane', this._container); | ||
2043 | + | ||
2044 | + this._tilePane = panes.tilePane = this._createPane('leaflet-tile-pane', this._mapPane); | ||
2045 | + panes.objectsPane = this._createPane('leaflet-objects-pane', this._mapPane); | ||
2046 | + panes.shadowPane = this._createPane('leaflet-shadow-pane'); | ||
2047 | + panes.overlayPane = this._createPane('leaflet-overlay-pane'); | ||
2048 | + panes.markerPane = this._createPane('leaflet-marker-pane'); | ||
2049 | + panes.popupPane = this._createPane('leaflet-popup-pane'); | ||
2050 | + | ||
2051 | + var zoomHide = ' leaflet-zoom-hide'; | ||
2052 | + | ||
2053 | + if (!this.options.markerZoomAnimation) { | ||
2054 | + L.DomUtil.addClass(panes.markerPane, zoomHide); | ||
2055 | + L.DomUtil.addClass(panes.shadowPane, zoomHide); | ||
2056 | + L.DomUtil.addClass(panes.popupPane, zoomHide); | ||
2057 | + } | ||
2058 | + }, | ||
2059 | + | ||
2060 | + _createPane: function (className, container) { | ||
2061 | + return L.DomUtil.create('div', className, container || this._panes.objectsPane); | ||
2062 | + }, | ||
2063 | + | ||
2064 | + _clearPanes: function () { | ||
2065 | + this._container.removeChild(this._mapPane); | ||
2066 | + }, | ||
2067 | + | ||
2068 | + _addLayers: function (layers) { | ||
2069 | + layers = layers ? (L.Util.isArray(layers) ? layers : [layers]) : []; | ||
2070 | + | ||
2071 | + for (var i = 0, len = layers.length; i < len; i++) { | ||
2072 | + this.addLayer(layers[i]); | ||
2073 | + } | ||
2074 | + }, | ||
2075 | + | ||
2076 | + | ||
2077 | + // private methods that modify map state | ||
2078 | + | ||
2079 | + _resetView: function (center, zoom, preserveMapOffset, afterZoomAnim) { | ||
2080 | + | ||
2081 | + var zoomChanged = (this._zoom !== zoom); | ||
2082 | + | ||
2083 | + if (!afterZoomAnim) { | ||
2084 | + this.fire('movestart'); | ||
2085 | + | ||
2086 | + if (zoomChanged) { | ||
2087 | + this.fire('zoomstart'); | ||
2088 | + } | ||
2089 | + } | ||
2090 | + | ||
2091 | + this._zoom = zoom; | ||
2092 | + this._initialCenter = center; | ||
2093 | + | ||
2094 | + this._initialTopLeftPoint = this._getNewTopLeftPoint(center); | ||
2095 | + | ||
2096 | + if (!preserveMapOffset) { | ||
2097 | + L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0)); | ||
2098 | + } else { | ||
2099 | + this._initialTopLeftPoint._add(this._getMapPanePos()); | ||
2100 | + } | ||
2101 | + | ||
2102 | + this._tileLayersToLoad = this._tileLayersNum; | ||
2103 | + | ||
2104 | + var loading = !this._loaded; | ||
2105 | + this._loaded = true; | ||
2106 | + | ||
2107 | + this.fire('viewreset', {hard: !preserveMapOffset}); | ||
2108 | + | ||
2109 | + if (loading) { | ||
2110 | + this.fire('load'); | ||
2111 | + this.eachLayer(this._layerAdd, this); | ||
2112 | + } | ||
2113 | + | ||
2114 | + this.fire('move'); | ||
2115 | + | ||
2116 | + if (zoomChanged || afterZoomAnim) { | ||
2117 | + this.fire('zoomend'); | ||
2118 | + } | ||
2119 | + | ||
2120 | + this.fire('moveend', {hard: !preserveMapOffset}); | ||
2121 | + }, | ||
2122 | + | ||
2123 | + _rawPanBy: function (offset) { | ||
2124 | + L.DomUtil.setPosition(this._mapPane, this._getMapPanePos().subtract(offset)); | ||
2125 | + }, | ||
2126 | + | ||
2127 | + _getZoomSpan: function () { | ||
2128 | + return this.getMaxZoom() - this.getMinZoom(); | ||
2129 | + }, | ||
2130 | + | ||
2131 | + _updateZoomLevels: function () { | ||
2132 | + var i, | ||
2133 | + minZoom = Infinity, | ||
2134 | + maxZoom = -Infinity, | ||
2135 | + oldZoomSpan = this._getZoomSpan(); | ||
2136 | + | ||
2137 | + for (i in this._zoomBoundLayers) { | ||
2138 | + var layer = this._zoomBoundLayers[i]; | ||
2139 | + if (!isNaN(layer.options.minZoom)) { | ||
2140 | + minZoom = Math.min(minZoom, layer.options.minZoom); | ||
2141 | + } | ||
2142 | + if (!isNaN(layer.options.maxZoom)) { | ||
2143 | + maxZoom = Math.max(maxZoom, layer.options.maxZoom); | ||
2144 | + } | ||
2145 | + } | ||
2146 | + | ||
2147 | + if (i === undefined) { // we have no tilelayers | ||
2148 | + this._layersMaxZoom = this._layersMinZoom = undefined; | ||
2149 | + } else { | ||
2150 | + this._layersMaxZoom = maxZoom; | ||
2151 | + this._layersMinZoom = minZoom; | ||
2152 | + } | ||
2153 | + | ||
2154 | + if (oldZoomSpan !== this._getZoomSpan()) { | ||
2155 | + this.fire('zoomlevelschange'); | ||
2156 | + } | ||
2157 | + }, | ||
2158 | + | ||
2159 | + _panInsideMaxBounds: function () { | ||
2160 | + this.panInsideBounds(this.options.maxBounds); | ||
2161 | + }, | ||
2162 | + | ||
2163 | + _checkIfLoaded: function () { | ||
2164 | + if (!this._loaded) { | ||
2165 | + throw new Error('Set map center and zoom first.'); | ||
2166 | + } | ||
2167 | + }, | ||
2168 | + | ||
2169 | + // map events | ||
2170 | + | ||
2171 | + _initEvents: function (onOff) { | ||
2172 | + if (!L.DomEvent) { return; } | ||
2173 | + | ||
2174 | + onOff = onOff || 'on'; | ||
2175 | + | ||
2176 | + L.DomEvent[onOff](this._container, 'click', this._onMouseClick, this); | ||
2177 | + | ||
2178 | + var events = ['dblclick', 'mousedown', 'mouseup', 'mouseenter', | ||
2179 | + 'mouseleave', 'mousemove', 'contextmenu'], | ||
2180 | + i, len; | ||
2181 | + | ||
2182 | + for (i = 0, len = events.length; i < len; i++) { | ||
2183 | + L.DomEvent[onOff](this._container, events[i], this._fireMouseEvent, this); | ||
2184 | + } | ||
2185 | + | ||
2186 | + if (this.options.trackResize) { | ||
2187 | + L.DomEvent[onOff](window, 'resize', this._onResize, this); | ||
2188 | + } | ||
2189 | + }, | ||
2190 | + | ||
2191 | + _onResize: function () { | ||
2192 | + L.Util.cancelAnimFrame(this._resizeRequest); | ||
2193 | + this._resizeRequest = L.Util.requestAnimFrame( | ||
2194 | + function () { this.invalidateSize({debounceMoveend: true}); }, this, false, this._container); | ||
2195 | + }, | ||
2196 | + | ||
2197 | + _onMouseClick: function (e) { | ||
2198 | + if (!this._loaded || (!e._simulated && | ||
2199 | + ((this.dragging && this.dragging.moved()) || | ||
2200 | + (this.boxZoom && this.boxZoom.moved()))) || | ||
2201 | + L.DomEvent._skipped(e)) { return; } | ||
2202 | + | ||
2203 | + this.fire('preclick'); | ||
2204 | + this._fireMouseEvent(e); | ||
2205 | + }, | ||
2206 | + | ||
2207 | + _fireMouseEvent: function (e) { | ||
2208 | + if (!this._loaded || L.DomEvent._skipped(e)) { return; } | ||
2209 | + | ||
2210 | + var type = e.type; | ||
2211 | + | ||
2212 | + type = (type === 'mouseenter' ? 'mouseover' : (type === 'mouseleave' ? 'mouseout' : type)); | ||
2213 | + | ||
2214 | + if (!this.hasEventListeners(type)) { return; } | ||
2215 | + | ||
2216 | + if (type === 'contextmenu') { | ||
2217 | + L.DomEvent.preventDefault(e); | ||
2218 | + } | ||
2219 | + | ||
2220 | + var containerPoint = this.mouseEventToContainerPoint(e), | ||
2221 | + layerPoint = this.containerPointToLayerPoint(containerPoint), | ||
2222 | + latlng = this.layerPointToLatLng(layerPoint); | ||
2223 | + | ||
2224 | + this.fire(type, { | ||
2225 | + latlng: latlng, | ||
2226 | + layerPoint: layerPoint, | ||
2227 | + containerPoint: containerPoint, | ||
2228 | + originalEvent: e | ||
2229 | + }); | ||
2230 | + }, | ||
2231 | + | ||
2232 | + _onTileLayerLoad: function () { | ||
2233 | + this._tileLayersToLoad--; | ||
2234 | + if (this._tileLayersNum && !this._tileLayersToLoad) { | ||
2235 | + this.fire('tilelayersload'); | ||
2236 | + } | ||
2237 | + }, | ||
2238 | + | ||
2239 | + _clearHandlers: function () { | ||
2240 | + for (var i = 0, len = this._handlers.length; i < len; i++) { | ||
2241 | + this._handlers[i].disable(); | ||
2242 | + } | ||
2243 | + }, | ||
2244 | + | ||
2245 | + whenReady: function (callback, context) { | ||
2246 | + if (this._loaded) { | ||
2247 | + callback.call(context || this, this); | ||
2248 | + } else { | ||
2249 | + this.on('load', callback, context); | ||
2250 | + } | ||
2251 | + return this; | ||
2252 | + }, | ||
2253 | + | ||
2254 | + _layerAdd: function (layer) { | ||
2255 | + layer.onAdd(this); | ||
2256 | + this.fire('layeradd', {layer: layer}); | ||
2257 | + }, | ||
2258 | + | ||
2259 | + | ||
2260 | + // private methods for getting map state | ||
2261 | + | ||
2262 | + _getMapPanePos: function () { | ||
2263 | + return L.DomUtil.getPosition(this._mapPane); | ||
2264 | + }, | ||
2265 | + | ||
2266 | + _moved: function () { | ||
2267 | + var pos = this._getMapPanePos(); | ||
2268 | + return pos && !pos.equals([0, 0]); | ||
2269 | + }, | ||
2270 | + | ||
2271 | + _getTopLeftPoint: function () { | ||
2272 | + return this.getPixelOrigin().subtract(this._getMapPanePos()); | ||
2273 | + }, | ||
2274 | + | ||
2275 | + _getNewTopLeftPoint: function (center, zoom) { | ||
2276 | + var viewHalf = this.getSize()._divideBy(2); | ||
2277 | + // TODO round on display, not calculation to increase precision? | ||
2278 | + return this.project(center, zoom)._subtract(viewHalf)._round(); | ||
2279 | + }, | ||
2280 | + | ||
2281 | + _latLngToNewLayerPoint: function (latlng, newZoom, newCenter) { | ||
2282 | + var topLeft = this._getNewTopLeftPoint(newCenter, newZoom).add(this._getMapPanePos()); | ||
2283 | + return this.project(latlng, newZoom)._subtract(topLeft); | ||
2284 | + }, | ||
2285 | + | ||
2286 | + // layer point of the current center | ||
2287 | + _getCenterLayerPoint: function () { | ||
2288 | + return this.containerPointToLayerPoint(this.getSize()._divideBy(2)); | ||
2289 | + }, | ||
2290 | + | ||
2291 | + // offset of the specified place to the current center in pixels | ||
2292 | + _getCenterOffset: function (latlng) { | ||
2293 | + return this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint()); | ||
2294 | + }, | ||
2295 | + | ||
2296 | + // adjust center for view to get inside bounds | ||
2297 | + _limitCenter: function (center, zoom, bounds) { | ||
2298 | + | ||
2299 | + if (!bounds) { return center; } | ||
2300 | + | ||
2301 | + var centerPoint = this.project(center, zoom), | ||
2302 | + viewHalf = this.getSize().divideBy(2), | ||
2303 | + viewBounds = new L.Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)), | ||
2304 | + offset = this._getBoundsOffset(viewBounds, bounds, zoom); | ||
2305 | + | ||
2306 | + return this.unproject(centerPoint.add(offset), zoom); | ||
2307 | + }, | ||
2308 | + | ||
2309 | + // adjust offset for view to get inside bounds | ||
2310 | + _limitOffset: function (offset, bounds) { | ||
2311 | + if (!bounds) { return offset; } | ||
2312 | + | ||
2313 | + var viewBounds = this.getPixelBounds(), | ||
2314 | + newBounds = new L.Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset)); | ||
2315 | + | ||
2316 | + return offset.add(this._getBoundsOffset(newBounds, bounds)); | ||
2317 | + }, | ||
2318 | + | ||
2319 | + // returns offset needed for pxBounds to get inside maxBounds at a specified zoom | ||
2320 | + _getBoundsOffset: function (pxBounds, maxBounds, zoom) { | ||
2321 | + var nwOffset = this.project(maxBounds.getNorthWest(), zoom).subtract(pxBounds.min), | ||
2322 | + seOffset = this.project(maxBounds.getSouthEast(), zoom).subtract(pxBounds.max), | ||
2323 | + | ||
2324 | + dx = this._rebound(nwOffset.x, -seOffset.x), | ||
2325 | + dy = this._rebound(nwOffset.y, -seOffset.y); | ||
2326 | + | ||
2327 | + return new L.Point(dx, dy); | ||
2328 | + }, | ||
2329 | + | ||
2330 | + _rebound: function (left, right) { | ||
2331 | + return left + right > 0 ? | ||
2332 | + Math.round(left - right) / 2 : | ||
2333 | + Math.max(0, Math.ceil(left)) - Math.max(0, Math.floor(right)); | ||
2334 | + }, | ||
2335 | + | ||
2336 | + _limitZoom: function (zoom) { | ||
2337 | + var min = this.getMinZoom(), | ||
2338 | + max = this.getMaxZoom(); | ||
2339 | + | ||
2340 | + return Math.max(min, Math.min(max, zoom)); | ||
2341 | + } | ||
2342 | +}); | ||
2343 | + | ||
2344 | +L.map = function (id, options) { | ||
2345 | + return new L.Map(id, options); | ||
2346 | +}; | ||
2347 | + | ||
2348 | + | ||
2349 | +/* | ||
2350 | + * Mercator projection that takes into account that the Earth is not a perfect sphere. | ||
2351 | + * Less popular than spherical mercator; used by projections like EPSG:3395. | ||
2352 | + */ | ||
2353 | + | ||
2354 | +L.Projection.Mercator = { | ||
2355 | + MAX_LATITUDE: 85.0840591556, | ||
2356 | + | ||
2357 | + R_MINOR: 6356752.314245179, | ||
2358 | + R_MAJOR: 6378137, | ||
2359 | + | ||
2360 | + project: function (latlng) { // (LatLng) -> Point | ||
2361 | + var d = L.LatLng.DEG_TO_RAD, | ||
2362 | + max = this.MAX_LATITUDE, | ||
2363 | + lat = Math.max(Math.min(max, latlng.lat), -max), | ||
2364 | + r = this.R_MAJOR, | ||
2365 | + r2 = this.R_MINOR, | ||
2366 | + x = latlng.lng * d * r, | ||
2367 | + y = lat * d, | ||
2368 | + tmp = r2 / r, | ||
2369 | + eccent = Math.sqrt(1.0 - tmp * tmp), | ||
2370 | + con = eccent * Math.sin(y); | ||
2371 | + | ||
2372 | + con = Math.pow((1 - con) / (1 + con), eccent * 0.5); | ||
2373 | + | ||
2374 | + var ts = Math.tan(0.5 * ((Math.PI * 0.5) - y)) / con; | ||
2375 | + y = -r * Math.log(ts); | ||
2376 | + | ||
2377 | + return new L.Point(x, y); | ||
2378 | + }, | ||
2379 | + | ||
2380 | + unproject: function (point) { // (Point, Boolean) -> LatLng | ||
2381 | + var d = L.LatLng.RAD_TO_DEG, | ||
2382 | + r = this.R_MAJOR, | ||
2383 | + r2 = this.R_MINOR, | ||
2384 | + lng = point.x * d / r, | ||
2385 | + tmp = r2 / r, | ||
2386 | + eccent = Math.sqrt(1 - (tmp * tmp)), | ||
2387 | + ts = Math.exp(- point.y / r), | ||
2388 | + phi = (Math.PI / 2) - 2 * Math.atan(ts), | ||
2389 | + numIter = 15, | ||
2390 | + tol = 1e-7, | ||
2391 | + i = numIter, | ||
2392 | + dphi = 0.1, | ||
2393 | + con; | ||
2394 | + | ||
2395 | + while ((Math.abs(dphi) > tol) && (--i > 0)) { | ||
2396 | + con = eccent * Math.sin(phi); | ||
2397 | + dphi = (Math.PI / 2) - 2 * Math.atan(ts * | ||
2398 | + Math.pow((1.0 - con) / (1.0 + con), 0.5 * eccent)) - phi; | ||
2399 | + phi += dphi; | ||
2400 | + } | ||
2401 | + | ||
2402 | + return new L.LatLng(phi * d, lng); | ||
2403 | + } | ||
2404 | +}; | ||
2405 | + | ||
2406 | + | ||
2407 | + | ||
2408 | +L.CRS.EPSG3395 = L.extend({}, L.CRS, { | ||
2409 | + code: 'EPSG:3395', | ||
2410 | + | ||
2411 | + projection: L.Projection.Mercator, | ||
2412 | + | ||
2413 | + transformation: (function () { | ||
2414 | + var m = L.Projection.Mercator, | ||
2415 | + r = m.R_MAJOR, | ||
2416 | + scale = 0.5 / (Math.PI * r); | ||
2417 | + | ||
2418 | + return new L.Transformation(scale, 0.5, -scale, 0.5); | ||
2419 | + }()) | ||
2420 | +}); | ||
2421 | + | ||
2422 | + | ||
2423 | +/* | ||
2424 | + * L.TileLayer is used for standard xyz-numbered tile layers. | ||
2425 | + */ | ||
2426 | + | ||
2427 | +L.TileLayer = L.Class.extend({ | ||
2428 | + includes: L.Mixin.Events, | ||
2429 | + | ||
2430 | + options: { | ||
2431 | + minZoom: 0, | ||
2432 | + maxZoom: 18, | ||
2433 | + tileSize: 256, | ||
2434 | + subdomains: 'abc', | ||
2435 | + errorTileUrl: '', | ||
2436 | + attribution: '', | ||
2437 | + zoomOffset: 0, | ||
2438 | + opacity: 1, | ||
2439 | + /* | ||
2440 | + maxNativeZoom: null, | ||
2441 | + zIndex: null, | ||
2442 | + tms: false, | ||
2443 | + continuousWorld: false, | ||
2444 | + noWrap: false, | ||
2445 | + zoomReverse: false, | ||
2446 | + detectRetina: false, | ||
2447 | + reuseTiles: false, | ||
2448 | + bounds: false, | ||
2449 | + */ | ||
2450 | + unloadInvisibleTiles: L.Browser.mobile, | ||
2451 | + updateWhenIdle: L.Browser.mobile | ||
2452 | + }, | ||
2453 | + | ||
2454 | + initialize: function (url, options) { | ||
2455 | + options = L.setOptions(this, options); | ||
2456 | + | ||
2457 | + // detecting retina displays, adjusting tileSize and zoom levels | ||
2458 | + if (options.detectRetina && L.Browser.retina && options.maxZoom > 0) { | ||
2459 | + | ||
2460 | + options.tileSize = Math.floor(options.tileSize / 2); | ||
2461 | + options.zoomOffset++; | ||
2462 | + | ||
2463 | + if (options.minZoom > 0) { | ||
2464 | + options.minZoom--; | ||
2465 | + } | ||
2466 | + this.options.maxZoom--; | ||
2467 | + } | ||
2468 | + | ||
2469 | + if (options.bounds) { | ||
2470 | + options.bounds = L.latLngBounds(options.bounds); | ||
2471 | + } | ||
2472 | + | ||
2473 | + this._url = url; | ||
2474 | + | ||
2475 | + var subdomains = this.options.subdomains; | ||
2476 | + | ||
2477 | + if (typeof subdomains === 'string') { | ||
2478 | + this.options.subdomains = subdomains.split(''); | ||
2479 | + } | ||
2480 | + }, | ||
2481 | + | ||
2482 | + onAdd: function (map) { | ||
2483 | + this._map = map; | ||
2484 | + this._animated = map._zoomAnimated; | ||
2485 | + | ||
2486 | + // create a container div for tiles | ||
2487 | + this._initContainer(); | ||
2488 | + | ||
2489 | + // set up events | ||
2490 | + map.on({ | ||
2491 | + 'viewreset': this._reset, | ||
2492 | + 'moveend': this._update | ||
2493 | + }, this); | ||
2494 | + | ||
2495 | + if (this._animated) { | ||
2496 | + map.on({ | ||
2497 | + 'zoomanim': this._animateZoom, | ||
2498 | + 'zoomend': this._endZoomAnim | ||
2499 | + }, this); | ||
2500 | + } | ||
2501 | + | ||
2502 | + if (!this.options.updateWhenIdle) { | ||
2503 | + this._limitedUpdate = L.Util.limitExecByInterval(this._update, 150, this); | ||
2504 | + map.on('move', this._limitedUpdate, this); | ||
2505 | + } | ||
2506 | + | ||
2507 | + this._reset(); | ||
2508 | + this._update(); | ||
2509 | + }, | ||
2510 | + | ||
2511 | + addTo: function (map) { | ||
2512 | + map.addLayer(this); | ||
2513 | + return this; | ||
2514 | + }, | ||
2515 | + | ||
2516 | + onRemove: function (map) { | ||
2517 | + this._container.parentNode.removeChild(this._container); | ||
2518 | + | ||
2519 | + map.off({ | ||
2520 | + 'viewreset': this._reset, | ||
2521 | + 'moveend': this._update | ||
2522 | + }, this); | ||
2523 | + | ||
2524 | + if (this._animated) { | ||
2525 | + map.off({ | ||
2526 | + 'zoomanim': this._animateZoom, | ||
2527 | + 'zoomend': this._endZoomAnim | ||
2528 | + }, this); | ||
2529 | + } | ||
2530 | + | ||
2531 | + if (!this.options.updateWhenIdle) { | ||
2532 | + map.off('move', this._limitedUpdate, this); | ||
2533 | + } | ||
2534 | + | ||
2535 | + this._container = null; | ||
2536 | + this._map = null; | ||
2537 | + }, | ||
2538 | + | ||
2539 | + bringToFront: function () { | ||
2540 | + var pane = this._map._panes.tilePane; | ||
2541 | + | ||
2542 | + if (this._container) { | ||
2543 | + pane.appendChild(this._container); | ||
2544 | + this._setAutoZIndex(pane, Math.max); | ||
2545 | + } | ||
2546 | + | ||
2547 | + return this; | ||
2548 | + }, | ||
2549 | + | ||
2550 | + bringToBack: function () { | ||
2551 | + var pane = this._map._panes.tilePane; | ||
2552 | + | ||
2553 | + if (this._container) { | ||
2554 | + pane.insertBefore(this._container, pane.firstChild); | ||
2555 | + this._setAutoZIndex(pane, Math.min); | ||
2556 | + } | ||
2557 | + | ||
2558 | + return this; | ||
2559 | + }, | ||
2560 | + | ||
2561 | + getAttribution: function () { | ||
2562 | + return this.options.attribution; | ||
2563 | + }, | ||
2564 | + | ||
2565 | + getContainer: function () { | ||
2566 | + return this._container; | ||
2567 | + }, | ||
2568 | + | ||
2569 | + setOpacity: function (opacity) { | ||
2570 | + this.options.opacity = opacity; | ||
2571 | + | ||
2572 | + if (this._map) { | ||
2573 | + this._updateOpacity(); | ||
2574 | + } | ||
2575 | + | ||
2576 | + return this; | ||
2577 | + }, | ||
2578 | + | ||
2579 | + setZIndex: function (zIndex) { | ||
2580 | + this.options.zIndex = zIndex; | ||
2581 | + this._updateZIndex(); | ||
2582 | + | ||
2583 | + return this; | ||
2584 | + }, | ||
2585 | + | ||
2586 | + setUrl: function (url, noRedraw) { | ||
2587 | + this._url = url; | ||
2588 | + | ||
2589 | + if (!noRedraw) { | ||
2590 | + this.redraw(); | ||
2591 | + } | ||
2592 | + | ||
2593 | + return this; | ||
2594 | + }, | ||
2595 | + | ||
2596 | + redraw: function () { | ||
2597 | + if (this._map) { | ||
2598 | + this._reset({hard: true}); | ||
2599 | + this._update(); | ||
2600 | + } | ||
2601 | + return this; | ||
2602 | + }, | ||
2603 | + | ||
2604 | + _updateZIndex: function () { | ||
2605 | + if (this._container && this.options.zIndex !== undefined) { | ||
2606 | + this._container.style.zIndex = this.options.zIndex; | ||
2607 | + } | ||
2608 | + }, | ||
2609 | + | ||
2610 | + _setAutoZIndex: function (pane, compare) { | ||
2611 | + | ||
2612 | + var layers = pane.children, | ||
2613 | + edgeZIndex = -compare(Infinity, -Infinity), // -Infinity for max, Infinity for min | ||
2614 | + zIndex, i, len; | ||
2615 | + | ||
2616 | + for (i = 0, len = layers.length; i < len; i++) { | ||
2617 | + | ||
2618 | + if (layers[i] !== this._container) { | ||
2619 | + zIndex = parseInt(layers[i].style.zIndex, 10); | ||
2620 | + | ||
2621 | + if (!isNaN(zIndex)) { | ||
2622 | + edgeZIndex = compare(edgeZIndex, zIndex); | ||
2623 | + } | ||
2624 | + } | ||
2625 | + } | ||
2626 | + | ||
2627 | + this.options.zIndex = this._container.style.zIndex = | ||
2628 | + (isFinite(edgeZIndex) ? edgeZIndex : 0) + compare(1, -1); | ||
2629 | + }, | ||
2630 | + | ||
2631 | + _updateOpacity: function () { | ||
2632 | + var i, | ||
2633 | + tiles = this._tiles; | ||
2634 | + | ||
2635 | + if (L.Browser.ielt9) { | ||
2636 | + for (i in tiles) { | ||
2637 | + L.DomUtil.setOpacity(tiles[i], this.options.opacity); | ||
2638 | + } | ||
2639 | + } else { | ||
2640 | + L.DomUtil.setOpacity(this._container, this.options.opacity); | ||
2641 | + } | ||
2642 | + }, | ||
2643 | + | ||
2644 | + _initContainer: function () { | ||
2645 | + var tilePane = this._map._panes.tilePane; | ||
2646 | + | ||
2647 | + if (!this._container) { | ||
2648 | + this._container = L.DomUtil.create('div', 'leaflet-layer'); | ||
2649 | + | ||
2650 | + this._updateZIndex(); | ||
2651 | + | ||
2652 | + if (this._animated) { | ||
2653 | + var className = 'leaflet-tile-container'; | ||
2654 | + | ||
2655 | + this._bgBuffer = L.DomUtil.create('div', className, this._container); | ||
2656 | + this._tileContainer = L.DomUtil.create('div', className, this._container); | ||
2657 | + | ||
2658 | + } else { | ||
2659 | + this._tileContainer = this._container; | ||
2660 | + } | ||
2661 | + | ||
2662 | + tilePane.appendChild(this._container); | ||
2663 | + | ||
2664 | + if (this.options.opacity < 1) { | ||
2665 | + this._updateOpacity(); | ||
2666 | + } | ||
2667 | + } | ||
2668 | + }, | ||
2669 | + | ||
2670 | + _reset: function (e) { | ||
2671 | + for (var key in this._tiles) { | ||
2672 | + this.fire('tileunload', {tile: this._tiles[key]}); | ||
2673 | + } | ||
2674 | + | ||
2675 | + this._tiles = {}; | ||
2676 | + this._tilesToLoad = 0; | ||
2677 | + | ||
2678 | + if (this.options.reuseTiles) { | ||
2679 | + this._unusedTiles = []; | ||
2680 | + } | ||
2681 | + | ||
2682 | + this._tileContainer.innerHTML = ''; | ||
2683 | + | ||
2684 | + if (this._animated && e && e.hard) { | ||
2685 | + this._clearBgBuffer(); | ||
2686 | + } | ||
2687 | + | ||
2688 | + this._initContainer(); | ||
2689 | + }, | ||
2690 | + | ||
2691 | + _getTileSize: function () { | ||
2692 | + var map = this._map, | ||
2693 | + zoom = map.getZoom() + this.options.zoomOffset, | ||
2694 | + zoomN = this.options.maxNativeZoom, | ||
2695 | + tileSize = this.options.tileSize; | ||
2696 | + | ||
2697 | + if (zoomN && zoom > zoomN) { | ||
2698 | + tileSize = Math.round(map.getZoomScale(zoom) / map.getZoomScale(zoomN) * tileSize); | ||
2699 | + } | ||
2700 | + | ||
2701 | + return tileSize; | ||
2702 | + }, | ||
2703 | + | ||
2704 | + _update: function () { | ||
2705 | + | ||
2706 | + if (!this._map) { return; } | ||
2707 | + | ||
2708 | + var map = this._map, | ||
2709 | + bounds = map.getPixelBounds(), | ||
2710 | + zoom = map.getZoom(), | ||
2711 | + tileSize = this._getTileSize(); | ||
2712 | + | ||
2713 | + if (zoom > this.options.maxZoom || zoom < this.options.minZoom) { | ||
2714 | + return; | ||
2715 | + } | ||
2716 | + | ||
2717 | + var tileBounds = L.bounds( | ||
2718 | + bounds.min.divideBy(tileSize)._floor(), | ||
2719 | + bounds.max.divideBy(tileSize)._floor()); | ||
2720 | + | ||
2721 | + this._addTilesFromCenterOut(tileBounds); | ||
2722 | + | ||
2723 | + if (this.options.unloadInvisibleTiles || this.options.reuseTiles) { | ||
2724 | + this._removeOtherTiles(tileBounds); | ||
2725 | + } | ||
2726 | + }, | ||
2727 | + | ||
2728 | + _addTilesFromCenterOut: function (bounds) { | ||
2729 | + var queue = [], | ||
2730 | + center = bounds.getCenter(); | ||
2731 | + | ||
2732 | + var j, i, point; | ||
2733 | + | ||
2734 | + for (j = bounds.min.y; j <= bounds.max.y; j++) { | ||
2735 | + for (i = bounds.min.x; i <= bounds.max.x; i++) { | ||
2736 | + point = new L.Point(i, j); | ||
2737 | + | ||
2738 | + if (this._tileShouldBeLoaded(point)) { | ||
2739 | + queue.push(point); | ||
2740 | + } | ||
2741 | + } | ||
2742 | + } | ||
2743 | + | ||
2744 | + var tilesToLoad = queue.length; | ||
2745 | + | ||
2746 | + if (tilesToLoad === 0) { return; } | ||
2747 | + | ||
2748 | + // load tiles in order of their distance to center | ||
2749 | + queue.sort(function (a, b) { | ||
2750 | + return a.distanceTo(center) - b.distanceTo(center); | ||
2751 | + }); | ||
2752 | + | ||
2753 | + var fragment = document.createDocumentFragment(); | ||
2754 | + | ||
2755 | + // if its the first batch of tiles to load | ||
2756 | + if (!this._tilesToLoad) { | ||
2757 | + this.fire('loading'); | ||
2758 | + } | ||
2759 | + | ||
2760 | + this._tilesToLoad += tilesToLoad; | ||
2761 | + | ||
2762 | + for (i = 0; i < tilesToLoad; i++) { | ||
2763 | + this._addTile(queue[i], fragment); | ||
2764 | + } | ||
2765 | + | ||
2766 | + this._tileContainer.appendChild(fragment); | ||
2767 | + }, | ||
2768 | + | ||
2769 | + _tileShouldBeLoaded: function (tilePoint) { | ||
2770 | + if ((tilePoint.x + ':' + tilePoint.y) in this._tiles) { | ||
2771 | + return false; // already loaded | ||
2772 | + } | ||
2773 | + | ||
2774 | + var options = this.options; | ||
2775 | + | ||
2776 | + if (!options.continuousWorld) { | ||
2777 | + var limit = this._getWrapTileNum(); | ||
2778 | + | ||
2779 | + // don't load if exceeds world bounds | ||
2780 | + if ((options.noWrap && (tilePoint.x < 0 || tilePoint.x >= limit.x)) || | ||
2781 | + tilePoint.y < 0 || tilePoint.y >= limit.y) { return false; } | ||
2782 | + } | ||
2783 | + | ||
2784 | + if (options.bounds) { | ||
2785 | + var tileSize = options.tileSize, | ||
2786 | + nwPoint = tilePoint.multiplyBy(tileSize), | ||
2787 | + sePoint = nwPoint.add([tileSize, tileSize]), | ||
2788 | + nw = this._map.unproject(nwPoint), | ||
2789 | + se = this._map.unproject(sePoint); | ||
2790 | + | ||
2791 | + // TODO temporary hack, will be removed after refactoring projections | ||
2792 | + // https://github.com/Leaflet/Leaflet/issues/1618 | ||
2793 | + if (!options.continuousWorld && !options.noWrap) { | ||
2794 | + nw = nw.wrap(); | ||
2795 | + se = se.wrap(); | ||
2796 | + } | ||
2797 | + | ||
2798 | + if (!options.bounds.intersects([nw, se])) { return false; } | ||
2799 | + } | ||
2800 | + | ||
2801 | + return true; | ||
2802 | + }, | ||
2803 | + | ||
2804 | + _removeOtherTiles: function (bounds) { | ||
2805 | + var kArr, x, y, key; | ||
2806 | + | ||
2807 | + for (key in this._tiles) { | ||
2808 | + kArr = key.split(':'); | ||
2809 | + x = parseInt(kArr[0], 10); | ||
2810 | + y = parseInt(kArr[1], 10); | ||
2811 | + | ||
2812 | + // remove tile if it's out of bounds | ||
2813 | + if (x < bounds.min.x || x > bounds.max.x || y < bounds.min.y || y > bounds.max.y) { | ||
2814 | + this._removeTile(key); | ||
2815 | + } | ||
2816 | + } | ||
2817 | + }, | ||
2818 | + | ||
2819 | + _removeTile: function (key) { | ||
2820 | + var tile = this._tiles[key]; | ||
2821 | + | ||
2822 | + this.fire('tileunload', {tile: tile, url: tile.src}); | ||
2823 | + | ||
2824 | + if (this.options.reuseTiles) { | ||
2825 | + L.DomUtil.removeClass(tile, 'leaflet-tile-loaded'); | ||
2826 | + this._unusedTiles.push(tile); | ||
2827 | + | ||
2828 | + } else if (tile.parentNode === this._tileContainer) { | ||
2829 | + this._tileContainer.removeChild(tile); | ||
2830 | + } | ||
2831 | + | ||
2832 | + // for https://github.com/CloudMade/Leaflet/issues/137 | ||
2833 | + if (!L.Browser.android) { | ||
2834 | + tile.onload = null; | ||
2835 | + tile.src = L.Util.emptyImageUrl; | ||
2836 | + } | ||
2837 | + | ||
2838 | + delete this._tiles[key]; | ||
2839 | + }, | ||
2840 | + | ||
2841 | + _addTile: function (tilePoint, container) { | ||
2842 | + var tilePos = this._getTilePos(tilePoint); | ||
2843 | + | ||
2844 | + // get unused tile - or create a new tile | ||
2845 | + var tile = this._getTile(); | ||
2846 | + | ||
2847 | + /* | ||
2848 | + Chrome 20 layouts much faster with top/left (verify with timeline, frames) | ||
2849 | + Android 4 browser has display issues with top/left and requires transform instead | ||
2850 | + (other browsers don't currently care) - see debug/hacks/jitter.html for an example | ||
2851 | + */ | ||
2852 | + L.DomUtil.setPosition(tile, tilePos, L.Browser.chrome); | ||
2853 | + | ||
2854 | + this._tiles[tilePoint.x + ':' + tilePoint.y] = tile; | ||
2855 | + | ||
2856 | + this._loadTile(tile, tilePoint); | ||
2857 | + | ||
2858 | + if (tile.parentNode !== this._tileContainer) { | ||
2859 | + container.appendChild(tile); | ||
2860 | + } | ||
2861 | + }, | ||
2862 | + | ||
2863 | + _getZoomForUrl: function () { | ||
2864 | + | ||
2865 | + var options = this.options, | ||
2866 | + zoom = this._map.getZoom(); | ||
2867 | + | ||
2868 | + if (options.zoomReverse) { | ||
2869 | + zoom = options.maxZoom - zoom; | ||
2870 | + } | ||
2871 | + | ||
2872 | + zoom += options.zoomOffset; | ||
2873 | + | ||
2874 | + return options.maxNativeZoom ? Math.min(zoom, options.maxNativeZoom) : zoom; | ||
2875 | + }, | ||
2876 | + | ||
2877 | + _getTilePos: function (tilePoint) { | ||
2878 | + var origin = this._map.getPixelOrigin(), | ||
2879 | + tileSize = this._getTileSize(); | ||
2880 | + | ||
2881 | + return tilePoint.multiplyBy(tileSize).subtract(origin); | ||
2882 | + }, | ||
2883 | + | ||
2884 | + // image-specific code (override to implement e.g. Canvas or SVG tile layer) | ||
2885 | + | ||
2886 | + getTileUrl: function (tilePoint) { | ||
2887 | + return L.Util.template(this._url, L.extend({ | ||
2888 | + s: this._getSubdomain(tilePoint), | ||
2889 | + z: tilePoint.z, | ||
2890 | + x: tilePoint.x, | ||
2891 | + y: tilePoint.y | ||
2892 | + }, this.options)); | ||
2893 | + }, | ||
2894 | + | ||
2895 | + _getWrapTileNum: function () { | ||
2896 | + var crs = this._map.options.crs, | ||
2897 | + size = crs.getSize(this._map.getZoom()); | ||
2898 | + return size.divideBy(this._getTileSize())._floor(); | ||
2899 | + }, | ||
2900 | + | ||
2901 | + _adjustTilePoint: function (tilePoint) { | ||
2902 | + | ||
2903 | + var limit = this._getWrapTileNum(); | ||
2904 | + | ||
2905 | + // wrap tile coordinates | ||
2906 | + if (!this.options.continuousWorld && !this.options.noWrap) { | ||
2907 | + tilePoint.x = ((tilePoint.x % limit.x) + limit.x) % limit.x; | ||
2908 | + } | ||
2909 | + | ||
2910 | + if (this.options.tms) { | ||
2911 | + tilePoint.y = limit.y - tilePoint.y - 1; | ||
2912 | + } | ||
2913 | + | ||
2914 | + tilePoint.z = this._getZoomForUrl(); | ||
2915 | + }, | ||
2916 | + | ||
2917 | + _getSubdomain: function (tilePoint) { | ||
2918 | + var index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length; | ||
2919 | + return this.options.subdomains[index]; | ||
2920 | + }, | ||
2921 | + | ||
2922 | + _getTile: function () { | ||
2923 | + if (this.options.reuseTiles && this._unusedTiles.length > 0) { | ||
2924 | + var tile = this._unusedTiles.pop(); | ||
2925 | + this._resetTile(tile); | ||
2926 | + return tile; | ||
2927 | + } | ||
2928 | + return this._createTile(); | ||
2929 | + }, | ||
2930 | + | ||
2931 | + // Override if data stored on a tile needs to be cleaned up before reuse | ||
2932 | + _resetTile: function (/*tile*/) {}, | ||
2933 | + | ||
2934 | + _createTile: function () { | ||
2935 | + var tile = L.DomUtil.create('img', 'leaflet-tile'); | ||
2936 | + tile.style.width = tile.style.height = this._getTileSize() + 'px'; | ||
2937 | + tile.galleryimg = 'no'; | ||
2938 | + | ||
2939 | + tile.onselectstart = tile.onmousemove = L.Util.falseFn; | ||
2940 | + | ||
2941 | + if (L.Browser.ielt9 && this.options.opacity !== undefined) { | ||
2942 | + L.DomUtil.setOpacity(tile, this.options.opacity); | ||
2943 | + } | ||
2944 | + // without this hack, tiles disappear after zoom on Chrome for Android | ||
2945 | + // https://github.com/Leaflet/Leaflet/issues/2078 | ||
2946 | + if (L.Browser.mobileWebkit3d) { | ||
2947 | + tile.style.WebkitBackfaceVisibility = 'hidden'; | ||
2948 | + } | ||
2949 | + return tile; | ||
2950 | + }, | ||
2951 | + | ||
2952 | + _loadTile: function (tile, tilePoint) { | ||
2953 | + tile._layer = this; | ||
2954 | + tile.onload = this._tileOnLoad; | ||
2955 | + tile.onerror = this._tileOnError; | ||
2956 | + | ||
2957 | + this._adjustTilePoint(tilePoint); | ||
2958 | + tile.src = this.getTileUrl(tilePoint); | ||
2959 | + | ||
2960 | + this.fire('tileloadstart', { | ||
2961 | + tile: tile, | ||
2962 | + url: tile.src | ||
2963 | + }); | ||
2964 | + }, | ||
2965 | + | ||
2966 | + _tileLoaded: function () { | ||
2967 | + this._tilesToLoad--; | ||
2968 | + | ||
2969 | + if (this._animated) { | ||
2970 | + L.DomUtil.addClass(this._tileContainer, 'leaflet-zoom-animated'); | ||
2971 | + } | ||
2972 | + | ||
2973 | + if (!this._tilesToLoad) { | ||
2974 | + this.fire('load'); | ||
2975 | + | ||
2976 | + if (this._animated) { | ||
2977 | + // clear scaled tiles after all new tiles are loaded (for performance) | ||
2978 | + clearTimeout(this._clearBgBufferTimer); | ||
2979 | + this._clearBgBufferTimer = setTimeout(L.bind(this._clearBgBuffer, this), 500); | ||
2980 | + } | ||
2981 | + } | ||
2982 | + }, | ||
2983 | + | ||
2984 | + _tileOnLoad: function () { | ||
2985 | + var layer = this._layer; | ||
2986 | + | ||
2987 | + //Only if we are loading an actual image | ||
2988 | + if (this.src !== L.Util.emptyImageUrl) { | ||
2989 | + L.DomUtil.addClass(this, 'leaflet-tile-loaded'); | ||
2990 | + | ||
2991 | + layer.fire('tileload', { | ||
2992 | + tile: this, | ||
2993 | + url: this.src | ||
2994 | + }); | ||
2995 | + } | ||
2996 | + | ||
2997 | + layer._tileLoaded(); | ||
2998 | + }, | ||
2999 | + | ||
3000 | + _tileOnError: function () { | ||
3001 | + var layer = this._layer; | ||
3002 | + | ||
3003 | + layer.fire('tileerror', { | ||
3004 | + tile: this, | ||
3005 | + url: this.src | ||
3006 | + }); | ||
3007 | + | ||
3008 | + var newUrl = layer.options.errorTileUrl; | ||
3009 | + if (newUrl) { | ||
3010 | + this.src = newUrl; | ||
3011 | + } | ||
3012 | + | ||
3013 | + layer._tileLoaded(); | ||
3014 | + } | ||
3015 | +}); | ||
3016 | + | ||
3017 | +L.tileLayer = function (url, options) { | ||
3018 | + return new L.TileLayer(url, options); | ||
3019 | +}; | ||
3020 | + | ||
3021 | + | ||
3022 | +/* | ||
3023 | + * L.TileLayer.WMS is used for putting WMS tile layers on the map. | ||
3024 | + */ | ||
3025 | + | ||
3026 | +L.TileLayer.WMS = L.TileLayer.extend({ | ||
3027 | + | ||
3028 | + defaultWmsParams: { | ||
3029 | + service: 'WMS', | ||
3030 | + request: 'GetMap', | ||
3031 | + version: '1.1.1', | ||
3032 | + layers: '', | ||
3033 | + styles: '', | ||
3034 | + format: 'image/jpeg', | ||
3035 | + transparent: false | ||
3036 | + }, | ||
3037 | + | ||
3038 | + initialize: function (url, options) { // (String, Object) | ||
3039 | + | ||
3040 | + this._url = url; | ||
3041 | + | ||
3042 | + var wmsParams = L.extend({}, this.defaultWmsParams), | ||
3043 | + tileSize = options.tileSize || this.options.tileSize; | ||
3044 | + | ||
3045 | + if (options.detectRetina && L.Browser.retina) { | ||
3046 | + wmsParams.width = wmsParams.height = tileSize * 2; | ||
3047 | + } else { | ||
3048 | + wmsParams.width = wmsParams.height = tileSize; | ||
3049 | + } | ||
3050 | + | ||
3051 | + for (var i in options) { | ||
3052 | + // all keys that are not TileLayer options go to WMS params | ||
3053 | + if (!this.options.hasOwnProperty(i) && i !== 'crs') { | ||
3054 | + wmsParams[i] = options[i]; | ||
3055 | + } | ||
3056 | + } | ||
3057 | + | ||
3058 | + this.wmsParams = wmsParams; | ||
3059 | + | ||
3060 | + L.setOptions(this, options); | ||
3061 | + }, | ||
3062 | + | ||
3063 | + onAdd: function (map) { | ||
3064 | + | ||
3065 | + this._crs = this.options.crs || map.options.crs; | ||
3066 | + | ||
3067 | + this._wmsVersion = parseFloat(this.wmsParams.version); | ||
3068 | + | ||
3069 | + var projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs'; | ||
3070 | + this.wmsParams[projectionKey] = this._crs.code; | ||
3071 | + | ||
3072 | + L.TileLayer.prototype.onAdd.call(this, map); | ||
3073 | + }, | ||
3074 | + | ||
3075 | + getTileUrl: function (tilePoint) { // (Point, Number) -> String | ||
3076 | + | ||
3077 | + var map = this._map, | ||
3078 | + tileSize = this.options.tileSize, | ||
3079 | + | ||
3080 | + nwPoint = tilePoint.multiplyBy(tileSize), | ||
3081 | + sePoint = nwPoint.add([tileSize, tileSize]), | ||
3082 | + | ||
3083 | + nw = this._crs.project(map.unproject(nwPoint, tilePoint.z)), | ||
3084 | + se = this._crs.project(map.unproject(sePoint, tilePoint.z)), | ||
3085 | + bbox = this._wmsVersion >= 1.3 && this._crs === L.CRS.EPSG4326 ? | ||
3086 | + [se.y, nw.x, nw.y, se.x].join(',') : | ||
3087 | + [nw.x, se.y, se.x, nw.y].join(','), | ||
3088 | + | ||
3089 | + url = L.Util.template(this._url, {s: this._getSubdomain(tilePoint)}); | ||
3090 | + | ||
3091 | + return url + L.Util.getParamString(this.wmsParams, url, true) + '&BBOX=' + bbox; | ||
3092 | + }, | ||
3093 | + | ||
3094 | + setParams: function (params, noRedraw) { | ||
3095 | + | ||
3096 | + L.extend(this.wmsParams, params); | ||
3097 | + | ||
3098 | + if (!noRedraw) { | ||
3099 | + this.redraw(); | ||
3100 | + } | ||
3101 | + | ||
3102 | + return this; | ||
3103 | + } | ||
3104 | +}); | ||
3105 | + | ||
3106 | +L.tileLayer.wms = function (url, options) { | ||
3107 | + return new L.TileLayer.WMS(url, options); | ||
3108 | +}; | ||
3109 | + | ||
3110 | + | ||
3111 | +/* | ||
3112 | + * L.TileLayer.Canvas is a class that you can use as a base for creating | ||
3113 | + * dynamically drawn Canvas-based tile layers. | ||
3114 | + */ | ||
3115 | + | ||
3116 | +L.TileLayer.Canvas = L.TileLayer.extend({ | ||
3117 | + options: { | ||
3118 | + async: false | ||
3119 | + }, | ||
3120 | + | ||
3121 | + initialize: function (options) { | ||
3122 | + L.setOptions(this, options); | ||
3123 | + }, | ||
3124 | + | ||
3125 | + redraw: function () { | ||
3126 | + if (this._map) { | ||
3127 | + this._reset({hard: true}); | ||
3128 | + this._update(); | ||
3129 | + } | ||
3130 | + | ||
3131 | + for (var i in this._tiles) { | ||
3132 | + this._redrawTile(this._tiles[i]); | ||
3133 | + } | ||
3134 | + return this; | ||
3135 | + }, | ||
3136 | + | ||
3137 | + _redrawTile: function (tile) { | ||
3138 | + this.drawTile(tile, tile._tilePoint, this._map._zoom); | ||
3139 | + }, | ||
3140 | + | ||
3141 | + _createTile: function () { | ||
3142 | + var tile = L.DomUtil.create('canvas', 'leaflet-tile'); | ||
3143 | + tile.width = tile.height = this.options.tileSize; | ||
3144 | + tile.onselectstart = tile.onmousemove = L.Util.falseFn; | ||
3145 | + return tile; | ||
3146 | + }, | ||
3147 | + | ||
3148 | + _loadTile: function (tile, tilePoint) { | ||
3149 | + tile._layer = this; | ||
3150 | + tile._tilePoint = tilePoint; | ||
3151 | + | ||
3152 | + this._redrawTile(tile); | ||
3153 | + | ||
3154 | + if (!this.options.async) { | ||
3155 | + this.tileDrawn(tile); | ||
3156 | + } | ||
3157 | + }, | ||
3158 | + | ||
3159 | + drawTile: function (/*tile, tilePoint*/) { | ||
3160 | + // override with rendering code | ||
3161 | + }, | ||
3162 | + | ||
3163 | + tileDrawn: function (tile) { | ||
3164 | + this._tileOnLoad.call(tile); | ||
3165 | + } | ||
3166 | +}); | ||
3167 | + | ||
3168 | + | ||
3169 | +L.tileLayer.canvas = function (options) { | ||
3170 | + return new L.TileLayer.Canvas(options); | ||
3171 | +}; | ||
3172 | + | ||
3173 | + | ||
3174 | +/* | ||
3175 | + * L.ImageOverlay is used to overlay images over the map (to specific geographical bounds). | ||
3176 | + */ | ||
3177 | + | ||
3178 | +L.ImageOverlay = L.Class.extend({ | ||
3179 | + includes: L.Mixin.Events, | ||
3180 | + | ||
3181 | + options: { | ||
3182 | + opacity: 1 | ||
3183 | + }, | ||
3184 | + | ||
3185 | + initialize: function (url, bounds, options) { // (String, LatLngBounds, Object) | ||
3186 | + this._url = url; | ||
3187 | + this._bounds = L.latLngBounds(bounds); | ||
3188 | + | ||
3189 | + L.setOptions(this, options); | ||
3190 | + }, | ||
3191 | + | ||
3192 | + onAdd: function (map) { | ||
3193 | + this._map = map; | ||
3194 | + | ||
3195 | + if (!this._image) { | ||
3196 | + this._initImage(); | ||
3197 | + } | ||
3198 | + | ||
3199 | + map._panes.overlayPane.appendChild(this._image); | ||
3200 | + | ||
3201 | + map.on('viewreset', this._reset, this); | ||
3202 | + | ||
3203 | + if (map.options.zoomAnimation && L.Browser.any3d) { | ||
3204 | + map.on('zoomanim', this._animateZoom, this); | ||
3205 | + } | ||
3206 | + | ||
3207 | + this._reset(); | ||
3208 | + }, | ||
3209 | + | ||
3210 | + onRemove: function (map) { | ||
3211 | + map.getPanes().overlayPane.removeChild(this._image); | ||
3212 | + | ||
3213 | + map.off('viewreset', this._reset, this); | ||
3214 | + | ||
3215 | + if (map.options.zoomAnimation) { | ||
3216 | + map.off('zoomanim', this._animateZoom, this); | ||
3217 | + } | ||
3218 | + }, | ||
3219 | + | ||
3220 | + addTo: function (map) { | ||
3221 | + map.addLayer(this); | ||
3222 | + return this; | ||
3223 | + }, | ||
3224 | + | ||
3225 | + setOpacity: function (opacity) { | ||
3226 | + this.options.opacity = opacity; | ||
3227 | + this._updateOpacity(); | ||
3228 | + return this; | ||
3229 | + }, | ||
3230 | + | ||
3231 | + // TODO remove bringToFront/bringToBack duplication from TileLayer/Path | ||
3232 | + bringToFront: function () { | ||
3233 | + if (this._image) { | ||
3234 | + this._map._panes.overlayPane.appendChild(this._image); | ||
3235 | + } | ||
3236 | + return this; | ||
3237 | + }, | ||
3238 | + | ||
3239 | + bringToBack: function () { | ||
3240 | + var pane = this._map._panes.overlayPane; | ||
3241 | + if (this._image) { | ||
3242 | + pane.insertBefore(this._image, pane.firstChild); | ||
3243 | + } | ||
3244 | + return this; | ||
3245 | + }, | ||
3246 | + | ||
3247 | + setUrl: function (url) { | ||
3248 | + this._url = url; | ||
3249 | + this._image.src = this._url; | ||
3250 | + }, | ||
3251 | + | ||
3252 | + getAttribution: function () { | ||
3253 | + return this.options.attribution; | ||
3254 | + }, | ||
3255 | + | ||
3256 | + _initImage: function () { | ||
3257 | + this._image = L.DomUtil.create('img', 'leaflet-image-layer'); | ||
3258 | + | ||
3259 | + if (this._map.options.zoomAnimation && L.Browser.any3d) { | ||
3260 | + L.DomUtil.addClass(this._image, 'leaflet-zoom-animated'); | ||
3261 | + } else { | ||
3262 | + L.DomUtil.addClass(this._image, 'leaflet-zoom-hide'); | ||
3263 | + } | ||
3264 | + | ||
3265 | + this._updateOpacity(); | ||
3266 | + | ||
3267 | + //TODO createImage util method to remove duplication | ||
3268 | + L.extend(this._image, { | ||
3269 | + galleryimg: 'no', | ||
3270 | + onselectstart: L.Util.falseFn, | ||
3271 | + onmousemove: L.Util.falseFn, | ||
3272 | + onload: L.bind(this._onImageLoad, this), | ||
3273 | + src: this._url | ||
3274 | + }); | ||
3275 | + }, | ||
3276 | + | ||
3277 | + _animateZoom: function (e) { | ||
3278 | + var map = this._map, | ||
3279 | + image = this._image, | ||
3280 | + scale = map.getZoomScale(e.zoom), | ||
3281 | + nw = this._bounds.getNorthWest(), | ||
3282 | + se = this._bounds.getSouthEast(), | ||
3283 | + | ||
3284 | + topLeft = map._latLngToNewLayerPoint(nw, e.zoom, e.center), | ||
3285 | + size = map._latLngToNewLayerPoint(se, e.zoom, e.center)._subtract(topLeft), | ||
3286 | + origin = topLeft._add(size._multiplyBy((1 / 2) * (1 - 1 / scale))); | ||
3287 | + | ||
3288 | + image.style[L.DomUtil.TRANSFORM] = | ||
3289 | + L.DomUtil.getTranslateString(origin) + ' scale(' + scale + ') '; | ||
3290 | + }, | ||
3291 | + | ||
3292 | + _reset: function () { | ||
3293 | + var image = this._image, | ||
3294 | + topLeft = this._map.latLngToLayerPoint(this._bounds.getNorthWest()), | ||
3295 | + size = this._map.latLngToLayerPoint(this._bounds.getSouthEast())._subtract(topLeft); | ||
3296 | + | ||
3297 | + L.DomUtil.setPosition(image, topLeft); | ||
3298 | + | ||
3299 | + image.style.width = size.x + 'px'; | ||
3300 | + image.style.height = size.y + 'px'; | ||
3301 | + }, | ||
3302 | + | ||
3303 | + _onImageLoad: function () { | ||
3304 | + this.fire('load'); | ||
3305 | + }, | ||
3306 | + | ||
3307 | + _updateOpacity: function () { | ||
3308 | + L.DomUtil.setOpacity(this._image, this.options.opacity); | ||
3309 | + } | ||
3310 | +}); | ||
3311 | + | ||
3312 | +L.imageOverlay = function (url, bounds, options) { | ||
3313 | + return new L.ImageOverlay(url, bounds, options); | ||
3314 | +}; | ||
3315 | + | ||
3316 | + | ||
3317 | +/* | ||
3318 | + * L.Icon is an image-based icon class that you can use with L.Marker for custom markers. | ||
3319 | + */ | ||
3320 | + | ||
3321 | +L.Icon = L.Class.extend({ | ||
3322 | + options: { | ||
3323 | + /* | ||
3324 | + iconUrl: (String) (required) | ||
3325 | + iconRetinaUrl: (String) (optional, used for retina devices if detected) | ||
3326 | + iconSize: (Point) (can be set through CSS) | ||
3327 | + iconAnchor: (Point) (centered by default, can be set in CSS with negative margins) | ||
3328 | + popupAnchor: (Point) (if not specified, popup opens in the anchor point) | ||
3329 | + shadowUrl: (String) (no shadow by default) | ||
3330 | + shadowRetinaUrl: (String) (optional, used for retina devices if detected) | ||
3331 | + shadowSize: (Point) | ||
3332 | + shadowAnchor: (Point) | ||
3333 | + */ | ||
3334 | + className: '' | ||
3335 | + }, | ||
3336 | + | ||
3337 | + initialize: function (options) { | ||
3338 | + L.setOptions(this, options); | ||
3339 | + }, | ||
3340 | + | ||
3341 | + createIcon: function (oldIcon) { | ||
3342 | + return this._createIcon('icon', oldIcon); | ||
3343 | + }, | ||
3344 | + | ||
3345 | + createShadow: function (oldIcon) { | ||
3346 | + return this._createIcon('shadow', oldIcon); | ||
3347 | + }, | ||
3348 | + | ||
3349 | + _createIcon: function (name, oldIcon) { | ||
3350 | + var src = this._getIconUrl(name); | ||
3351 | + | ||
3352 | + if (!src) { | ||
3353 | + if (name === 'icon') { | ||
3354 | + throw new Error('iconUrl not set in Icon options (see the docs).'); | ||
3355 | + } | ||
3356 | + return null; | ||
3357 | + } | ||
3358 | + | ||
3359 | + var img; | ||
3360 | + if (!oldIcon || oldIcon.tagName !== 'IMG') { | ||
3361 | + img = this._createImg(src); | ||
3362 | + } else { | ||
3363 | + img = this._createImg(src, oldIcon); | ||
3364 | + } | ||
3365 | + this._setIconStyles(img, name); | ||
3366 | + | ||
3367 | + return img; | ||
3368 | + }, | ||
3369 | + | ||
3370 | + _setIconStyles: function (img, name) { | ||
3371 | + var options = this.options, | ||
3372 | + size = L.point(options[name + 'Size']), | ||
3373 | + anchor; | ||
3374 | + | ||
3375 | + if (name === 'shadow') { | ||
3376 | + anchor = L.point(options.shadowAnchor || options.iconAnchor); | ||
3377 | + } else { | ||
3378 | + anchor = L.point(options.iconAnchor); | ||
3379 | + } | ||
3380 | + | ||
3381 | + if (!anchor && size) { | ||
3382 | + anchor = size.divideBy(2, true); | ||
3383 | + } | ||
3384 | + | ||
3385 | + img.className = 'leaflet-marker-' + name + ' ' + options.className; | ||
3386 | + | ||
3387 | + if (anchor) { | ||
3388 | + img.style.marginLeft = (-anchor.x) + 'px'; | ||
3389 | + img.style.marginTop = (-anchor.y) + 'px'; | ||
3390 | + } | ||
3391 | + | ||
3392 | + if (size) { | ||
3393 | + img.style.width = size.x + 'px'; | ||
3394 | + img.style.height = size.y + 'px'; | ||
3395 | + } | ||
3396 | + }, | ||
3397 | + | ||
3398 | + _createImg: function (src, el) { | ||
3399 | + el = el || document.createElement('img'); | ||
3400 | + el.src = src; | ||
3401 | + return el; | ||
3402 | + }, | ||
3403 | + | ||
3404 | + _getIconUrl: function (name) { | ||
3405 | + if (L.Browser.retina && this.options[name + 'RetinaUrl']) { | ||
3406 | + return this.options[name + 'RetinaUrl']; | ||
3407 | + } | ||
3408 | + return this.options[name + 'Url']; | ||
3409 | + } | ||
3410 | +}); | ||
3411 | + | ||
3412 | +L.icon = function (options) { | ||
3413 | + return new L.Icon(options); | ||
3414 | +}; | ||
3415 | + | ||
3416 | + | ||
3417 | +/* | ||
3418 | + * L.Icon.Default is the blue marker icon used by default in Leaflet. | ||
3419 | + */ | ||
3420 | + | ||
3421 | +L.Icon.Default = L.Icon.extend({ | ||
3422 | + | ||
3423 | + options: { | ||
3424 | + iconSize: [25, 41], | ||
3425 | + iconAnchor: [12, 41], | ||
3426 | + popupAnchor: [1, -34], | ||
3427 | + | ||
3428 | + shadowSize: [41, 41] | ||
3429 | + }, | ||
3430 | + | ||
3431 | + _getIconUrl: function (name) { | ||
3432 | + var key = name + 'Url'; | ||
3433 | + | ||
3434 | + if (this.options[key]) { | ||
3435 | + return this.options[key]; | ||
3436 | + } | ||
3437 | + | ||
3438 | + if (L.Browser.retina && name === 'icon') { | ||
3439 | + name += '-2x'; | ||
3440 | + } | ||
3441 | + | ||
3442 | + var path = L.Icon.Default.imagePath; | ||
3443 | + | ||
3444 | + if (!path) { | ||
3445 | + throw new Error('Couldn\'t autodetect L.Icon.Default.imagePath, set it manually.'); | ||
3446 | + } | ||
3447 | + | ||
3448 | + return path + '/marker-' + name + '.png'; | ||
3449 | + } | ||
3450 | +}); | ||
3451 | + | ||
3452 | +L.Icon.Default.imagePath = (function () { | ||
3453 | + var scripts = document.getElementsByTagName('script'), | ||
3454 | + leafletRe = /[\/^]leaflet[\-\._]?([\w\-\._]*)\.js\??/; | ||
3455 | + | ||
3456 | + var i, len, src, matches, path; | ||
3457 | + | ||
3458 | + for (i = 0, len = scripts.length; i < len; i++) { | ||
3459 | + src = scripts[i].src; | ||
3460 | + matches = src.match(leafletRe); | ||
3461 | + | ||
3462 | + if (matches) { | ||
3463 | + path = src.split(leafletRe)[0]; | ||
3464 | + return (path ? path + '/' : '') + 'images'; | ||
3465 | + } | ||
3466 | + } | ||
3467 | +}()); | ||
3468 | + | ||
3469 | + | ||
3470 | +/* | ||
3471 | + * L.Marker is used to display clickable/draggable icons on the map. | ||
3472 | + */ | ||
3473 | + | ||
3474 | +L.Marker = L.Class.extend({ | ||
3475 | + | ||
3476 | + includes: L.Mixin.Events, | ||
3477 | + | ||
3478 | + options: { | ||
3479 | + icon: new L.Icon.Default(), | ||
3480 | + title: '', | ||
3481 | + alt: '', | ||
3482 | + clickable: true, | ||
3483 | + draggable: false, | ||
3484 | + keyboard: true, | ||
3485 | + zIndexOffset: 0, | ||
3486 | + opacity: 1, | ||
3487 | + riseOnHover: false, | ||
3488 | + riseOffset: 250 | ||
3489 | + }, | ||
3490 | + | ||
3491 | + initialize: function (latlng, options) { | ||
3492 | + L.setOptions(this, options); | ||
3493 | + this._latlng = L.latLng(latlng); | ||
3494 | + }, | ||
3495 | + | ||
3496 | + onAdd: function (map) { | ||
3497 | + this._map = map; | ||
3498 | + | ||
3499 | + map.on('viewreset', this.update, this); | ||
3500 | + | ||
3501 | + this._initIcon(); | ||
3502 | + this.update(); | ||
3503 | + this.fire('add'); | ||
3504 | + | ||
3505 | + if (map.options.zoomAnimation && map.options.markerZoomAnimation) { | ||
3506 | + map.on('zoomanim', this._animateZoom, this); | ||
3507 | + } | ||
3508 | + }, | ||
3509 | + | ||
3510 | + addTo: function (map) { | ||
3511 | + map.addLayer(this); | ||
3512 | + return this; | ||
3513 | + }, | ||
3514 | + | ||
3515 | + onRemove: function (map) { | ||
3516 | + if (this.dragging) { | ||
3517 | + this.dragging.disable(); | ||
3518 | + } | ||
3519 | + | ||
3520 | + this._removeIcon(); | ||
3521 | + this._removeShadow(); | ||
3522 | + | ||
3523 | + this.fire('remove'); | ||
3524 | + | ||
3525 | + map.off({ | ||
3526 | + 'viewreset': this.update, | ||
3527 | + 'zoomanim': this._animateZoom | ||
3528 | + }, this); | ||
3529 | + | ||
3530 | + this._map = null; | ||
3531 | + }, | ||
3532 | + | ||
3533 | + getLatLng: function () { | ||
3534 | + return this._latlng; | ||
3535 | + }, | ||
3536 | + | ||
3537 | + setLatLng: function (latlng) { | ||
3538 | + this._latlng = L.latLng(latlng); | ||
3539 | + | ||
3540 | + this.update(); | ||
3541 | + | ||
3542 | + return this.fire('move', { latlng: this._latlng }); | ||
3543 | + }, | ||
3544 | + | ||
3545 | + setZIndexOffset: function (offset) { | ||
3546 | + this.options.zIndexOffset = offset; | ||
3547 | + this.update(); | ||
3548 | + | ||
3549 | + return this; | ||
3550 | + }, | ||
3551 | + | ||
3552 | + setIcon: function (icon) { | ||
3553 | + | ||
3554 | + this.options.icon = icon; | ||
3555 | + | ||
3556 | + if (this._map) { | ||
3557 | + this._initIcon(); | ||
3558 | + this.update(); | ||
3559 | + } | ||
3560 | + | ||
3561 | + if (this._popup) { | ||
3562 | + this.bindPopup(this._popup); | ||
3563 | + } | ||
3564 | + | ||
3565 | + return this; | ||
3566 | + }, | ||
3567 | + | ||
3568 | + update: function () { | ||
3569 | + if (this._icon) { | ||
3570 | + var pos = this._map.latLngToLayerPoint(this._latlng).round(); | ||
3571 | + this._setPos(pos); | ||
3572 | + } | ||
3573 | + | ||
3574 | + return this; | ||
3575 | + }, | ||
3576 | + | ||
3577 | + _initIcon: function () { | ||
3578 | + var options = this.options, | ||
3579 | + map = this._map, | ||
3580 | + animation = (map.options.zoomAnimation && map.options.markerZoomAnimation), | ||
3581 | + classToAdd = animation ? 'leaflet-zoom-animated' : 'leaflet-zoom-hide'; | ||
3582 | + | ||
3583 | + var icon = options.icon.createIcon(this._icon), | ||
3584 | + addIcon = false; | ||
3585 | + | ||
3586 | + // if we're not reusing the icon, remove the old one and init new one | ||
3587 | + if (icon !== this._icon) { | ||
3588 | + if (this._icon) { | ||
3589 | + this._removeIcon(); | ||
3590 | + } | ||
3591 | + addIcon = true; | ||
3592 | + | ||
3593 | + if (options.title) { | ||
3594 | + icon.title = options.title; | ||
3595 | + } | ||
3596 | + | ||
3597 | + if (options.alt) { | ||
3598 | + icon.alt = options.alt; | ||
3599 | + } | ||
3600 | + } | ||
3601 | + | ||
3602 | + L.DomUtil.addClass(icon, classToAdd); | ||
3603 | + | ||
3604 | + if (options.keyboard) { | ||
3605 | + icon.tabIndex = '0'; | ||
3606 | + } | ||
3607 | + | ||
3608 | + this._icon = icon; | ||
3609 | + | ||
3610 | + this._initInteraction(); | ||
3611 | + | ||
3612 | + if (options.riseOnHover) { | ||
3613 | + L.DomEvent | ||
3614 | + .on(icon, 'mouseover', this._bringToFront, this) | ||
3615 | + .on(icon, 'mouseout', this._resetZIndex, this); | ||
3616 | + } | ||
3617 | + | ||
3618 | + var newShadow = options.icon.createShadow(this._shadow), | ||
3619 | + addShadow = false; | ||
3620 | + | ||
3621 | + if (newShadow !== this._shadow) { | ||
3622 | + this._removeShadow(); | ||
3623 | + addShadow = true; | ||
3624 | + } | ||
3625 | + | ||
3626 | + if (newShadow) { | ||
3627 | + L.DomUtil.addClass(newShadow, classToAdd); | ||
3628 | + } | ||
3629 | + this._shadow = newShadow; | ||
3630 | + | ||
3631 | + | ||
3632 | + if (options.opacity < 1) { | ||
3633 | + this._updateOpacity(); | ||
3634 | + } | ||
3635 | + | ||
3636 | + | ||
3637 | + var panes = this._map._panes; | ||
3638 | + | ||
3639 | + if (addIcon) { | ||
3640 | + panes.markerPane.appendChild(this._icon); | ||
3641 | + } | ||
3642 | + | ||
3643 | + if (newShadow && addShadow) { | ||
3644 | + panes.shadowPane.appendChild(this._shadow); | ||
3645 | + } | ||
3646 | + }, | ||
3647 | + | ||
3648 | + _removeIcon: function () { | ||
3649 | + if (this.options.riseOnHover) { | ||
3650 | + L.DomEvent | ||
3651 | + .off(this._icon, 'mouseover', this._bringToFront) | ||
3652 | + .off(this._icon, 'mouseout', this._resetZIndex); | ||
3653 | + } | ||
3654 | + | ||
3655 | + this._map._panes.markerPane.removeChild(this._icon); | ||
3656 | + | ||
3657 | + this._icon = null; | ||
3658 | + }, | ||
3659 | + | ||
3660 | + _removeShadow: function () { | ||
3661 | + if (this._shadow) { | ||
3662 | + this._map._panes.shadowPane.removeChild(this._shadow); | ||
3663 | + } | ||
3664 | + this._shadow = null; | ||
3665 | + }, | ||
3666 | + | ||
3667 | + _setPos: function (pos) { | ||
3668 | + L.DomUtil.setPosition(this._icon, pos); | ||
3669 | + | ||
3670 | + if (this._shadow) { | ||
3671 | + L.DomUtil.setPosition(this._shadow, pos); | ||
3672 | + } | ||
3673 | + | ||
3674 | + this._zIndex = pos.y + this.options.zIndexOffset; | ||
3675 | + | ||
3676 | + this._resetZIndex(); | ||
3677 | + }, | ||
3678 | + | ||
3679 | + _updateZIndex: function (offset) { | ||
3680 | + this._icon.style.zIndex = this._zIndex + offset; | ||
3681 | + }, | ||
3682 | + | ||
3683 | + _animateZoom: function (opt) { | ||
3684 | + var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round(); | ||
3685 | + | ||
3686 | + this._setPos(pos); | ||
3687 | + }, | ||
3688 | + | ||
3689 | + _initInteraction: function () { | ||
3690 | + | ||
3691 | + if (!this.options.clickable) { return; } | ||
3692 | + | ||
3693 | + // TODO refactor into something shared with Map/Path/etc. to DRY it up | ||
3694 | + | ||
3695 | + var icon = this._icon, | ||
3696 | + events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu']; | ||
3697 | + | ||
3698 | + L.DomUtil.addClass(icon, 'leaflet-clickable'); | ||
3699 | + L.DomEvent.on(icon, 'click', this._onMouseClick, this); | ||
3700 | + L.DomEvent.on(icon, 'keypress', this._onKeyPress, this); | ||
3701 | + | ||
3702 | + for (var i = 0; i < events.length; i++) { | ||
3703 | + L.DomEvent.on(icon, events[i], this._fireMouseEvent, this); | ||
3704 | + } | ||
3705 | + | ||
3706 | + if (L.Handler.MarkerDrag) { | ||
3707 | + this.dragging = new L.Handler.MarkerDrag(this); | ||
3708 | + | ||
3709 | + if (this.options.draggable) { | ||
3710 | + this.dragging.enable(); | ||
3711 | + } | ||
3712 | + } | ||
3713 | + }, | ||
3714 | + | ||
3715 | + _onMouseClick: function (e) { | ||
3716 | + var wasDragged = this.dragging && this.dragging.moved(); | ||
3717 | + | ||
3718 | + if (this.hasEventListeners(e.type) || wasDragged) { | ||
3719 | + L.DomEvent.stopPropagation(e); | ||
3720 | + } | ||
3721 | + | ||
3722 | + if (wasDragged) { return; } | ||
3723 | + | ||
3724 | + if ((!this.dragging || !this.dragging._enabled) && this._map.dragging && this._map.dragging.moved()) { return; } | ||
3725 | + | ||
3726 | + this.fire(e.type, { | ||
3727 | + originalEvent: e, | ||
3728 | + latlng: this._latlng | ||
3729 | + }); | ||
3730 | + }, | ||
3731 | + | ||
3732 | + _onKeyPress: function (e) { | ||
3733 | + if (e.keyCode === 13) { | ||
3734 | + this.fire('click', { | ||
3735 | + originalEvent: e, | ||
3736 | + latlng: this._latlng | ||
3737 | + }); | ||
3738 | + } | ||
3739 | + }, | ||
3740 | + | ||
3741 | + _fireMouseEvent: function (e) { | ||
3742 | + | ||
3743 | + this.fire(e.type, { | ||
3744 | + originalEvent: e, | ||
3745 | + latlng: this._latlng | ||
3746 | + }); | ||
3747 | + | ||
3748 | + // TODO proper custom event propagation | ||
3749 | + // this line will always be called if marker is in a FeatureGroup | ||
3750 | + if (e.type === 'contextmenu' && this.hasEventListeners(e.type)) { | ||
3751 | + L.DomEvent.preventDefault(e); | ||
3752 | + } | ||
3753 | + if (e.type !== 'mousedown') { | ||
3754 | + L.DomEvent.stopPropagation(e); | ||
3755 | + } else { | ||
3756 | + L.DomEvent.preventDefault(e); | ||
3757 | + } | ||
3758 | + }, | ||
3759 | + | ||
3760 | + setOpacity: function (opacity) { | ||
3761 | + this.options.opacity = opacity; | ||
3762 | + if (this._map) { | ||
3763 | + this._updateOpacity(); | ||
3764 | + } | ||
3765 | + | ||
3766 | + return this; | ||
3767 | + }, | ||
3768 | + | ||
3769 | + _updateOpacity: function () { | ||
3770 | + L.DomUtil.setOpacity(this._icon, this.options.opacity); | ||
3771 | + if (this._shadow) { | ||
3772 | + L.DomUtil.setOpacity(this._shadow, this.options.opacity); | ||
3773 | + } | ||
3774 | + }, | ||
3775 | + | ||
3776 | + _bringToFront: function () { | ||
3777 | + this._updateZIndex(this.options.riseOffset); | ||
3778 | + }, | ||
3779 | + | ||
3780 | + _resetZIndex: function () { | ||
3781 | + this._updateZIndex(0); | ||
3782 | + } | ||
3783 | +}); | ||
3784 | + | ||
3785 | +L.marker = function (latlng, options) { | ||
3786 | + return new L.Marker(latlng, options); | ||
3787 | +}; | ||
3788 | + | ||
3789 | + | ||
3790 | +/* | ||
3791 | + * L.DivIcon is a lightweight HTML-based icon class (as opposed to the image-based L.Icon) | ||
3792 | + * to use with L.Marker. | ||
3793 | + */ | ||
3794 | + | ||
3795 | +L.DivIcon = L.Icon.extend({ | ||
3796 | + options: { | ||
3797 | + iconSize: [12, 12], // also can be set through CSS | ||
3798 | + /* | ||
3799 | + iconAnchor: (Point) | ||
3800 | + popupAnchor: (Point) | ||
3801 | + html: (String) | ||
3802 | + bgPos: (Point) | ||
3803 | + */ | ||
3804 | + className: 'leaflet-div-icon', | ||
3805 | + html: false | ||
3806 | + }, | ||
3807 | + | ||
3808 | + createIcon: function (oldIcon) { | ||
3809 | + var div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'), | ||
3810 | + options = this.options; | ||
3811 | + | ||
3812 | + if (options.html !== false) { | ||
3813 | + div.innerHTML = options.html; | ||
3814 | + } else { | ||
3815 | + div.innerHTML = ''; | ||
3816 | + } | ||
3817 | + | ||
3818 | + if (options.bgPos) { | ||
3819 | + div.style.backgroundPosition = | ||
3820 | + (-options.bgPos.x) + 'px ' + (-options.bgPos.y) + 'px'; | ||
3821 | + } | ||
3822 | + | ||
3823 | + this._setIconStyles(div, 'icon'); | ||
3824 | + return div; | ||
3825 | + }, | ||
3826 | + | ||
3827 | + createShadow: function () { | ||
3828 | + return null; | ||
3829 | + } | ||
3830 | +}); | ||
3831 | + | ||
3832 | +L.divIcon = function (options) { | ||
3833 | + return new L.DivIcon(options); | ||
3834 | +}; | ||
3835 | + | ||
3836 | + | ||
3837 | +/* | ||
3838 | + * L.Popup is used for displaying popups on the map. | ||
3839 | + */ | ||
3840 | + | ||
3841 | +L.Map.mergeOptions({ | ||
3842 | + closePopupOnClick: true | ||
3843 | +}); | ||
3844 | + | ||
3845 | +L.Popup = L.Class.extend({ | ||
3846 | + includes: L.Mixin.Events, | ||
3847 | + | ||
3848 | + options: { | ||
3849 | + minWidth: 50, | ||
3850 | + maxWidth: 300, | ||
3851 | + // maxHeight: null, | ||
3852 | + autoPan: true, | ||
3853 | + closeButton: true, | ||
3854 | + offset: [0, 7], | ||
3855 | + autoPanPadding: [5, 5], | ||
3856 | + // autoPanPaddingTopLeft: null, | ||
3857 | + // autoPanPaddingBottomRight: null, | ||
3858 | + keepInView: false, | ||
3859 | + className: '', | ||
3860 | + zoomAnimation: true | ||
3861 | + }, | ||
3862 | + | ||
3863 | + initialize: function (options, source) { | ||
3864 | + L.setOptions(this, options); | ||
3865 | + | ||
3866 | + this._source = source; | ||
3867 | + this._animated = L.Browser.any3d && this.options.zoomAnimation; | ||
3868 | + this._isOpen = false; | ||
3869 | + }, | ||
3870 | + | ||
3871 | + onAdd: function (map) { | ||
3872 | + this._map = map; | ||
3873 | + | ||
3874 | + if (!this._container) { | ||
3875 | + this._initLayout(); | ||
3876 | + } | ||
3877 | + | ||
3878 | + var animFade = map.options.fadeAnimation; | ||
3879 | + | ||
3880 | + if (animFade) { | ||
3881 | + L.DomUtil.setOpacity(this._container, 0); | ||
3882 | + } | ||
3883 | + map._panes.popupPane.appendChild(this._container); | ||
3884 | + | ||
3885 | + map.on(this._getEvents(), this); | ||
3886 | + | ||
3887 | + this.update(); | ||
3888 | + | ||
3889 | + if (animFade) { | ||
3890 | + L.DomUtil.setOpacity(this._container, 1); | ||
3891 | + } | ||
3892 | + | ||
3893 | + this.fire('open'); | ||
3894 | + | ||
3895 | + map.fire('popupopen', {popup: this}); | ||
3896 | + | ||
3897 | + if (this._source) { | ||
3898 | + this._source.fire('popupopen', {popup: this}); | ||
3899 | + } | ||
3900 | + }, | ||
3901 | + | ||
3902 | + addTo: function (map) { | ||
3903 | + map.addLayer(this); | ||
3904 | + return this; | ||
3905 | + }, | ||
3906 | + | ||
3907 | + openOn: function (map) { | ||
3908 | + map.openPopup(this); | ||
3909 | + return this; | ||
3910 | + }, | ||
3911 | + | ||
3912 | + onRemove: function (map) { | ||
3913 | + map._panes.popupPane.removeChild(this._container); | ||
3914 | + | ||
3915 | + L.Util.falseFn(this._container.offsetWidth); // force reflow | ||
3916 | + | ||
3917 | + map.off(this._getEvents(), this); | ||
3918 | + | ||
3919 | + if (map.options.fadeAnimation) { | ||
3920 | + L.DomUtil.setOpacity(this._container, 0); | ||
3921 | + } | ||
3922 | + | ||
3923 | + this._map = null; | ||
3924 | + | ||
3925 | + this.fire('close'); | ||
3926 | + | ||
3927 | + map.fire('popupclose', {popup: this}); | ||
3928 | + | ||
3929 | + if (this._source) { | ||
3930 | + this._source.fire('popupclose', {popup: this}); | ||
3931 | + } | ||
3932 | + }, | ||
3933 | + | ||
3934 | + getLatLng: function () { | ||
3935 | + return this._latlng; | ||
3936 | + }, | ||
3937 | + | ||
3938 | + setLatLng: function (latlng) { | ||
3939 | + this._latlng = L.latLng(latlng); | ||
3940 | + if (this._map) { | ||
3941 | + this._updatePosition(); | ||
3942 | + this._adjustPan(); | ||
3943 | + } | ||
3944 | + return this; | ||
3945 | + }, | ||
3946 | + | ||
3947 | + getContent: function () { | ||
3948 | + return this._content; | ||
3949 | + }, | ||
3950 | + | ||
3951 | + setContent: function (content) { | ||
3952 | + this._content = content; | ||
3953 | + this.update(); | ||
3954 | + return this; | ||
3955 | + }, | ||
3956 | + | ||
3957 | + update: function () { | ||
3958 | + if (!this._map) { return; } | ||
3959 | + | ||
3960 | + this._container.style.visibility = 'hidden'; | ||
3961 | + | ||
3962 | + this._updateContent(); | ||
3963 | + this._updateLayout(); | ||
3964 | + this._updatePosition(); | ||
3965 | + | ||
3966 | + this._container.style.visibility = ''; | ||
3967 | + | ||
3968 | + this._adjustPan(); | ||
3969 | + }, | ||
3970 | + | ||
3971 | + _getEvents: function () { | ||
3972 | + var events = { | ||
3973 | + viewreset: this._updatePosition | ||
3974 | + }; | ||
3975 | + | ||
3976 | + if (this._animated) { | ||
3977 | + events.zoomanim = this._zoomAnimation; | ||
3978 | + } | ||
3979 | + if ('closeOnClick' in this.options ? this.options.closeOnClick : this._map.options.closePopupOnClick) { | ||
3980 | + events.preclick = this._close; | ||
3981 | + } | ||
3982 | + if (this.options.keepInView) { | ||
3983 | + events.moveend = this._adjustPan; | ||
3984 | + } | ||
3985 | + | ||
3986 | + return events; | ||
3987 | + }, | ||
3988 | + | ||
3989 | + _close: function () { | ||
3990 | + if (this._map) { | ||
3991 | + this._map.closePopup(this); | ||
3992 | + } | ||
3993 | + }, | ||
3994 | + | ||
3995 | + _initLayout: function () { | ||
3996 | + var prefix = 'leaflet-popup', | ||
3997 | + containerClass = prefix + ' ' + this.options.className + ' leaflet-zoom-' + | ||
3998 | + (this._animated ? 'animated' : 'hide'), | ||
3999 | + container = this._container = L.DomUtil.create('div', containerClass), | ||
4000 | + closeButton; | ||
4001 | + | ||
4002 | + if (this.options.closeButton) { | ||
4003 | + closeButton = this._closeButton = | ||
4004 | + L.DomUtil.create('a', prefix + '-close-button', container); | ||
4005 | + closeButton.href = '#close'; | ||
4006 | + closeButton.innerHTML = '×'; | ||
4007 | + L.DomEvent.disableClickPropagation(closeButton); | ||
4008 | + | ||
4009 | + L.DomEvent.on(closeButton, 'click', this._onCloseButtonClick, this); | ||
4010 | + } | ||
4011 | + | ||
4012 | + var wrapper = this._wrapper = | ||
4013 | + L.DomUtil.create('div', prefix + '-content-wrapper', container); | ||
4014 | + L.DomEvent.disableClickPropagation(wrapper); | ||
4015 | + | ||
4016 | + this._contentNode = L.DomUtil.create('div', prefix + '-content', wrapper); | ||
4017 | + | ||
4018 | + L.DomEvent.disableScrollPropagation(this._contentNode); | ||
4019 | + L.DomEvent.on(wrapper, 'contextmenu', L.DomEvent.stopPropagation); | ||
4020 | + | ||
4021 | + this._tipContainer = L.DomUtil.create('div', prefix + '-tip-container', container); | ||
4022 | + this._tip = L.DomUtil.create('div', prefix + '-tip', this._tipContainer); | ||
4023 | + }, | ||
4024 | + | ||
4025 | + _updateContent: function () { | ||
4026 | + if (!this._content) { return; } | ||
4027 | + | ||
4028 | + if (typeof this._content === 'string') { | ||
4029 | + this._contentNode.innerHTML = this._content; | ||
4030 | + } else { | ||
4031 | + while (this._contentNode.hasChildNodes()) { | ||
4032 | + this._contentNode.removeChild(this._contentNode.firstChild); | ||
4033 | + } | ||
4034 | + this._contentNode.appendChild(this._content); | ||
4035 | + } | ||
4036 | + this.fire('contentupdate'); | ||
4037 | + }, | ||
4038 | + | ||
4039 | + _updateLayout: function () { | ||
4040 | + var container = this._contentNode, | ||
4041 | + style = container.style; | ||
4042 | + | ||
4043 | + style.width = ''; | ||
4044 | + style.whiteSpace = 'nowrap'; | ||
4045 | + | ||
4046 | + var width = container.offsetWidth; | ||
4047 | + width = Math.min(width, this.options.maxWidth); | ||
4048 | + width = Math.max(width, this.options.minWidth); | ||
4049 | + | ||
4050 | + style.width = (width + 1) + 'px'; | ||
4051 | + style.whiteSpace = ''; | ||
4052 | + | ||
4053 | + style.height = ''; | ||
4054 | + | ||
4055 | + var height = container.offsetHeight, | ||
4056 | + maxHeight = this.options.maxHeight, | ||
4057 | + scrolledClass = 'leaflet-popup-scrolled'; | ||
4058 | + | ||
4059 | + if (maxHeight && height > maxHeight) { | ||
4060 | + style.height = maxHeight + 'px'; | ||
4061 | + L.DomUtil.addClass(container, scrolledClass); | ||
4062 | + } else { | ||
4063 | + L.DomUtil.removeClass(container, scrolledClass); | ||
4064 | + } | ||
4065 | + | ||
4066 | + this._containerWidth = this._container.offsetWidth; | ||
4067 | + }, | ||
4068 | + | ||
4069 | + _updatePosition: function () { | ||
4070 | + if (!this._map) { return; } | ||
4071 | + | ||
4072 | + var pos = this._map.latLngToLayerPoint(this._latlng), | ||
4073 | + animated = this._animated, | ||
4074 | + offset = L.point(this.options.offset); | ||
4075 | + | ||
4076 | + if (animated) { | ||
4077 | + L.DomUtil.setPosition(this._container, pos); | ||
4078 | + } | ||
4079 | + | ||
4080 | + this._containerBottom = -offset.y - (animated ? 0 : pos.y); | ||
4081 | + this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x + (animated ? 0 : pos.x); | ||
4082 | + | ||
4083 | + // bottom position the popup in case the height of the popup changes (images loading etc) | ||
4084 | + this._container.style.bottom = this._containerBottom + 'px'; | ||
4085 | + this._container.style.left = this._containerLeft + 'px'; | ||
4086 | + }, | ||
4087 | + | ||
4088 | + _zoomAnimation: function (opt) { | ||
4089 | + var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center); | ||
4090 | + | ||
4091 | + L.DomUtil.setPosition(this._container, pos); | ||
4092 | + }, | ||
4093 | + | ||
4094 | + _adjustPan: function () { | ||
4095 | + if (!this.options.autoPan) { return; } | ||
4096 | + | ||
4097 | + var map = this._map, | ||
4098 | + containerHeight = this._container.offsetHeight, | ||
4099 | + containerWidth = this._containerWidth, | ||
4100 | + | ||
4101 | + layerPos = new L.Point(this._containerLeft, -containerHeight - this._containerBottom); | ||
4102 | + | ||
4103 | + if (this._animated) { | ||
4104 | + layerPos._add(L.DomUtil.getPosition(this._container)); | ||
4105 | + } | ||
4106 | + | ||
4107 | + var containerPos = map.layerPointToContainerPoint(layerPos), | ||
4108 | + padding = L.point(this.options.autoPanPadding), | ||
4109 | + paddingTL = L.point(this.options.autoPanPaddingTopLeft || padding), | ||
4110 | + paddingBR = L.point(this.options.autoPanPaddingBottomRight || padding), | ||
4111 | + size = map.getSize(), | ||
4112 | + dx = 0, | ||
4113 | + dy = 0; | ||
4114 | + | ||
4115 | + if (containerPos.x + containerWidth + paddingBR.x > size.x) { // right | ||
4116 | + dx = containerPos.x + containerWidth - size.x + paddingBR.x; | ||
4117 | + } | ||
4118 | + if (containerPos.x - dx - paddingTL.x < 0) { // left | ||
4119 | + dx = containerPos.x - paddingTL.x; | ||
4120 | + } | ||
4121 | + if (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom | ||
4122 | + dy = containerPos.y + containerHeight - size.y + paddingBR.y; | ||
4123 | + } | ||
4124 | + if (containerPos.y - dy - paddingTL.y < 0) { // top | ||
4125 | + dy = containerPos.y - paddingTL.y; | ||
4126 | + } | ||
4127 | + | ||
4128 | + if (dx || dy) { | ||
4129 | + map | ||
4130 | + .fire('autopanstart') | ||
4131 | + .panBy([dx, dy]); | ||
4132 | + } | ||
4133 | + }, | ||
4134 | + | ||
4135 | + _onCloseButtonClick: function (e) { | ||
4136 | + this._close(); | ||
4137 | + L.DomEvent.stop(e); | ||
4138 | + } | ||
4139 | +}); | ||
4140 | + | ||
4141 | +L.popup = function (options, source) { | ||
4142 | + return new L.Popup(options, source); | ||
4143 | +}; | ||
4144 | + | ||
4145 | + | ||
4146 | +L.Map.include({ | ||
4147 | + openPopup: function (popup, latlng, options) { // (Popup) or (String || HTMLElement, LatLng[, Object]) | ||
4148 | + this.closePopup(); | ||
4149 | + | ||
4150 | + if (!(popup instanceof L.Popup)) { | ||
4151 | + var content = popup; | ||
4152 | + | ||
4153 | + popup = new L.Popup(options) | ||
4154 | + .setLatLng(latlng) | ||
4155 | + .setContent(content); | ||
4156 | + } | ||
4157 | + popup._isOpen = true; | ||
4158 | + | ||
4159 | + this._popup = popup; | ||
4160 | + return this.addLayer(popup); | ||
4161 | + }, | ||
4162 | + | ||
4163 | + closePopup: function (popup) { | ||
4164 | + if (!popup || popup === this._popup) { | ||
4165 | + popup = this._popup; | ||
4166 | + this._popup = null; | ||
4167 | + } | ||
4168 | + if (popup) { | ||
4169 | + this.removeLayer(popup); | ||
4170 | + popup._isOpen = false; | ||
4171 | + } | ||
4172 | + return this; | ||
4173 | + } | ||
4174 | +}); | ||
4175 | + | ||
4176 | + | ||
4177 | +/* | ||
4178 | + * Popup extension to L.Marker, adding popup-related methods. | ||
4179 | + */ | ||
4180 | + | ||
4181 | +L.Marker.include({ | ||
4182 | + openPopup: function () { | ||
4183 | + if (this._popup && this._map && !this._map.hasLayer(this._popup)) { | ||
4184 | + this._popup.setLatLng(this._latlng); | ||
4185 | + this._map.openPopup(this._popup); | ||
4186 | + } | ||
4187 | + | ||
4188 | + return this; | ||
4189 | + }, | ||
4190 | + | ||
4191 | + closePopup: function () { | ||
4192 | + if (this._popup) { | ||
4193 | + this._popup._close(); | ||
4194 | + } | ||
4195 | + return this; | ||
4196 | + }, | ||
4197 | + | ||
4198 | + togglePopup: function () { | ||
4199 | + if (this._popup) { | ||
4200 | + if (this._popup._isOpen) { | ||
4201 | + this.closePopup(); | ||
4202 | + } else { | ||
4203 | + this.openPopup(); | ||
4204 | + } | ||
4205 | + } | ||
4206 | + return this; | ||
4207 | + }, | ||
4208 | + | ||
4209 | + bindPopup: function (content, options) { | ||
4210 | + var anchor = L.point(this.options.icon.options.popupAnchor || [0, 0]); | ||
4211 | + | ||
4212 | + anchor = anchor.add(L.Popup.prototype.options.offset); | ||
4213 | + | ||
4214 | + if (options && options.offset) { | ||
4215 | + anchor = anchor.add(options.offset); | ||
4216 | + } | ||
4217 | + | ||
4218 | + options = L.extend({offset: anchor}, options); | ||
4219 | + | ||
4220 | + if (!this._popupHandlersAdded) { | ||
4221 | + this | ||
4222 | + .on('click', this.togglePopup, this) | ||
4223 | + .on('remove', this.closePopup, this) | ||
4224 | + .on('move', this._movePopup, this); | ||
4225 | + this._popupHandlersAdded = true; | ||
4226 | + } | ||
4227 | + | ||
4228 | + if (content instanceof L.Popup) { | ||
4229 | + L.setOptions(content, options); | ||
4230 | + this._popup = content; | ||
4231 | + } else { | ||
4232 | + this._popup = new L.Popup(options, this) | ||
4233 | + .setContent(content); | ||
4234 | + } | ||
4235 | + | ||
4236 | + return this; | ||
4237 | + }, | ||
4238 | + | ||
4239 | + setPopupContent: function (content) { | ||
4240 | + if (this._popup) { | ||
4241 | + this._popup.setContent(content); | ||
4242 | + } | ||
4243 | + return this; | ||
4244 | + }, | ||
4245 | + | ||
4246 | + unbindPopup: function () { | ||
4247 | + if (this._popup) { | ||
4248 | + this._popup = null; | ||
4249 | + this | ||
4250 | + .off('click', this.togglePopup, this) | ||
4251 | + .off('remove', this.closePopup, this) | ||
4252 | + .off('move', this._movePopup, this); | ||
4253 | + this._popupHandlersAdded = false; | ||
4254 | + } | ||
4255 | + return this; | ||
4256 | + }, | ||
4257 | + | ||
4258 | + getPopup: function () { | ||
4259 | + return this._popup; | ||
4260 | + }, | ||
4261 | + | ||
4262 | + _movePopup: function (e) { | ||
4263 | + this._popup.setLatLng(e.latlng); | ||
4264 | + } | ||
4265 | +}); | ||
4266 | + | ||
4267 | + | ||
4268 | +/* | ||
4269 | + * L.LayerGroup is a class to combine several layers into one so that | ||
4270 | + * you can manipulate the group (e.g. add/remove it) as one layer. | ||
4271 | + */ | ||
4272 | + | ||
4273 | +L.LayerGroup = L.Class.extend({ | ||
4274 | + initialize: function (layers) { | ||
4275 | + this._layers = {}; | ||
4276 | + | ||
4277 | + var i, len; | ||
4278 | + | ||
4279 | + if (layers) { | ||
4280 | + for (i = 0, len = layers.length; i < len; i++) { | ||
4281 | + this.addLayer(layers[i]); | ||
4282 | + } | ||
4283 | + } | ||
4284 | + }, | ||
4285 | + | ||
4286 | + addLayer: function (layer) { | ||
4287 | + var id = this.getLayerId(layer); | ||
4288 | + | ||
4289 | + this._layers[id] = layer; | ||
4290 | + | ||
4291 | + if (this._map) { | ||
4292 | + this._map.addLayer(layer); | ||
4293 | + } | ||
4294 | + | ||
4295 | + return this; | ||
4296 | + }, | ||
4297 | + | ||
4298 | + removeLayer: function (layer) { | ||
4299 | + var id = layer in this._layers ? layer : this.getLayerId(layer); | ||
4300 | + | ||
4301 | + if (this._map && this._layers[id]) { | ||
4302 | + this._map.removeLayer(this._layers[id]); | ||
4303 | + } | ||
4304 | + | ||
4305 | + delete this._layers[id]; | ||
4306 | + | ||
4307 | + return this; | ||
4308 | + }, | ||
4309 | + | ||
4310 | + hasLayer: function (layer) { | ||
4311 | + if (!layer) { return false; } | ||
4312 | + | ||
4313 | + return (layer in this._layers || this.getLayerId(layer) in this._layers); | ||
4314 | + }, | ||
4315 | + | ||
4316 | + clearLayers: function () { | ||
4317 | + this.eachLayer(this.removeLayer, this); | ||
4318 | + return this; | ||
4319 | + }, | ||
4320 | + | ||
4321 | + invoke: function (methodName) { | ||
4322 | + var args = Array.prototype.slice.call(arguments, 1), | ||
4323 | + i, layer; | ||
4324 | + | ||
4325 | + for (i in this._layers) { | ||
4326 | + layer = this._layers[i]; | ||
4327 | + | ||
4328 | + if (layer[methodName]) { | ||
4329 | + layer[methodName].apply(layer, args); | ||
4330 | + } | ||
4331 | + } | ||
4332 | + | ||
4333 | + return this; | ||
4334 | + }, | ||
4335 | + | ||
4336 | + onAdd: function (map) { | ||
4337 | + this._map = map; | ||
4338 | + this.eachLayer(map.addLayer, map); | ||
4339 | + }, | ||
4340 | + | ||
4341 | + onRemove: function (map) { | ||
4342 | + this.eachLayer(map.removeLayer, map); | ||
4343 | + this._map = null; | ||
4344 | + }, | ||
4345 | + | ||
4346 | + addTo: function (map) { | ||
4347 | + map.addLayer(this); | ||
4348 | + return this; | ||
4349 | + }, | ||
4350 | + | ||
4351 | + eachLayer: function (method, context) { | ||
4352 | + for (var i in this._layers) { | ||
4353 | + method.call(context, this._layers[i]); | ||
4354 | + } | ||
4355 | + return this; | ||
4356 | + }, | ||
4357 | + | ||
4358 | + getLayer: function (id) { | ||
4359 | + return this._layers[id]; | ||
4360 | + }, | ||
4361 | + | ||
4362 | + getLayers: function () { | ||
4363 | + var layers = []; | ||
4364 | + | ||
4365 | + for (var i in this._layers) { | ||
4366 | + layers.push(this._layers[i]); | ||
4367 | + } | ||
4368 | + return layers; | ||
4369 | + }, | ||
4370 | + | ||
4371 | + setZIndex: function (zIndex) { | ||
4372 | + return this.invoke('setZIndex', zIndex); | ||
4373 | + }, | ||
4374 | + | ||
4375 | + getLayerId: function (layer) { | ||
4376 | + return L.stamp(layer); | ||
4377 | + } | ||
4378 | +}); | ||
4379 | + | ||
4380 | +L.layerGroup = function (layers) { | ||
4381 | + return new L.LayerGroup(layers); | ||
4382 | +}; | ||
4383 | + | ||
4384 | + | ||
4385 | +/* | ||
4386 | + * L.FeatureGroup extends L.LayerGroup by introducing mouse events and additional methods | ||
4387 | + * shared between a group of interactive layers (like vectors or markers). | ||
4388 | + */ | ||
4389 | + | ||
4390 | +L.FeatureGroup = L.LayerGroup.extend({ | ||
4391 | + includes: L.Mixin.Events, | ||
4392 | + | ||
4393 | + statics: { | ||
4394 | + EVENTS: 'click dblclick mouseover mouseout mousemove contextmenu popupopen popupclose' | ||
4395 | + }, | ||
4396 | + | ||
4397 | + addLayer: function (layer) { | ||
4398 | + if (this.hasLayer(layer)) { | ||
4399 | + return this; | ||
4400 | + } | ||
4401 | + | ||
4402 | + if ('on' in layer) { | ||
4403 | + layer.on(L.FeatureGroup.EVENTS, this._propagateEvent, this); | ||
4404 | + } | ||
4405 | + | ||
4406 | + L.LayerGroup.prototype.addLayer.call(this, layer); | ||
4407 | + | ||
4408 | + if (this._popupContent && layer.bindPopup) { | ||
4409 | + layer.bindPopup(this._popupContent, this._popupOptions); | ||
4410 | + } | ||
4411 | + | ||
4412 | + return this.fire('layeradd', {layer: layer}); | ||
4413 | + }, | ||
4414 | + | ||
4415 | + removeLayer: function (layer) { | ||
4416 | + if (!this.hasLayer(layer)) { | ||
4417 | + return this; | ||
4418 | + } | ||
4419 | + if (layer in this._layers) { | ||
4420 | + layer = this._layers[layer]; | ||
4421 | + } | ||
4422 | + | ||
4423 | + layer.off(L.FeatureGroup.EVENTS, this._propagateEvent, this); | ||
4424 | + | ||
4425 | + L.LayerGroup.prototype.removeLayer.call(this, layer); | ||
4426 | + | ||
4427 | + if (this._popupContent) { | ||
4428 | + this.invoke('unbindPopup'); | ||
4429 | + } | ||
4430 | + | ||
4431 | + return this.fire('layerremove', {layer: layer}); | ||
4432 | + }, | ||
4433 | + | ||
4434 | + bindPopup: function (content, options) { | ||
4435 | + this._popupContent = content; | ||
4436 | + this._popupOptions = options; | ||
4437 | + return this.invoke('bindPopup', content, options); | ||
4438 | + }, | ||
4439 | + | ||
4440 | + openPopup: function (latlng) { | ||
4441 | + // open popup on the first layer | ||
4442 | + for (var id in this._layers) { | ||
4443 | + this._layers[id].openPopup(latlng); | ||
4444 | + break; | ||
4445 | + } | ||
4446 | + return this; | ||
4447 | + }, | ||
4448 | + | ||
4449 | + setStyle: function (style) { | ||
4450 | + return this.invoke('setStyle', style); | ||
4451 | + }, | ||
4452 | + | ||
4453 | + bringToFront: function () { | ||
4454 | + return this.invoke('bringToFront'); | ||
4455 | + }, | ||
4456 | + | ||
4457 | + bringToBack: function () { | ||
4458 | + return this.invoke('bringToBack'); | ||
4459 | + }, | ||
4460 | + | ||
4461 | + getBounds: function () { | ||
4462 | + var bounds = new L.LatLngBounds(); | ||
4463 | + | ||
4464 | + this.eachLayer(function (layer) { | ||
4465 | + bounds.extend(layer instanceof L.Marker ? layer.getLatLng() : layer.getBounds()); | ||
4466 | + }); | ||
4467 | + | ||
4468 | + return bounds; | ||
4469 | + }, | ||
4470 | + | ||
4471 | + _propagateEvent: function (e) { | ||
4472 | + e = L.extend({ | ||
4473 | + layer: e.target, | ||
4474 | + target: this | ||
4475 | + }, e); | ||
4476 | + this.fire(e.type, e); | ||
4477 | + } | ||
4478 | +}); | ||
4479 | + | ||
4480 | +L.featureGroup = function (layers) { | ||
4481 | + return new L.FeatureGroup(layers); | ||
4482 | +}; | ||
4483 | + | ||
4484 | + | ||
4485 | +/* | ||
4486 | + * L.Path is a base class for rendering vector paths on a map. Inherited by Polyline, Circle, etc. | ||
4487 | + */ | ||
4488 | + | ||
4489 | +L.Path = L.Class.extend({ | ||
4490 | + includes: [L.Mixin.Events], | ||
4491 | + | ||
4492 | + statics: { | ||
4493 | + // how much to extend the clip area around the map view | ||
4494 | + // (relative to its size, e.g. 0.5 is half the screen in each direction) | ||
4495 | + // set it so that SVG element doesn't exceed 1280px (vectors flicker on dragend if it is) | ||
4496 | + CLIP_PADDING: (function () { | ||
4497 | + var max = L.Browser.mobile ? 1280 : 2000, | ||
4498 | + target = (max / Math.max(window.outerWidth, window.outerHeight) - 1) / 2; | ||
4499 | + return Math.max(0, Math.min(0.5, target)); | ||
4500 | + })() | ||
4501 | + }, | ||
4502 | + | ||
4503 | + options: { | ||
4504 | + stroke: true, | ||
4505 | + color: '#0033ff', | ||
4506 | + dashArray: null, | ||
4507 | + lineCap: null, | ||
4508 | + lineJoin: null, | ||
4509 | + weight: 5, | ||
4510 | + opacity: 0.5, | ||
4511 | + | ||
4512 | + fill: false, | ||
4513 | + fillColor: null, //same as color by default | ||
4514 | + fillOpacity: 0.2, | ||
4515 | + | ||
4516 | + clickable: true | ||
4517 | + }, | ||
4518 | + | ||
4519 | + initialize: function (options) { | ||
4520 | + L.setOptions(this, options); | ||
4521 | + }, | ||
4522 | + | ||
4523 | + onAdd: function (map) { | ||
4524 | + this._map = map; | ||
4525 | + | ||
4526 | + if (!this._container) { | ||
4527 | + this._initElements(); | ||
4528 | + this._initEvents(); | ||
4529 | + } | ||
4530 | + | ||
4531 | + this.projectLatlngs(); | ||
4532 | + this._updatePath(); | ||
4533 | + | ||
4534 | + if (this._container) { | ||
4535 | + this._map._pathRoot.appendChild(this._container); | ||
4536 | + } | ||
4537 | + | ||
4538 | + this.fire('add'); | ||
4539 | + | ||
4540 | + map.on({ | ||
4541 | + 'viewreset': this.projectLatlngs, | ||
4542 | + 'moveend': this._updatePath | ||
4543 | + }, this); | ||
4544 | + }, | ||
4545 | + | ||
4546 | + addTo: function (map) { | ||
4547 | + map.addLayer(this); | ||
4548 | + return this; | ||
4549 | + }, | ||
4550 | + | ||
4551 | + onRemove: function (map) { | ||
4552 | + map._pathRoot.removeChild(this._container); | ||
4553 | + | ||
4554 | + // Need to fire remove event before we set _map to null as the event hooks might need the object | ||
4555 | + this.fire('remove'); | ||
4556 | + this._map = null; | ||
4557 | + | ||
4558 | + if (L.Browser.vml) { | ||
4559 | + this._container = null; | ||
4560 | + this._stroke = null; | ||
4561 | + this._fill = null; | ||
4562 | + } | ||
4563 | + | ||
4564 | + map.off({ | ||
4565 | + 'viewreset': this.projectLatlngs, | ||
4566 | + 'moveend': this._updatePath | ||
4567 | + }, this); | ||
4568 | + }, | ||
4569 | + | ||
4570 | + projectLatlngs: function () { | ||
4571 | + // do all projection stuff here | ||
4572 | + }, | ||
4573 | + | ||
4574 | + setStyle: function (style) { | ||
4575 | + L.setOptions(this, style); | ||
4576 | + | ||
4577 | + if (this._container) { | ||
4578 | + this._updateStyle(); | ||
4579 | + } | ||
4580 | + | ||
4581 | + return this; | ||
4582 | + }, | ||
4583 | + | ||
4584 | + redraw: function () { | ||
4585 | + if (this._map) { | ||
4586 | + this.projectLatlngs(); | ||
4587 | + this._updatePath(); | ||
4588 | + } | ||
4589 | + return this; | ||
4590 | + } | ||
4591 | +}); | ||
4592 | + | ||
4593 | +L.Map.include({ | ||
4594 | + _updatePathViewport: function () { | ||
4595 | + var p = L.Path.CLIP_PADDING, | ||
4596 | + size = this.getSize(), | ||
4597 | + panePos = L.DomUtil.getPosition(this._mapPane), | ||
4598 | + min = panePos.multiplyBy(-1)._subtract(size.multiplyBy(p)._round()), | ||
4599 | + max = min.add(size.multiplyBy(1 + p * 2)._round()); | ||
4600 | + | ||
4601 | + this._pathViewport = new L.Bounds(min, max); | ||
4602 | + } | ||
4603 | +}); | ||
4604 | + | ||
4605 | + | ||
4606 | +/* | ||
4607 | + * Extends L.Path with SVG-specific rendering code. | ||
4608 | + */ | ||
4609 | + | ||
4610 | +L.Path.SVG_NS = 'http://www.w3.org/2000/svg'; | ||
4611 | + | ||
4612 | +L.Browser.svg = !!(document.createElementNS && document.createElementNS(L.Path.SVG_NS, 'svg').createSVGRect); | ||
4613 | + | ||
4614 | +L.Path = L.Path.extend({ | ||
4615 | + statics: { | ||
4616 | + SVG: L.Browser.svg | ||
4617 | + }, | ||
4618 | + | ||
4619 | + bringToFront: function () { | ||
4620 | + var root = this._map._pathRoot, | ||
4621 | + path = this._container; | ||
4622 | + | ||
4623 | + if (path && root.lastChild !== path) { | ||
4624 | + root.appendChild(path); | ||
4625 | + } | ||
4626 | + return this; | ||
4627 | + }, | ||
4628 | + | ||
4629 | + bringToBack: function () { | ||
4630 | + var root = this._map._pathRoot, | ||
4631 | + path = this._container, | ||
4632 | + first = root.firstChild; | ||
4633 | + | ||
4634 | + if (path && first !== path) { | ||
4635 | + root.insertBefore(path, first); | ||
4636 | + } | ||
4637 | + return this; | ||
4638 | + }, | ||
4639 | + | ||
4640 | + getPathString: function () { | ||
4641 | + // form path string here | ||
4642 | + }, | ||
4643 | + | ||
4644 | + _createElement: function (name) { | ||
4645 | + return document.createElementNS(L.Path.SVG_NS, name); | ||
4646 | + }, | ||
4647 | + | ||
4648 | + _initElements: function () { | ||
4649 | + this._map._initPathRoot(); | ||
4650 | + this._initPath(); | ||
4651 | + this._initStyle(); | ||
4652 | + }, | ||
4653 | + | ||
4654 | + _initPath: function () { | ||
4655 | + this._container = this._createElement('g'); | ||
4656 | + | ||
4657 | + this._path = this._createElement('path'); | ||
4658 | + | ||
4659 | + if (this.options.className) { | ||
4660 | + L.DomUtil.addClass(this._path, this.options.className); | ||
4661 | + } | ||
4662 | + | ||
4663 | + this._container.appendChild(this._path); | ||
4664 | + }, | ||
4665 | + | ||
4666 | + _initStyle: function () { | ||
4667 | + if (this.options.stroke) { | ||
4668 | + this._path.setAttribute('stroke-linejoin', 'round'); | ||
4669 | + this._path.setAttribute('stroke-linecap', 'round'); | ||
4670 | + } | ||
4671 | + if (this.options.fill) { | ||
4672 | + this._path.setAttribute('fill-rule', 'evenodd'); | ||
4673 | + } | ||
4674 | + if (this.options.pointerEvents) { | ||
4675 | + this._path.setAttribute('pointer-events', this.options.pointerEvents); | ||
4676 | + } | ||
4677 | + if (!this.options.clickable && !this.options.pointerEvents) { | ||
4678 | + this._path.setAttribute('pointer-events', 'none'); | ||
4679 | + } | ||
4680 | + this._updateStyle(); | ||
4681 | + }, | ||
4682 | + | ||
4683 | + _updateStyle: function () { | ||
4684 | + if (this.options.stroke) { | ||
4685 | + this._path.setAttribute('stroke', this.options.color); | ||
4686 | + this._path.setAttribute('stroke-opacity', this.options.opacity); | ||
4687 | + this._path.setAttribute('stroke-width', this.options.weight); | ||
4688 | + if (this.options.dashArray) { | ||
4689 | + this._path.setAttribute('stroke-dasharray', this.options.dashArray); | ||
4690 | + } else { | ||
4691 | + this._path.removeAttribute('stroke-dasharray'); | ||
4692 | + } | ||
4693 | + if (this.options.lineCap) { | ||
4694 | + this._path.setAttribute('stroke-linecap', this.options.lineCap); | ||
4695 | + } | ||
4696 | + if (this.options.lineJoin) { | ||
4697 | + this._path.setAttribute('stroke-linejoin', this.options.lineJoin); | ||
4698 | + } | ||
4699 | + } else { | ||
4700 | + this._path.setAttribute('stroke', 'none'); | ||
4701 | + } | ||
4702 | + if (this.options.fill) { | ||
4703 | + this._path.setAttribute('fill', this.options.fillColor || this.options.color); | ||
4704 | + this._path.setAttribute('fill-opacity', this.options.fillOpacity); | ||
4705 | + } else { | ||
4706 | + this._path.setAttribute('fill', 'none'); | ||
4707 | + } | ||
4708 | + }, | ||
4709 | + | ||
4710 | + _updatePath: function () { | ||
4711 | + var str = this.getPathString(); | ||
4712 | + if (!str) { | ||
4713 | + // fix webkit empty string parsing bug | ||
4714 | + str = 'M0 0'; | ||
4715 | + } | ||
4716 | + this._path.setAttribute('d', str); | ||
4717 | + }, | ||
4718 | + | ||
4719 | + // TODO remove duplication with L.Map | ||
4720 | + _initEvents: function () { | ||
4721 | + if (this.options.clickable) { | ||
4722 | + if (L.Browser.svg || !L.Browser.vml) { | ||
4723 | + L.DomUtil.addClass(this._path, 'leaflet-clickable'); | ||
4724 | + } | ||
4725 | + | ||
4726 | + L.DomEvent.on(this._container, 'click', this._onMouseClick, this); | ||
4727 | + | ||
4728 | + var events = ['dblclick', 'mousedown', 'mouseover', | ||
4729 | + 'mouseout', 'mousemove', 'contextmenu']; | ||
4730 | + for (var i = 0; i < events.length; i++) { | ||
4731 | + L.DomEvent.on(this._container, events[i], this._fireMouseEvent, this); | ||
4732 | + } | ||
4733 | + } | ||
4734 | + }, | ||
4735 | + | ||
4736 | + _onMouseClick: function (e) { | ||
4737 | + if (this._map.dragging && this._map.dragging.moved()) { return; } | ||
4738 | + | ||
4739 | + this._fireMouseEvent(e); | ||
4740 | + }, | ||
4741 | + | ||
4742 | + _fireMouseEvent: function (e) { | ||
4743 | + if (!this.hasEventListeners(e.type)) { return; } | ||
4744 | + | ||
4745 | + var map = this._map, | ||
4746 | + containerPoint = map.mouseEventToContainerPoint(e), | ||
4747 | + layerPoint = map.containerPointToLayerPoint(containerPoint), | ||
4748 | + latlng = map.layerPointToLatLng(layerPoint); | ||
4749 | + | ||
4750 | + this.fire(e.type, { | ||
4751 | + latlng: latlng, | ||
4752 | + layerPoint: layerPoint, | ||
4753 | + containerPoint: containerPoint, | ||
4754 | + originalEvent: e | ||
4755 | + }); | ||
4756 | + | ||
4757 | + if (e.type === 'contextmenu') { | ||
4758 | + L.DomEvent.preventDefault(e); | ||
4759 | + } | ||
4760 | + if (e.type !== 'mousemove') { | ||
4761 | + L.DomEvent.stopPropagation(e); | ||
4762 | + } | ||
4763 | + } | ||
4764 | +}); | ||
4765 | + | ||
4766 | +L.Map.include({ | ||
4767 | + _initPathRoot: function () { | ||
4768 | + if (!this._pathRoot) { | ||
4769 | + this._pathRoot = L.Path.prototype._createElement('svg'); | ||
4770 | + this._panes.overlayPane.appendChild(this._pathRoot); | ||
4771 | + | ||
4772 | + if (this.options.zoomAnimation && L.Browser.any3d) { | ||
4773 | + L.DomUtil.addClass(this._pathRoot, 'leaflet-zoom-animated'); | ||
4774 | + | ||
4775 | + this.on({ | ||
4776 | + 'zoomanim': this._animatePathZoom, | ||
4777 | + 'zoomend': this._endPathZoom | ||
4778 | + }); | ||
4779 | + } else { | ||
4780 | + L.DomUtil.addClass(this._pathRoot, 'leaflet-zoom-hide'); | ||
4781 | + } | ||
4782 | + | ||
4783 | + this.on('moveend', this._updateSvgViewport); | ||
4784 | + this._updateSvgViewport(); | ||
4785 | + } | ||
4786 | + }, | ||
4787 | + | ||
4788 | + _animatePathZoom: function (e) { | ||
4789 | + var scale = this.getZoomScale(e.zoom), | ||
4790 | + offset = this._getCenterOffset(e.center)._multiplyBy(-scale)._add(this._pathViewport.min); | ||
4791 | + | ||
4792 | + this._pathRoot.style[L.DomUtil.TRANSFORM] = | ||
4793 | + L.DomUtil.getTranslateString(offset) + ' scale(' + scale + ') '; | ||
4794 | + | ||
4795 | + this._pathZooming = true; | ||
4796 | + }, | ||
4797 | + | ||
4798 | + _endPathZoom: function () { | ||
4799 | + this._pathZooming = false; | ||
4800 | + }, | ||
4801 | + | ||
4802 | + _updateSvgViewport: function () { | ||
4803 | + | ||
4804 | + if (this._pathZooming) { | ||
4805 | + // Do not update SVGs while a zoom animation is going on otherwise the animation will break. | ||
4806 | + // When the zoom animation ends we will be updated again anyway | ||
4807 | + // This fixes the case where you do a momentum move and zoom while the move is still ongoing. | ||
4808 | + return; | ||
4809 | + } | ||
4810 | + | ||
4811 | + this._updatePathViewport(); | ||
4812 | + | ||
4813 | + var vp = this._pathViewport, | ||
4814 | + min = vp.min, | ||
4815 | + max = vp.max, | ||
4816 | + width = max.x - min.x, | ||
4817 | + height = max.y - min.y, | ||
4818 | + root = this._pathRoot, | ||
4819 | + pane = this._panes.overlayPane; | ||
4820 | + | ||
4821 | + // Hack to make flicker on drag end on mobile webkit less irritating | ||
4822 | + if (L.Browser.mobileWebkit) { | ||
4823 | + pane.removeChild(root); | ||
4824 | + } | ||
4825 | + | ||
4826 | + L.DomUtil.setPosition(root, min); | ||
4827 | + root.setAttribute('width', width); | ||
4828 | + root.setAttribute('height', height); | ||
4829 | + root.setAttribute('viewBox', [min.x, min.y, width, height].join(' ')); | ||
4830 | + | ||
4831 | + if (L.Browser.mobileWebkit) { | ||
4832 | + pane.appendChild(root); | ||
4833 | + } | ||
4834 | + } | ||
4835 | +}); | ||
4836 | + | ||
4837 | + | ||
4838 | +/* | ||
4839 | + * Popup extension to L.Path (polylines, polygons, circles), adding popup-related methods. | ||
4840 | + */ | ||
4841 | + | ||
4842 | +L.Path.include({ | ||
4843 | + | ||
4844 | + bindPopup: function (content, options) { | ||
4845 | + | ||
4846 | + if (content instanceof L.Popup) { | ||
4847 | + this._popup = content; | ||
4848 | + } else { | ||
4849 | + if (!this._popup || options) { | ||
4850 | + this._popup = new L.Popup(options, this); | ||
4851 | + } | ||
4852 | + this._popup.setContent(content); | ||
4853 | + } | ||
4854 | + | ||
4855 | + if (!this._popupHandlersAdded) { | ||
4856 | + this | ||
4857 | + .on('click', this._openPopup, this) | ||
4858 | + .on('remove', this.closePopup, this); | ||
4859 | + | ||
4860 | + this._popupHandlersAdded = true; | ||
4861 | + } | ||
4862 | + | ||
4863 | + return this; | ||
4864 | + }, | ||
4865 | + | ||
4866 | + unbindPopup: function () { | ||
4867 | + if (this._popup) { | ||
4868 | + this._popup = null; | ||
4869 | + this | ||
4870 | + .off('click', this._openPopup) | ||
4871 | + .off('remove', this.closePopup); | ||
4872 | + | ||
4873 | + this._popupHandlersAdded = false; | ||
4874 | + } | ||
4875 | + return this; | ||
4876 | + }, | ||
4877 | + | ||
4878 | + openPopup: function (latlng) { | ||
4879 | + | ||
4880 | + if (this._popup) { | ||
4881 | + // open the popup from one of the path's points if not specified | ||
4882 | + latlng = latlng || this._latlng || | ||
4883 | + this._latlngs[Math.floor(this._latlngs.length / 2)]; | ||
4884 | + | ||
4885 | + this._openPopup({latlng: latlng}); | ||
4886 | + } | ||
4887 | + | ||
4888 | + return this; | ||
4889 | + }, | ||
4890 | + | ||
4891 | + closePopup: function () { | ||
4892 | + if (this._popup) { | ||
4893 | + this._popup._close(); | ||
4894 | + } | ||
4895 | + return this; | ||
4896 | + }, | ||
4897 | + | ||
4898 | + _openPopup: function (e) { | ||
4899 | + this._popup.setLatLng(e.latlng); | ||
4900 | + this._map.openPopup(this._popup); | ||
4901 | + } | ||
4902 | +}); | ||
4903 | + | ||
4904 | + | ||
4905 | +/* | ||
4906 | + * Vector rendering for IE6-8 through VML. | ||
4907 | + * Thanks to Dmitry Baranovsky and his Raphael library for inspiration! | ||
4908 | + */ | ||
4909 | + | ||
4910 | +L.Browser.vml = !L.Browser.svg && (function () { | ||
4911 | + try { | ||
4912 | + var div = document.createElement('div'); | ||
4913 | + div.innerHTML = '<v:shape adj="1"/>'; | ||
4914 | + | ||
4915 | + var shape = div.firstChild; | ||
4916 | + shape.style.behavior = 'url(#default#VML)'; | ||
4917 | + | ||
4918 | + return shape && (typeof shape.adj === 'object'); | ||
4919 | + | ||
4920 | + } catch (e) { | ||
4921 | + return false; | ||
4922 | + } | ||
4923 | +}()); | ||
4924 | + | ||
4925 | +L.Path = L.Browser.svg || !L.Browser.vml ? L.Path : L.Path.extend({ | ||
4926 | + statics: { | ||
4927 | + VML: true, | ||
4928 | + CLIP_PADDING: 0.02 | ||
4929 | + }, | ||
4930 | + | ||
4931 | + _createElement: (function () { | ||
4932 | + try { | ||
4933 | + document.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml'); | ||
4934 | + return function (name) { | ||
4935 | + return document.createElement('<lvml:' + name + ' class="lvml">'); | ||
4936 | + }; | ||
4937 | + } catch (e) { | ||
4938 | + return function (name) { | ||
4939 | + return document.createElement( | ||
4940 | + '<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">'); | ||
4941 | + }; | ||
4942 | + } | ||
4943 | + }()), | ||
4944 | + | ||
4945 | + _initPath: function () { | ||
4946 | + var container = this._container = this._createElement('shape'); | ||
4947 | + | ||
4948 | + L.DomUtil.addClass(container, 'leaflet-vml-shape' + | ||
4949 | + (this.options.className ? ' ' + this.options.className : '')); | ||
4950 | + | ||
4951 | + if (this.options.clickable) { | ||
4952 | + L.DomUtil.addClass(container, 'leaflet-clickable'); | ||
4953 | + } | ||
4954 | + | ||
4955 | + container.coordsize = '1 1'; | ||
4956 | + | ||
4957 | + this._path = this._createElement('path'); | ||
4958 | + container.appendChild(this._path); | ||
4959 | + | ||
4960 | + this._map._pathRoot.appendChild(container); | ||
4961 | + }, | ||
4962 | + | ||
4963 | + _initStyle: function () { | ||
4964 | + this._updateStyle(); | ||
4965 | + }, | ||
4966 | + | ||
4967 | + _updateStyle: function () { | ||
4968 | + var stroke = this._stroke, | ||
4969 | + fill = this._fill, | ||
4970 | + options = this.options, | ||
4971 | + container = this._container; | ||
4972 | + | ||
4973 | + container.stroked = options.stroke; | ||
4974 | + container.filled = options.fill; | ||
4975 | + | ||
4976 | + if (options.stroke) { | ||
4977 | + if (!stroke) { | ||
4978 | + stroke = this._stroke = this._createElement('stroke'); | ||
4979 | + stroke.endcap = 'round'; | ||
4980 | + container.appendChild(stroke); | ||
4981 | + } | ||
4982 | + stroke.weight = options.weight + 'px'; | ||
4983 | + stroke.color = options.color; | ||
4984 | + stroke.opacity = options.opacity; | ||
4985 | + | ||
4986 | + if (options.dashArray) { | ||
4987 | + stroke.dashStyle = L.Util.isArray(options.dashArray) ? | ||
4988 | + options.dashArray.join(' ') : | ||
4989 | + options.dashArray.replace(/( *, *)/g, ' '); | ||
4990 | + } else { | ||
4991 | + stroke.dashStyle = ''; | ||
4992 | + } | ||
4993 | + if (options.lineCap) { | ||
4994 | + stroke.endcap = options.lineCap.replace('butt', 'flat'); | ||
4995 | + } | ||
4996 | + if (options.lineJoin) { | ||
4997 | + stroke.joinstyle = options.lineJoin; | ||
4998 | + } | ||
4999 | + | ||
5000 | + } else if (stroke) { | ||
5001 | + container.removeChild(stroke); | ||
5002 | + this._stroke = null; | ||
5003 | + } | ||
5004 | + | ||
5005 | + if (options.fill) { | ||
5006 | + if (!fill) { | ||
5007 | + fill = this._fill = this._createElement('fill'); | ||
5008 | + container.appendChild(fill); | ||
5009 | + } | ||
5010 | + fill.color = options.fillColor || options.color; | ||
5011 | + fill.opacity = options.fillOpacity; | ||
5012 | + | ||
5013 | + } else if (fill) { | ||
5014 | + container.removeChild(fill); | ||
5015 | + this._fill = null; | ||
5016 | + } | ||
5017 | + }, | ||
5018 | + | ||
5019 | + _updatePath: function () { | ||
5020 | + var style = this._container.style; | ||
5021 | + | ||
5022 | + style.display = 'none'; | ||
5023 | + this._path.v = this.getPathString() + ' '; // the space fixes IE empty path string bug | ||
5024 | + style.display = ''; | ||
5025 | + } | ||
5026 | +}); | ||
5027 | + | ||
5028 | +L.Map.include(L.Browser.svg || !L.Browser.vml ? {} : { | ||
5029 | + _initPathRoot: function () { | ||
5030 | + if (this._pathRoot) { return; } | ||
5031 | + | ||
5032 | + var root = this._pathRoot = document.createElement('div'); | ||
5033 | + root.className = 'leaflet-vml-container'; | ||
5034 | + this._panes.overlayPane.appendChild(root); | ||
5035 | + | ||
5036 | + this.on('moveend', this._updatePathViewport); | ||
5037 | + this._updatePathViewport(); | ||
5038 | + } | ||
5039 | +}); | ||
5040 | + | ||
5041 | + | ||
5042 | +/* | ||
5043 | + * Vector rendering for all browsers that support canvas. | ||
5044 | + */ | ||
5045 | + | ||
5046 | +L.Browser.canvas = (function () { | ||
5047 | + return !!document.createElement('canvas').getContext; | ||
5048 | +}()); | ||
5049 | + | ||
5050 | +L.Path = (L.Path.SVG && !window.L_PREFER_CANVAS) || !L.Browser.canvas ? L.Path : L.Path.extend({ | ||
5051 | + statics: { | ||
5052 | + //CLIP_PADDING: 0.02, // not sure if there's a need to set it to a small value | ||
5053 | + CANVAS: true, | ||
5054 | + SVG: false | ||
5055 | + }, | ||
5056 | + | ||
5057 | + redraw: function () { | ||
5058 | + if (this._map) { | ||
5059 | + this.projectLatlngs(); | ||
5060 | + this._requestUpdate(); | ||
5061 | + } | ||
5062 | + return this; | ||
5063 | + }, | ||
5064 | + | ||
5065 | + setStyle: function (style) { | ||
5066 | + L.setOptions(this, style); | ||
5067 | + | ||
5068 | + if (this._map) { | ||
5069 | + this._updateStyle(); | ||
5070 | + this._requestUpdate(); | ||
5071 | + } | ||
5072 | + return this; | ||
5073 | + }, | ||
5074 | + | ||
5075 | + onRemove: function (map) { | ||
5076 | + map | ||
5077 | + .off('viewreset', this.projectLatlngs, this) | ||
5078 | + .off('moveend', this._updatePath, this); | ||
5079 | + | ||
5080 | + if (this.options.clickable) { | ||
5081 | + this._map.off('click', this._onClick, this); | ||
5082 | + this._map.off('mousemove', this._onMouseMove, this); | ||
5083 | + } | ||
5084 | + | ||
5085 | + this._requestUpdate(); | ||
5086 | + | ||
5087 | + this.fire('remove'); | ||
5088 | + this._map = null; | ||
5089 | + }, | ||
5090 | + | ||
5091 | + _requestUpdate: function () { | ||
5092 | + if (this._map && !L.Path._updateRequest) { | ||
5093 | + L.Path._updateRequest = L.Util.requestAnimFrame(this._fireMapMoveEnd, this._map); | ||
5094 | + } | ||
5095 | + }, | ||
5096 | + | ||
5097 | + _fireMapMoveEnd: function () { | ||
5098 | + L.Path._updateRequest = null; | ||
5099 | + this.fire('moveend'); | ||
5100 | + }, | ||
5101 | + | ||
5102 | + _initElements: function () { | ||
5103 | + this._map._initPathRoot(); | ||
5104 | + this._ctx = this._map._canvasCtx; | ||
5105 | + }, | ||
5106 | + | ||
5107 | + _updateStyle: function () { | ||
5108 | + var options = this.options; | ||
5109 | + | ||
5110 | + if (options.stroke) { | ||
5111 | + this._ctx.lineWidth = options.weight; | ||
5112 | + this._ctx.strokeStyle = options.color; | ||
5113 | + } | ||
5114 | + if (options.fill) { | ||
5115 | + this._ctx.fillStyle = options.fillColor || options.color; | ||
5116 | + } | ||
5117 | + }, | ||
5118 | + | ||
5119 | + _drawPath: function () { | ||
5120 | + var i, j, len, len2, point, drawMethod; | ||
5121 | + | ||
5122 | + this._ctx.beginPath(); | ||
5123 | + | ||
5124 | + for (i = 0, len = this._parts.length; i < len; i++) { | ||
5125 | + for (j = 0, len2 = this._parts[i].length; j < len2; j++) { | ||
5126 | + point = this._parts[i][j]; | ||
5127 | + drawMethod = (j === 0 ? 'move' : 'line') + 'To'; | ||
5128 | + | ||
5129 | + this._ctx[drawMethod](point.x, point.y); | ||
5130 | + } | ||
5131 | + // TODO refactor ugly hack | ||
5132 | + if (this instanceof L.Polygon) { | ||
5133 | + this._ctx.closePath(); | ||
5134 | + } | ||
5135 | + } | ||
5136 | + }, | ||
5137 | + | ||
5138 | + _checkIfEmpty: function () { | ||
5139 | + return !this._parts.length; | ||
5140 | + }, | ||
5141 | + | ||
5142 | + _updatePath: function () { | ||
5143 | + if (this._checkIfEmpty()) { return; } | ||
5144 | + | ||
5145 | + var ctx = this._ctx, | ||
5146 | + options = this.options; | ||
5147 | + | ||
5148 | + this._drawPath(); | ||
5149 | + ctx.save(); | ||
5150 | + this._updateStyle(); | ||
5151 | + | ||
5152 | + if (options.fill) { | ||
5153 | + ctx.globalAlpha = options.fillOpacity; | ||
5154 | + ctx.fill(); | ||
5155 | + } | ||
5156 | + | ||
5157 | + if (options.stroke) { | ||
5158 | + ctx.globalAlpha = options.opacity; | ||
5159 | + ctx.stroke(); | ||
5160 | + } | ||
5161 | + | ||
5162 | + ctx.restore(); | ||
5163 | + | ||
5164 | + // TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature | ||
5165 | + }, | ||
5166 | + | ||
5167 | + _initEvents: function () { | ||
5168 | + if (this.options.clickable) { | ||
5169 | + // TODO dblclick | ||
5170 | + this._map.on('mousemove', this._onMouseMove, this); | ||
5171 | + this._map.on('click', this._onClick, this); | ||
5172 | + } | ||
5173 | + }, | ||
5174 | + | ||
5175 | + _onClick: function (e) { | ||
5176 | + if (this._containsPoint(e.layerPoint)) { | ||
5177 | + this.fire('click', e); | ||
5178 | + } | ||
5179 | + }, | ||
5180 | + | ||
5181 | + _onMouseMove: function (e) { | ||
5182 | + if (!this._map || this._map._animatingZoom) { return; } | ||
5183 | + | ||
5184 | + // TODO don't do on each move | ||
5185 | + if (this._containsPoint(e.layerPoint)) { | ||
5186 | + this._ctx.canvas.style.cursor = 'pointer'; | ||
5187 | + this._mouseInside = true; | ||
5188 | + this.fire('mouseover', e); | ||
5189 | + | ||
5190 | + } else if (this._mouseInside) { | ||
5191 | + this._ctx.canvas.style.cursor = ''; | ||
5192 | + this._mouseInside = false; | ||
5193 | + this.fire('mouseout', e); | ||
5194 | + } | ||
5195 | + } | ||
5196 | +}); | ||
5197 | + | ||
5198 | +L.Map.include((L.Path.SVG && !window.L_PREFER_CANVAS) || !L.Browser.canvas ? {} : { | ||
5199 | + _initPathRoot: function () { | ||
5200 | + var root = this._pathRoot, | ||
5201 | + ctx; | ||
5202 | + | ||
5203 | + if (!root) { | ||
5204 | + root = this._pathRoot = document.createElement('canvas'); | ||
5205 | + root.style.position = 'absolute'; | ||
5206 | + ctx = this._canvasCtx = root.getContext('2d'); | ||
5207 | + | ||
5208 | + ctx.lineCap = 'round'; | ||
5209 | + ctx.lineJoin = 'round'; | ||
5210 | + | ||
5211 | + this._panes.overlayPane.appendChild(root); | ||
5212 | + | ||
5213 | + if (this.options.zoomAnimation) { | ||
5214 | + this._pathRoot.className = 'leaflet-zoom-animated'; | ||
5215 | + this.on('zoomanim', this._animatePathZoom); | ||
5216 | + this.on('zoomend', this._endPathZoom); | ||
5217 | + } | ||
5218 | + this.on('moveend', this._updateCanvasViewport); | ||
5219 | + this._updateCanvasViewport(); | ||
5220 | + } | ||
5221 | + }, | ||
5222 | + | ||
5223 | + _updateCanvasViewport: function () { | ||
5224 | + // don't redraw while zooming. See _updateSvgViewport for more details | ||
5225 | + if (this._pathZooming) { return; } | ||
5226 | + this._updatePathViewport(); | ||
5227 | + | ||
5228 | + var vp = this._pathViewport, | ||
5229 | + min = vp.min, | ||
5230 | + size = vp.max.subtract(min), | ||
5231 | + root = this._pathRoot; | ||
5232 | + | ||
5233 | + //TODO check if this works properly on mobile webkit | ||
5234 | + L.DomUtil.setPosition(root, min); | ||
5235 | + root.width = size.x; | ||
5236 | + root.height = size.y; | ||
5237 | + root.getContext('2d').translate(-min.x, -min.y); | ||
5238 | + } | ||
5239 | +}); | ||
5240 | + | ||
5241 | + | ||
5242 | +/* | ||
5243 | + * L.LineUtil contains different utility functions for line segments | ||
5244 | + * and polylines (clipping, simplification, distances, etc.) | ||
5245 | + */ | ||
5246 | + | ||
5247 | +/*jshint bitwise:false */ // allow bitwise operations for this file | ||
5248 | + | ||
5249 | +L.LineUtil = { | ||
5250 | + | ||
5251 | + // Simplify polyline with vertex reduction and Douglas-Peucker simplification. | ||
5252 | + // Improves rendering performance dramatically by lessening the number of points to draw. | ||
5253 | + | ||
5254 | + simplify: function (/*Point[]*/ points, /*Number*/ tolerance) { | ||
5255 | + if (!tolerance || !points.length) { | ||
5256 | + return points.slice(); | ||
5257 | + } | ||
5258 | + | ||
5259 | + var sqTolerance = tolerance * tolerance; | ||
5260 | + | ||
5261 | + // stage 1: vertex reduction | ||
5262 | + points = this._reducePoints(points, sqTolerance); | ||
5263 | + | ||
5264 | + // stage 2: Douglas-Peucker simplification | ||
5265 | + points = this._simplifyDP(points, sqTolerance); | ||
5266 | + | ||
5267 | + return points; | ||
5268 | + }, | ||
5269 | + | ||
5270 | + // distance from a point to a segment between two points | ||
5271 | + pointToSegmentDistance: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) { | ||
5272 | + return Math.sqrt(this._sqClosestPointOnSegment(p, p1, p2, true)); | ||
5273 | + }, | ||
5274 | + | ||
5275 | + closestPointOnSegment: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) { | ||
5276 | + return this._sqClosestPointOnSegment(p, p1, p2); | ||
5277 | + }, | ||
5278 | + | ||
5279 | + // Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm | ||
5280 | + _simplifyDP: function (points, sqTolerance) { | ||
5281 | + | ||
5282 | + var len = points.length, | ||
5283 | + ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array, | ||
5284 | + markers = new ArrayConstructor(len); | ||
5285 | + | ||
5286 | + markers[0] = markers[len - 1] = 1; | ||
5287 | + | ||
5288 | + this._simplifyDPStep(points, markers, sqTolerance, 0, len - 1); | ||
5289 | + | ||
5290 | + var i, | ||
5291 | + newPoints = []; | ||
5292 | + | ||
5293 | + for (i = 0; i < len; i++) { | ||
5294 | + if (markers[i]) { | ||
5295 | + newPoints.push(points[i]); | ||
5296 | + } | ||
5297 | + } | ||
5298 | + | ||
5299 | + return newPoints; | ||
5300 | + }, | ||
5301 | + | ||
5302 | + _simplifyDPStep: function (points, markers, sqTolerance, first, last) { | ||
5303 | + | ||
5304 | + var maxSqDist = 0, | ||
5305 | + index, i, sqDist; | ||
5306 | + | ||
5307 | + for (i = first + 1; i <= last - 1; i++) { | ||
5308 | + sqDist = this._sqClosestPointOnSegment(points[i], points[first], points[last], true); | ||
5309 | + | ||
5310 | + if (sqDist > maxSqDist) { | ||
5311 | + index = i; | ||
5312 | + maxSqDist = sqDist; | ||
5313 | + } | ||
5314 | + } | ||
5315 | + | ||
5316 | + if (maxSqDist > sqTolerance) { | ||
5317 | + markers[index] = 1; | ||
5318 | + | ||
5319 | + this._simplifyDPStep(points, markers, sqTolerance, first, index); | ||
5320 | + this._simplifyDPStep(points, markers, sqTolerance, index, last); | ||
5321 | + } | ||
5322 | + }, | ||
5323 | + | ||
5324 | + // reduce points that are too close to each other to a single point | ||
5325 | + _reducePoints: function (points, sqTolerance) { | ||
5326 | + var reducedPoints = [points[0]]; | ||
5327 | + | ||
5328 | + for (var i = 1, prev = 0, len = points.length; i < len; i++) { | ||
5329 | + if (this._sqDist(points[i], points[prev]) > sqTolerance) { | ||
5330 | + reducedPoints.push(points[i]); | ||
5331 | + prev = i; | ||
5332 | + } | ||
5333 | + } | ||
5334 | + if (prev < len - 1) { | ||
5335 | + reducedPoints.push(points[len - 1]); | ||
5336 | + } | ||
5337 | + return reducedPoints; | ||
5338 | + }, | ||
5339 | + | ||
5340 | + // Cohen-Sutherland line clipping algorithm. | ||
5341 | + // Used to avoid rendering parts of a polyline that are not currently visible. | ||
5342 | + | ||
5343 | + clipSegment: function (a, b, bounds, useLastCode) { | ||
5344 | + var codeA = useLastCode ? this._lastCode : this._getBitCode(a, bounds), | ||
5345 | + codeB = this._getBitCode(b, bounds), | ||
5346 | + | ||
5347 | + codeOut, p, newCode; | ||
5348 | + | ||
5349 | + // save 2nd code to avoid calculating it on the next segment | ||
5350 | + this._lastCode = codeB; | ||
5351 | + | ||
5352 | + while (true) { | ||
5353 | + // if a,b is inside the clip window (trivial accept) | ||
5354 | + if (!(codeA | codeB)) { | ||
5355 | + return [a, b]; | ||
5356 | + // if a,b is outside the clip window (trivial reject) | ||
5357 | + } else if (codeA & codeB) { | ||
5358 | + return false; | ||
5359 | + // other cases | ||
5360 | + } else { | ||
5361 | + codeOut = codeA || codeB; | ||
5362 | + p = this._getEdgeIntersection(a, b, codeOut, bounds); | ||
5363 | + newCode = this._getBitCode(p, bounds); | ||
5364 | + | ||
5365 | + if (codeOut === codeA) { | ||
5366 | + a = p; | ||
5367 | + codeA = newCode; | ||
5368 | + } else { | ||
5369 | + b = p; | ||
5370 | + codeB = newCode; | ||
5371 | + } | ||
5372 | + } | ||
5373 | + } | ||
5374 | + }, | ||
5375 | + | ||
5376 | + _getEdgeIntersection: function (a, b, code, bounds) { | ||
5377 | + var dx = b.x - a.x, | ||
5378 | + dy = b.y - a.y, | ||
5379 | + min = bounds.min, | ||
5380 | + max = bounds.max; | ||
5381 | + | ||
5382 | + if (code & 8) { // top | ||
5383 | + return new L.Point(a.x + dx * (max.y - a.y) / dy, max.y); | ||
5384 | + } else if (code & 4) { // bottom | ||
5385 | + return new L.Point(a.x + dx * (min.y - a.y) / dy, min.y); | ||
5386 | + } else if (code & 2) { // right | ||
5387 | + return new L.Point(max.x, a.y + dy * (max.x - a.x) / dx); | ||
5388 | + } else if (code & 1) { // left | ||
5389 | + return new L.Point(min.x, a.y + dy * (min.x - a.x) / dx); | ||
5390 | + } | ||
5391 | + }, | ||
5392 | + | ||
5393 | + _getBitCode: function (/*Point*/ p, bounds) { | ||
5394 | + var code = 0; | ||
5395 | + | ||
5396 | + if (p.x < bounds.min.x) { // left | ||
5397 | + code |= 1; | ||
5398 | + } else if (p.x > bounds.max.x) { // right | ||
5399 | + code |= 2; | ||
5400 | + } | ||
5401 | + if (p.y < bounds.min.y) { // bottom | ||
5402 | + code |= 4; | ||
5403 | + } else if (p.y > bounds.max.y) { // top | ||
5404 | + code |= 8; | ||
5405 | + } | ||
5406 | + | ||
5407 | + return code; | ||
5408 | + }, | ||
5409 | + | ||
5410 | + // square distance (to avoid unnecessary Math.sqrt calls) | ||
5411 | + _sqDist: function (p1, p2) { | ||
5412 | + var dx = p2.x - p1.x, | ||
5413 | + dy = p2.y - p1.y; | ||
5414 | + return dx * dx + dy * dy; | ||
5415 | + }, | ||
5416 | + | ||
5417 | + // return closest point on segment or distance to that point | ||
5418 | + _sqClosestPointOnSegment: function (p, p1, p2, sqDist) { | ||
5419 | + var x = p1.x, | ||
5420 | + y = p1.y, | ||
5421 | + dx = p2.x - x, | ||
5422 | + dy = p2.y - y, | ||
5423 | + dot = dx * dx + dy * dy, | ||
5424 | + t; | ||
5425 | + | ||
5426 | + if (dot > 0) { | ||
5427 | + t = ((p.x - x) * dx + (p.y - y) * dy) / dot; | ||
5428 | + | ||
5429 | + if (t > 1) { | ||
5430 | + x = p2.x; | ||
5431 | + y = p2.y; | ||
5432 | + } else if (t > 0) { | ||
5433 | + x += dx * t; | ||
5434 | + y += dy * t; | ||
5435 | + } | ||
5436 | + } | ||
5437 | + | ||
5438 | + dx = p.x - x; | ||
5439 | + dy = p.y - y; | ||
5440 | + | ||
5441 | + return sqDist ? dx * dx + dy * dy : new L.Point(x, y); | ||
5442 | + } | ||
5443 | +}; | ||
5444 | + | ||
5445 | + | ||
5446 | +/* | ||
5447 | + * L.Polyline is used to display polylines on a map. | ||
5448 | + */ | ||
5449 | + | ||
5450 | +L.Polyline = L.Path.extend({ | ||
5451 | + initialize: function (latlngs, options) { | ||
5452 | + L.Path.prototype.initialize.call(this, options); | ||
5453 | + | ||
5454 | + this._latlngs = this._convertLatLngs(latlngs); | ||
5455 | + }, | ||
5456 | + | ||
5457 | + options: { | ||
5458 | + // how much to simplify the polyline on each zoom level | ||
5459 | + // more = better performance and smoother look, less = more accurate | ||
5460 | + smoothFactor: 1.0, | ||
5461 | + noClip: false | ||
5462 | + }, | ||
5463 | + | ||
5464 | + projectLatlngs: function () { | ||
5465 | + this._originalPoints = []; | ||
5466 | + | ||
5467 | + for (var i = 0, len = this._latlngs.length; i < len; i++) { | ||
5468 | + this._originalPoints[i] = this._map.latLngToLayerPoint(this._latlngs[i]); | ||
5469 | + } | ||
5470 | + }, | ||
5471 | + | ||
5472 | + getPathString: function () { | ||
5473 | + for (var i = 0, len = this._parts.length, str = ''; i < len; i++) { | ||
5474 | + str += this._getPathPartStr(this._parts[i]); | ||
5475 | + } | ||
5476 | + return str; | ||
5477 | + }, | ||
5478 | + | ||
5479 | + getLatLngs: function () { | ||
5480 | + return this._latlngs; | ||
5481 | + }, | ||
5482 | + | ||
5483 | + setLatLngs: function (latlngs) { | ||
5484 | + this._latlngs = this._convertLatLngs(latlngs); | ||
5485 | + return this.redraw(); | ||
5486 | + }, | ||
5487 | + | ||
5488 | + addLatLng: function (latlng) { | ||
5489 | + this._latlngs.push(L.latLng(latlng)); | ||
5490 | + return this.redraw(); | ||
5491 | + }, | ||
5492 | + | ||
5493 | + spliceLatLngs: function () { // (Number index, Number howMany) | ||
5494 | + var removed = [].splice.apply(this._latlngs, arguments); | ||
5495 | + this._convertLatLngs(this._latlngs, true); | ||
5496 | + this.redraw(); | ||
5497 | + return removed; | ||
5498 | + }, | ||
5499 | + | ||
5500 | + closestLayerPoint: function (p) { | ||
5501 | + var minDistance = Infinity, parts = this._parts, p1, p2, minPoint = null; | ||
5502 | + | ||
5503 | + for (var j = 0, jLen = parts.length; j < jLen; j++) { | ||
5504 | + var points = parts[j]; | ||
5505 | + for (var i = 1, len = points.length; i < len; i++) { | ||
5506 | + p1 = points[i - 1]; | ||
5507 | + p2 = points[i]; | ||
5508 | + var sqDist = L.LineUtil._sqClosestPointOnSegment(p, p1, p2, true); | ||
5509 | + if (sqDist < minDistance) { | ||
5510 | + minDistance = sqDist; | ||
5511 | + minPoint = L.LineUtil._sqClosestPointOnSegment(p, p1, p2); | ||
5512 | + } | ||
5513 | + } | ||
5514 | + } | ||
5515 | + if (minPoint) { | ||
5516 | + minPoint.distance = Math.sqrt(minDistance); | ||
5517 | + } | ||
5518 | + return minPoint; | ||
5519 | + }, | ||
5520 | + | ||
5521 | + getBounds: function () { | ||
5522 | + return new L.LatLngBounds(this.getLatLngs()); | ||
5523 | + }, | ||
5524 | + | ||
5525 | + _convertLatLngs: function (latlngs, overwrite) { | ||
5526 | + var i, len, target = overwrite ? latlngs : []; | ||
5527 | + | ||
5528 | + for (i = 0, len = latlngs.length; i < len; i++) { | ||
5529 | + if (L.Util.isArray(latlngs[i]) && typeof latlngs[i][0] !== 'number') { | ||
5530 | + return; | ||
5531 | + } | ||
5532 | + target[i] = L.latLng(latlngs[i]); | ||
5533 | + } | ||
5534 | + return target; | ||
5535 | + }, | ||
5536 | + | ||
5537 | + _initEvents: function () { | ||
5538 | + L.Path.prototype._initEvents.call(this); | ||
5539 | + }, | ||
5540 | + | ||
5541 | + _getPathPartStr: function (points) { | ||
5542 | + var round = L.Path.VML; | ||
5543 | + | ||
5544 | + for (var j = 0, len2 = points.length, str = '', p; j < len2; j++) { | ||
5545 | + p = points[j]; | ||
5546 | + if (round) { | ||
5547 | + p._round(); | ||
5548 | + } | ||
5549 | + str += (j ? 'L' : 'M') + p.x + ' ' + p.y; | ||
5550 | + } | ||
5551 | + return str; | ||
5552 | + }, | ||
5553 | + | ||
5554 | + _clipPoints: function () { | ||
5555 | + var points = this._originalPoints, | ||
5556 | + len = points.length, | ||
5557 | + i, k, segment; | ||
5558 | + | ||
5559 | + if (this.options.noClip) { | ||
5560 | + this._parts = [points]; | ||
5561 | + return; | ||
5562 | + } | ||
5563 | + | ||
5564 | + this._parts = []; | ||
5565 | + | ||
5566 | + var parts = this._parts, | ||
5567 | + vp = this._map._pathViewport, | ||
5568 | + lu = L.LineUtil; | ||
5569 | + | ||
5570 | + for (i = 0, k = 0; i < len - 1; i++) { | ||
5571 | + segment = lu.clipSegment(points[i], points[i + 1], vp, i); | ||
5572 | + if (!segment) { | ||
5573 | + continue; | ||
5574 | + } | ||
5575 | + | ||
5576 | + parts[k] = parts[k] || []; | ||
5577 | + parts[k].push(segment[0]); | ||
5578 | + | ||
5579 | + // if segment goes out of screen, or it's the last one, it's the end of the line part | ||
5580 | + if ((segment[1] !== points[i + 1]) || (i === len - 2)) { | ||
5581 | + parts[k].push(segment[1]); | ||
5582 | + k++; | ||
5583 | + } | ||
5584 | + } | ||
5585 | + }, | ||
5586 | + | ||
5587 | + // simplify each clipped part of the polyline | ||
5588 | + _simplifyPoints: function () { | ||
5589 | + var parts = this._parts, | ||
5590 | + lu = L.LineUtil; | ||
5591 | + | ||
5592 | + for (var i = 0, len = parts.length; i < len; i++) { | ||
5593 | + parts[i] = lu.simplify(parts[i], this.options.smoothFactor); | ||
5594 | + } | ||
5595 | + }, | ||
5596 | + | ||
5597 | + _updatePath: function () { | ||
5598 | + if (!this._map) { return; } | ||
5599 | + | ||
5600 | + this._clipPoints(); | ||
5601 | + this._simplifyPoints(); | ||
5602 | + | ||
5603 | + L.Path.prototype._updatePath.call(this); | ||
5604 | + } | ||
5605 | +}); | ||
5606 | + | ||
5607 | +L.polyline = function (latlngs, options) { | ||
5608 | + return new L.Polyline(latlngs, options); | ||
5609 | +}; | ||
5610 | + | ||
5611 | + | ||
5612 | +/* | ||
5613 | + * L.PolyUtil contains utility functions for polygons (clipping, etc.). | ||
5614 | + */ | ||
5615 | + | ||
5616 | +/*jshint bitwise:false */ // allow bitwise operations here | ||
5617 | + | ||
5618 | +L.PolyUtil = {}; | ||
5619 | + | ||
5620 | +/* | ||
5621 | + * Sutherland-Hodgeman polygon clipping algorithm. | ||
5622 | + * Used to avoid rendering parts of a polygon that are not currently visible. | ||
5623 | + */ | ||
5624 | +L.PolyUtil.clipPolygon = function (points, bounds) { | ||
5625 | + var clippedPoints, | ||
5626 | + edges = [1, 4, 2, 8], | ||
5627 | + i, j, k, | ||
5628 | + a, b, | ||
5629 | + len, edge, p, | ||
5630 | + lu = L.LineUtil; | ||
5631 | + | ||
5632 | + for (i = 0, len = points.length; i < len; i++) { | ||
5633 | + points[i]._code = lu._getBitCode(points[i], bounds); | ||
5634 | + } | ||
5635 | + | ||
5636 | + // for each edge (left, bottom, right, top) | ||
5637 | + for (k = 0; k < 4; k++) { | ||
5638 | + edge = edges[k]; | ||
5639 | + clippedPoints = []; | ||
5640 | + | ||
5641 | + for (i = 0, len = points.length, j = len - 1; i < len; j = i++) { | ||
5642 | + a = points[i]; | ||
5643 | + b = points[j]; | ||
5644 | + | ||
5645 | + // if a is inside the clip window | ||
5646 | + if (!(a._code & edge)) { | ||
5647 | + // if b is outside the clip window (a->b goes out of screen) | ||
5648 | + if (b._code & edge) { | ||
5649 | + p = lu._getEdgeIntersection(b, a, edge, bounds); | ||
5650 | + p._code = lu._getBitCode(p, bounds); | ||
5651 | + clippedPoints.push(p); | ||
5652 | + } | ||
5653 | + clippedPoints.push(a); | ||
5654 | + | ||
5655 | + // else if b is inside the clip window (a->b enters the screen) | ||
5656 | + } else if (!(b._code & edge)) { | ||
5657 | + p = lu._getEdgeIntersection(b, a, edge, bounds); | ||
5658 | + p._code = lu._getBitCode(p, bounds); | ||
5659 | + clippedPoints.push(p); | ||
5660 | + } | ||
5661 | + } | ||
5662 | + points = clippedPoints; | ||
5663 | + } | ||
5664 | + | ||
5665 | + return points; | ||
5666 | +}; | ||
5667 | + | ||
5668 | + | ||
5669 | +/* | ||
5670 | + * L.Polygon is used to display polygons on a map. | ||
5671 | + */ | ||
5672 | + | ||
5673 | +L.Polygon = L.Polyline.extend({ | ||
5674 | + options: { | ||
5675 | + fill: true | ||
5676 | + }, | ||
5677 | + | ||
5678 | + initialize: function (latlngs, options) { | ||
5679 | + L.Polyline.prototype.initialize.call(this, latlngs, options); | ||
5680 | + this._initWithHoles(latlngs); | ||
5681 | + }, | ||
5682 | + | ||
5683 | + _initWithHoles: function (latlngs) { | ||
5684 | + var i, len, hole; | ||
5685 | + if (latlngs && L.Util.isArray(latlngs[0]) && (typeof latlngs[0][0] !== 'number')) { | ||
5686 | + this._latlngs = this._convertLatLngs(latlngs[0]); | ||
5687 | + this._holes = latlngs.slice(1); | ||
5688 | + | ||
5689 | + for (i = 0, len = this._holes.length; i < len; i++) { | ||
5690 | + hole = this._holes[i] = this._convertLatLngs(this._holes[i]); | ||
5691 | + if (hole[0].equals(hole[hole.length - 1])) { | ||
5692 | + hole.pop(); | ||
5693 | + } | ||
5694 | + } | ||
5695 | + } | ||
5696 | + | ||
5697 | + // filter out last point if its equal to the first one | ||
5698 | + latlngs = this._latlngs; | ||
5699 | + | ||
5700 | + if (latlngs.length >= 2 && latlngs[0].equals(latlngs[latlngs.length - 1])) { | ||
5701 | + latlngs.pop(); | ||
5702 | + } | ||
5703 | + }, | ||
5704 | + | ||
5705 | + projectLatlngs: function () { | ||
5706 | + L.Polyline.prototype.projectLatlngs.call(this); | ||
5707 | + | ||
5708 | + // project polygon holes points | ||
5709 | + // TODO move this logic to Polyline to get rid of duplication | ||
5710 | + this._holePoints = []; | ||
5711 | + | ||
5712 | + if (!this._holes) { return; } | ||
5713 | + | ||
5714 | + var i, j, len, len2; | ||
5715 | + | ||
5716 | + for (i = 0, len = this._holes.length; i < len; i++) { | ||
5717 | + this._holePoints[i] = []; | ||
5718 | + | ||
5719 | + for (j = 0, len2 = this._holes[i].length; j < len2; j++) { | ||
5720 | + this._holePoints[i][j] = this._map.latLngToLayerPoint(this._holes[i][j]); | ||
5721 | + } | ||
5722 | + } | ||
5723 | + }, | ||
5724 | + | ||
5725 | + setLatLngs: function (latlngs) { | ||
5726 | + if (latlngs && L.Util.isArray(latlngs[0]) && (typeof latlngs[0][0] !== 'number')) { | ||
5727 | + this._initWithHoles(latlngs); | ||
5728 | + return this.redraw(); | ||
5729 | + } else { | ||
5730 | + return L.Polyline.prototype.setLatLngs.call(this, latlngs); | ||
5731 | + } | ||
5732 | + }, | ||
5733 | + | ||
5734 | + _clipPoints: function () { | ||
5735 | + var points = this._originalPoints, | ||
5736 | + newParts = []; | ||
5737 | + | ||
5738 | + this._parts = [points].concat(this._holePoints); | ||
5739 | + | ||
5740 | + if (this.options.noClip) { return; } | ||
5741 | + | ||
5742 | + for (var i = 0, len = this._parts.length; i < len; i++) { | ||
5743 | + var clipped = L.PolyUtil.clipPolygon(this._parts[i], this._map._pathViewport); | ||
5744 | + if (clipped.length) { | ||
5745 | + newParts.push(clipped); | ||
5746 | + } | ||
5747 | + } | ||
5748 | + | ||
5749 | + this._parts = newParts; | ||
5750 | + }, | ||
5751 | + | ||
5752 | + _getPathPartStr: function (points) { | ||
5753 | + var str = L.Polyline.prototype._getPathPartStr.call(this, points); | ||
5754 | + return str + (L.Browser.svg ? 'z' : 'x'); | ||
5755 | + } | ||
5756 | +}); | ||
5757 | + | ||
5758 | +L.polygon = function (latlngs, options) { | ||
5759 | + return new L.Polygon(latlngs, options); | ||
5760 | +}; | ||
5761 | + | ||
5762 | + | ||
5763 | +/* | ||
5764 | + * Contains L.MultiPolyline and L.MultiPolygon layers. | ||
5765 | + */ | ||
5766 | + | ||
5767 | +(function () { | ||
5768 | + function createMulti(Klass) { | ||
5769 | + | ||
5770 | + return L.FeatureGroup.extend({ | ||
5771 | + | ||
5772 | + initialize: function (latlngs, options) { | ||
5773 | + this._layers = {}; | ||
5774 | + this._options = options; | ||
5775 | + this.setLatLngs(latlngs); | ||
5776 | + }, | ||
5777 | + | ||
5778 | + setLatLngs: function (latlngs) { | ||
5779 | + var i = 0, | ||
5780 | + len = latlngs.length; | ||
5781 | + | ||
5782 | + this.eachLayer(function (layer) { | ||
5783 | + if (i < len) { | ||
5784 | + layer.setLatLngs(latlngs[i++]); | ||
5785 | + } else { | ||
5786 | + this.removeLayer(layer); | ||
5787 | + } | ||
5788 | + }, this); | ||
5789 | + | ||
5790 | + while (i < len) { | ||
5791 | + this.addLayer(new Klass(latlngs[i++], this._options)); | ||
5792 | + } | ||
5793 | + | ||
5794 | + return this; | ||
5795 | + }, | ||
5796 | + | ||
5797 | + getLatLngs: function () { | ||
5798 | + var latlngs = []; | ||
5799 | + | ||
5800 | + this.eachLayer(function (layer) { | ||
5801 | + latlngs.push(layer.getLatLngs()); | ||
5802 | + }); | ||
5803 | + | ||
5804 | + return latlngs; | ||
5805 | + } | ||
5806 | + }); | ||
5807 | + } | ||
5808 | + | ||
5809 | + L.MultiPolyline = createMulti(L.Polyline); | ||
5810 | + L.MultiPolygon = createMulti(L.Polygon); | ||
5811 | + | ||
5812 | + L.multiPolyline = function (latlngs, options) { | ||
5813 | + return new L.MultiPolyline(latlngs, options); | ||
5814 | + }; | ||
5815 | + | ||
5816 | + L.multiPolygon = function (latlngs, options) { | ||
5817 | + return new L.MultiPolygon(latlngs, options); | ||
5818 | + }; | ||
5819 | +}()); | ||
5820 | + | ||
5821 | + | ||
5822 | +/* | ||
5823 | + * L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds object. | ||
5824 | + */ | ||
5825 | + | ||
5826 | +L.Rectangle = L.Polygon.extend({ | ||
5827 | + initialize: function (latLngBounds, options) { | ||
5828 | + L.Polygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options); | ||
5829 | + }, | ||
5830 | + | ||
5831 | + setBounds: function (latLngBounds) { | ||
5832 | + this.setLatLngs(this._boundsToLatLngs(latLngBounds)); | ||
5833 | + }, | ||
5834 | + | ||
5835 | + _boundsToLatLngs: function (latLngBounds) { | ||
5836 | + latLngBounds = L.latLngBounds(latLngBounds); | ||
5837 | + return [ | ||
5838 | + latLngBounds.getSouthWest(), | ||
5839 | + latLngBounds.getNorthWest(), | ||
5840 | + latLngBounds.getNorthEast(), | ||
5841 | + latLngBounds.getSouthEast() | ||
5842 | + ]; | ||
5843 | + } | ||
5844 | +}); | ||
5845 | + | ||
5846 | +L.rectangle = function (latLngBounds, options) { | ||
5847 | + return new L.Rectangle(latLngBounds, options); | ||
5848 | +}; | ||
5849 | + | ||
5850 | + | ||
5851 | +/* | ||
5852 | + * L.Circle is a circle overlay (with a certain radius in meters). | ||
5853 | + */ | ||
5854 | + | ||
5855 | +L.Circle = L.Path.extend({ | ||
5856 | + initialize: function (latlng, radius, options) { | ||
5857 | + L.Path.prototype.initialize.call(this, options); | ||
5858 | + | ||
5859 | + this._latlng = L.latLng(latlng); | ||
5860 | + this._mRadius = radius; | ||
5861 | + }, | ||
5862 | + | ||
5863 | + options: { | ||
5864 | + fill: true | ||
5865 | + }, | ||
5866 | + | ||
5867 | + setLatLng: function (latlng) { | ||
5868 | + this._latlng = L.latLng(latlng); | ||
5869 | + return this.redraw(); | ||
5870 | + }, | ||
5871 | + | ||
5872 | + setRadius: function (radius) { | ||
5873 | + this._mRadius = radius; | ||
5874 | + return this.redraw(); | ||
5875 | + }, | ||
5876 | + | ||
5877 | + projectLatlngs: function () { | ||
5878 | + var lngRadius = this._getLngRadius(), | ||
5879 | + latlng = this._latlng, | ||
5880 | + pointLeft = this._map.latLngToLayerPoint([latlng.lat, latlng.lng - lngRadius]); | ||
5881 | + | ||
5882 | + this._point = this._map.latLngToLayerPoint(latlng); | ||
5883 | + this._radius = Math.max(this._point.x - pointLeft.x, 1); | ||
5884 | + }, | ||
5885 | + | ||
5886 | + getBounds: function () { | ||
5887 | + var lngRadius = this._getLngRadius(), | ||
5888 | + latRadius = (this._mRadius / 40075017) * 360, | ||
5889 | + latlng = this._latlng; | ||
5890 | + | ||
5891 | + return new L.LatLngBounds( | ||
5892 | + [latlng.lat - latRadius, latlng.lng - lngRadius], | ||
5893 | + [latlng.lat + latRadius, latlng.lng + lngRadius]); | ||
5894 | + }, | ||
5895 | + | ||
5896 | + getLatLng: function () { | ||
5897 | + return this._latlng; | ||
5898 | + }, | ||
5899 | + | ||
5900 | + getPathString: function () { | ||
5901 | + var p = this._point, | ||
5902 | + r = this._radius; | ||
5903 | + | ||
5904 | + if (this._checkIfEmpty()) { | ||
5905 | + return ''; | ||
5906 | + } | ||
5907 | + | ||
5908 | + if (L.Browser.svg) { | ||
5909 | + return 'M' + p.x + ',' + (p.y - r) + | ||
5910 | + 'A' + r + ',' + r + ',0,1,1,' + | ||
5911 | + (p.x - 0.1) + ',' + (p.y - r) + ' z'; | ||
5912 | + } else { | ||
5913 | + p._round(); | ||
5914 | + r = Math.round(r); | ||
5915 | + return 'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r + ' 0,' + (65535 * 360); | ||
5916 | + } | ||
5917 | + }, | ||
5918 | + | ||
5919 | + getRadius: function () { | ||
5920 | + return this._mRadius; | ||
5921 | + }, | ||
5922 | + | ||
5923 | + // TODO Earth hardcoded, move into projection code! | ||
5924 | + | ||
5925 | + _getLatRadius: function () { | ||
5926 | + return (this._mRadius / 40075017) * 360; | ||
5927 | + }, | ||
5928 | + | ||
5929 | + _getLngRadius: function () { | ||
5930 | + return this._getLatRadius() / Math.cos(L.LatLng.DEG_TO_RAD * this._latlng.lat); | ||
5931 | + }, | ||
5932 | + | ||
5933 | + _checkIfEmpty: function () { | ||
5934 | + if (!this._map) { | ||
5935 | + return false; | ||
5936 | + } | ||
5937 | + var vp = this._map._pathViewport, | ||
5938 | + r = this._radius, | ||
5939 | + p = this._point; | ||
5940 | + | ||
5941 | + return p.x - r > vp.max.x || p.y - r > vp.max.y || | ||
5942 | + p.x + r < vp.min.x || p.y + r < vp.min.y; | ||
5943 | + } | ||
5944 | +}); | ||
5945 | + | ||
5946 | +L.circle = function (latlng, radius, options) { | ||
5947 | + return new L.Circle(latlng, radius, options); | ||
5948 | +}; | ||
5949 | + | ||
5950 | + | ||
5951 | +/* | ||
5952 | + * L.CircleMarker is a circle overlay with a permanent pixel radius. | ||
5953 | + */ | ||
5954 | + | ||
5955 | +L.CircleMarker = L.Circle.extend({ | ||
5956 | + options: { | ||
5957 | + radius: 10, | ||
5958 | + weight: 2 | ||
5959 | + }, | ||
5960 | + | ||
5961 | + initialize: function (latlng, options) { | ||
5962 | + L.Circle.prototype.initialize.call(this, latlng, null, options); | ||
5963 | + this._radius = this.options.radius; | ||
5964 | + }, | ||
5965 | + | ||
5966 | + projectLatlngs: function () { | ||
5967 | + this._point = this._map.latLngToLayerPoint(this._latlng); | ||
5968 | + }, | ||
5969 | + | ||
5970 | + _updateStyle : function () { | ||
5971 | + L.Circle.prototype._updateStyle.call(this); | ||
5972 | + this.setRadius(this.options.radius); | ||
5973 | + }, | ||
5974 | + | ||
5975 | + setLatLng: function (latlng) { | ||
5976 | + L.Circle.prototype.setLatLng.call(this, latlng); | ||
5977 | + if (this._popup && this._popup._isOpen) { | ||
5978 | + this._popup.setLatLng(latlng); | ||
5979 | + } | ||
5980 | + return this; | ||
5981 | + }, | ||
5982 | + | ||
5983 | + setRadius: function (radius) { | ||
5984 | + this.options.radius = this._radius = radius; | ||
5985 | + return this.redraw(); | ||
5986 | + }, | ||
5987 | + | ||
5988 | + getRadius: function () { | ||
5989 | + return this._radius; | ||
5990 | + } | ||
5991 | +}); | ||
5992 | + | ||
5993 | +L.circleMarker = function (latlng, options) { | ||
5994 | + return new L.CircleMarker(latlng, options); | ||
5995 | +}; | ||
5996 | + | ||
5997 | + | ||
5998 | +/* | ||
5999 | + * Extends L.Polyline to be able to manually detect clicks on Canvas-rendered polylines. | ||
6000 | + */ | ||
6001 | + | ||
6002 | +L.Polyline.include(!L.Path.CANVAS ? {} : { | ||
6003 | + _containsPoint: function (p, closed) { | ||
6004 | + var i, j, k, len, len2, dist, part, | ||
6005 | + w = this.options.weight / 2; | ||
6006 | + | ||
6007 | + if (L.Browser.touch) { | ||
6008 | + w += 10; // polyline click tolerance on touch devices | ||
6009 | + } | ||
6010 | + | ||
6011 | + for (i = 0, len = this._parts.length; i < len; i++) { | ||
6012 | + part = this._parts[i]; | ||
6013 | + for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) { | ||
6014 | + if (!closed && (j === 0)) { | ||
6015 | + continue; | ||
6016 | + } | ||
6017 | + | ||
6018 | + dist = L.LineUtil.pointToSegmentDistance(p, part[k], part[j]); | ||
6019 | + | ||
6020 | + if (dist <= w) { | ||
6021 | + return true; | ||
6022 | + } | ||
6023 | + } | ||
6024 | + } | ||
6025 | + return false; | ||
6026 | + } | ||
6027 | +}); | ||
6028 | + | ||
6029 | + | ||
6030 | +/* | ||
6031 | + * Extends L.Polygon to be able to manually detect clicks on Canvas-rendered polygons. | ||
6032 | + */ | ||
6033 | + | ||
6034 | +L.Polygon.include(!L.Path.CANVAS ? {} : { | ||
6035 | + _containsPoint: function (p) { | ||
6036 | + var inside = false, | ||
6037 | + part, p1, p2, | ||
6038 | + i, j, k, | ||
6039 | + len, len2; | ||
6040 | + | ||
6041 | + // TODO optimization: check if within bounds first | ||
6042 | + | ||
6043 | + if (L.Polyline.prototype._containsPoint.call(this, p, true)) { | ||
6044 | + // click on polygon border | ||
6045 | + return true; | ||
6046 | + } | ||
6047 | + | ||
6048 | + // ray casting algorithm for detecting if point is in polygon | ||
6049 | + | ||
6050 | + for (i = 0, len = this._parts.length; i < len; i++) { | ||
6051 | + part = this._parts[i]; | ||
6052 | + | ||
6053 | + for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) { | ||
6054 | + p1 = part[j]; | ||
6055 | + p2 = part[k]; | ||
6056 | + | ||
6057 | + if (((p1.y > p.y) !== (p2.y > p.y)) && | ||
6058 | + (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) { | ||
6059 | + inside = !inside; | ||
6060 | + } | ||
6061 | + } | ||
6062 | + } | ||
6063 | + | ||
6064 | + return inside; | ||
6065 | + } | ||
6066 | +}); | ||
6067 | + | ||
6068 | + | ||
6069 | +/* | ||
6070 | + * Extends L.Circle with Canvas-specific code. | ||
6071 | + */ | ||
6072 | + | ||
6073 | +L.Circle.include(!L.Path.CANVAS ? {} : { | ||
6074 | + _drawPath: function () { | ||
6075 | + var p = this._point; | ||
6076 | + this._ctx.beginPath(); | ||
6077 | + this._ctx.arc(p.x, p.y, this._radius, 0, Math.PI * 2, false); | ||
6078 | + }, | ||
6079 | + | ||
6080 | + _containsPoint: function (p) { | ||
6081 | + var center = this._point, | ||
6082 | + w2 = this.options.stroke ? this.options.weight / 2 : 0; | ||
6083 | + | ||
6084 | + return (p.distanceTo(center) <= this._radius + w2); | ||
6085 | + } | ||
6086 | +}); | ||
6087 | + | ||
6088 | + | ||
6089 | +/* | ||
6090 | + * CircleMarker canvas specific drawing parts. | ||
6091 | + */ | ||
6092 | + | ||
6093 | +L.CircleMarker.include(!L.Path.CANVAS ? {} : { | ||
6094 | + _updateStyle: function () { | ||
6095 | + L.Path.prototype._updateStyle.call(this); | ||
6096 | + } | ||
6097 | +}); | ||
6098 | + | ||
6099 | + | ||
6100 | +/* | ||
6101 | + * L.GeoJSON turns any GeoJSON data into a Leaflet layer. | ||
6102 | + */ | ||
6103 | + | ||
6104 | +L.GeoJSON = L.FeatureGroup.extend({ | ||
6105 | + | ||
6106 | + initialize: function (geojson, options) { | ||
6107 | + L.setOptions(this, options); | ||
6108 | + | ||
6109 | + this._layers = {}; | ||
6110 | + | ||
6111 | + if (geojson) { | ||
6112 | + this.addData(geojson); | ||
6113 | + } | ||
6114 | + }, | ||
6115 | + | ||
6116 | + addData: function (geojson) { | ||
6117 | + var features = L.Util.isArray(geojson) ? geojson : geojson.features, | ||
6118 | + i, len, feature; | ||
6119 | + | ||
6120 | + if (features) { | ||
6121 | + for (i = 0, len = features.length; i < len; i++) { | ||
6122 | + // Only add this if geometry or geometries are set and not null | ||
6123 | + feature = features[i]; | ||
6124 | + if (feature.geometries || feature.geometry || feature.features || feature.coordinates) { | ||
6125 | + this.addData(features[i]); | ||
6126 | + } | ||
6127 | + } | ||
6128 | + return this; | ||
6129 | + } | ||
6130 | + | ||
6131 | + var options = this.options; | ||
6132 | + | ||
6133 | + if (options.filter && !options.filter(geojson)) { return; } | ||
6134 | + | ||
6135 | + var layer = L.GeoJSON.geometryToLayer(geojson, options.pointToLayer, options.coordsToLatLng, options); | ||
6136 | + layer.feature = L.GeoJSON.asFeature(geojson); | ||
6137 | + | ||
6138 | + layer.defaultOptions = layer.options; | ||
6139 | + this.resetStyle(layer); | ||
6140 | + | ||
6141 | + if (options.onEachFeature) { | ||
6142 | + options.onEachFeature(geojson, layer); | ||
6143 | + } | ||
6144 | + | ||
6145 | + return this.addLayer(layer); | ||
6146 | + }, | ||
6147 | + | ||
6148 | + resetStyle: function (layer) { | ||
6149 | + var style = this.options.style; | ||
6150 | + if (style) { | ||
6151 | + // reset any custom styles | ||
6152 | + L.Util.extend(layer.options, layer.defaultOptions); | ||
6153 | + | ||
6154 | + this._setLayerStyle(layer, style); | ||
6155 | + } | ||
6156 | + }, | ||
6157 | + | ||
6158 | + setStyle: function (style) { | ||
6159 | + this.eachLayer(function (layer) { | ||
6160 | + this._setLayerStyle(layer, style); | ||
6161 | + }, this); | ||
6162 | + }, | ||
6163 | + | ||
6164 | + _setLayerStyle: function (layer, style) { | ||
6165 | + if (typeof style === 'function') { | ||
6166 | + style = style(layer.feature); | ||
6167 | + } | ||
6168 | + if (layer.setStyle) { | ||
6169 | + layer.setStyle(style); | ||
6170 | + } | ||
6171 | + } | ||
6172 | +}); | ||
6173 | + | ||
6174 | +L.extend(L.GeoJSON, { | ||
6175 | + geometryToLayer: function (geojson, pointToLayer, coordsToLatLng, vectorOptions) { | ||
6176 | + var geometry = geojson.type === 'Feature' ? geojson.geometry : geojson, | ||
6177 | + coords = geometry.coordinates, | ||
6178 | + layers = [], | ||
6179 | + latlng, latlngs, i, len; | ||
6180 | + | ||
6181 | + coordsToLatLng = coordsToLatLng || this.coordsToLatLng; | ||
6182 | + | ||
6183 | + switch (geometry.type) { | ||
6184 | + case 'Point': | ||
6185 | + latlng = coordsToLatLng(coords); | ||
6186 | + return pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng); | ||
6187 | + | ||
6188 | + case 'MultiPoint': | ||
6189 | + for (i = 0, len = coords.length; i < len; i++) { | ||
6190 | + latlng = coordsToLatLng(coords[i]); | ||
6191 | + layers.push(pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng)); | ||
6192 | + } | ||
6193 | + return new L.FeatureGroup(layers); | ||
6194 | + | ||
6195 | + case 'LineString': | ||
6196 | + latlngs = this.coordsToLatLngs(coords, 0, coordsToLatLng); | ||
6197 | + return new L.Polyline(latlngs, vectorOptions); | ||
6198 | + | ||
6199 | + case 'Polygon': | ||
6200 | + if (coords.length === 2 && !coords[1].length) { | ||
6201 | + throw new Error('Invalid GeoJSON object.'); | ||
6202 | + } | ||
6203 | + latlngs = this.coordsToLatLngs(coords, 1, coordsToLatLng); | ||
6204 | + return new L.Polygon(latlngs, vectorOptions); | ||
6205 | + | ||
6206 | + case 'MultiLineString': | ||
6207 | + latlngs = this.coordsToLatLngs(coords, 1, coordsToLatLng); | ||
6208 | + return new L.MultiPolyline(latlngs, vectorOptions); | ||
6209 | + | ||
6210 | + case 'MultiPolygon': | ||
6211 | + latlngs = this.coordsToLatLngs(coords, 2, coordsToLatLng); | ||
6212 | + return new L.MultiPolygon(latlngs, vectorOptions); | ||
6213 | + | ||
6214 | + case 'GeometryCollection': | ||
6215 | + for (i = 0, len = geometry.geometries.length; i < len; i++) { | ||
6216 | + | ||
6217 | + layers.push(this.geometryToLayer({ | ||
6218 | + geometry: geometry.geometries[i], | ||
6219 | + type: 'Feature', | ||
6220 | + properties: geojson.properties | ||
6221 | + }, pointToLayer, coordsToLatLng, vectorOptions)); | ||
6222 | + } | ||
6223 | + return new L.FeatureGroup(layers); | ||
6224 | + | ||
6225 | + default: | ||
6226 | + throw new Error('Invalid GeoJSON object.'); | ||
6227 | + } | ||
6228 | + }, | ||
6229 | + | ||
6230 | + coordsToLatLng: function (coords) { // (Array[, Boolean]) -> LatLng | ||
6231 | + return new L.LatLng(coords[1], coords[0], coords[2]); | ||
6232 | + }, | ||
6233 | + | ||
6234 | + coordsToLatLngs: function (coords, levelsDeep, coordsToLatLng) { // (Array[, Number, Function]) -> Array | ||
6235 | + var latlng, i, len, | ||
6236 | + latlngs = []; | ||
6237 | + | ||
6238 | + for (i = 0, len = coords.length; i < len; i++) { | ||
6239 | + latlng = levelsDeep ? | ||
6240 | + this.coordsToLatLngs(coords[i], levelsDeep - 1, coordsToLatLng) : | ||
6241 | + (coordsToLatLng || this.coordsToLatLng)(coords[i]); | ||
6242 | + | ||
6243 | + latlngs.push(latlng); | ||
6244 | + } | ||
6245 | + | ||
6246 | + return latlngs; | ||
6247 | + }, | ||
6248 | + | ||
6249 | + latLngToCoords: function (latlng) { | ||
6250 | + var coords = [latlng.lng, latlng.lat]; | ||
6251 | + | ||
6252 | + if (latlng.alt !== undefined) { | ||
6253 | + coords.push(latlng.alt); | ||
6254 | + } | ||
6255 | + return coords; | ||
6256 | + }, | ||
6257 | + | ||
6258 | + latLngsToCoords: function (latLngs) { | ||
6259 | + var coords = []; | ||
6260 | + | ||
6261 | + for (var i = 0, len = latLngs.length; i < len; i++) { | ||
6262 | + coords.push(L.GeoJSON.latLngToCoords(latLngs[i])); | ||
6263 | + } | ||
6264 | + | ||
6265 | + return coords; | ||
6266 | + }, | ||
6267 | + | ||
6268 | + getFeature: function (layer, newGeometry) { | ||
6269 | + return layer.feature ? L.extend({}, layer.feature, {geometry: newGeometry}) : L.GeoJSON.asFeature(newGeometry); | ||
6270 | + }, | ||
6271 | + | ||
6272 | + asFeature: function (geoJSON) { | ||
6273 | + if (geoJSON.type === 'Feature') { | ||
6274 | + return geoJSON; | ||
6275 | + } | ||
6276 | + | ||
6277 | + return { | ||
6278 | + type: 'Feature', | ||
6279 | + properties: {}, | ||
6280 | + geometry: geoJSON | ||
6281 | + }; | ||
6282 | + } | ||
6283 | +}); | ||
6284 | + | ||
6285 | +var PointToGeoJSON = { | ||
6286 | + toGeoJSON: function () { | ||
6287 | + return L.GeoJSON.getFeature(this, { | ||
6288 | + type: 'Point', | ||
6289 | + coordinates: L.GeoJSON.latLngToCoords(this.getLatLng()) | ||
6290 | + }); | ||
6291 | + } | ||
6292 | +}; | ||
6293 | + | ||
6294 | +L.Marker.include(PointToGeoJSON); | ||
6295 | +L.Circle.include(PointToGeoJSON); | ||
6296 | +L.CircleMarker.include(PointToGeoJSON); | ||
6297 | + | ||
6298 | +L.Polyline.include({ | ||
6299 | + toGeoJSON: function () { | ||
6300 | + return L.GeoJSON.getFeature(this, { | ||
6301 | + type: 'LineString', | ||
6302 | + coordinates: L.GeoJSON.latLngsToCoords(this.getLatLngs()) | ||
6303 | + }); | ||
6304 | + } | ||
6305 | +}); | ||
6306 | + | ||
6307 | +L.Polygon.include({ | ||
6308 | + toGeoJSON: function () { | ||
6309 | + var coords = [L.GeoJSON.latLngsToCoords(this.getLatLngs())], | ||
6310 | + i, len, hole; | ||
6311 | + | ||
6312 | + coords[0].push(coords[0][0]); | ||
6313 | + | ||
6314 | + if (this._holes) { | ||
6315 | + for (i = 0, len = this._holes.length; i < len; i++) { | ||
6316 | + hole = L.GeoJSON.latLngsToCoords(this._holes[i]); | ||
6317 | + hole.push(hole[0]); | ||
6318 | + coords.push(hole); | ||
6319 | + } | ||
6320 | + } | ||
6321 | + | ||
6322 | + return L.GeoJSON.getFeature(this, { | ||
6323 | + type: 'Polygon', | ||
6324 | + coordinates: coords | ||
6325 | + }); | ||
6326 | + } | ||
6327 | +}); | ||
6328 | + | ||
6329 | +(function () { | ||
6330 | + function multiToGeoJSON(type) { | ||
6331 | + return function () { | ||
6332 | + var coords = []; | ||
6333 | + | ||
6334 | + this.eachLayer(function (layer) { | ||
6335 | + coords.push(layer.toGeoJSON().geometry.coordinates); | ||
6336 | + }); | ||
6337 | + | ||
6338 | + return L.GeoJSON.getFeature(this, { | ||
6339 | + type: type, | ||
6340 | + coordinates: coords | ||
6341 | + }); | ||
6342 | + }; | ||
6343 | + } | ||
6344 | + | ||
6345 | + L.MultiPolyline.include({toGeoJSON: multiToGeoJSON('MultiLineString')}); | ||
6346 | + L.MultiPolygon.include({toGeoJSON: multiToGeoJSON('MultiPolygon')}); | ||
6347 | + | ||
6348 | + L.LayerGroup.include({ | ||
6349 | + toGeoJSON: function () { | ||
6350 | + | ||
6351 | + var geometry = this.feature && this.feature.geometry, | ||
6352 | + jsons = [], | ||
6353 | + json; | ||
6354 | + | ||
6355 | + if (geometry && geometry.type === 'MultiPoint') { | ||
6356 | + return multiToGeoJSON('MultiPoint').call(this); | ||
6357 | + } | ||
6358 | + | ||
6359 | + var isGeometryCollection = geometry && geometry.type === 'GeometryCollection'; | ||
6360 | + | ||
6361 | + this.eachLayer(function (layer) { | ||
6362 | + if (layer.toGeoJSON) { | ||
6363 | + json = layer.toGeoJSON(); | ||
6364 | + jsons.push(isGeometryCollection ? json.geometry : L.GeoJSON.asFeature(json)); | ||
6365 | + } | ||
6366 | + }); | ||
6367 | + | ||
6368 | + if (isGeometryCollection) { | ||
6369 | + return L.GeoJSON.getFeature(this, { | ||
6370 | + geometries: jsons, | ||
6371 | + type: 'GeometryCollection' | ||
6372 | + }); | ||
6373 | + } | ||
6374 | + | ||
6375 | + return { | ||
6376 | + type: 'FeatureCollection', | ||
6377 | + features: jsons | ||
6378 | + }; | ||
6379 | + } | ||
6380 | + }); | ||
6381 | +}()); | ||
6382 | + | ||
6383 | +L.geoJson = function (geojson, options) { | ||
6384 | + return new L.GeoJSON(geojson, options); | ||
6385 | +}; | ||
6386 | + | ||
6387 | + | ||
6388 | +/* | ||
6389 | + * L.DomEvent contains functions for working with DOM events. | ||
6390 | + */ | ||
6391 | + | ||
6392 | +L.DomEvent = { | ||
6393 | + /* inspired by John Resig, Dean Edwards and YUI addEvent implementations */ | ||
6394 | + addListener: function (obj, type, fn, context) { // (HTMLElement, String, Function[, Object]) | ||
6395 | + | ||
6396 | + var id = L.stamp(fn), | ||
6397 | + key = '_leaflet_' + type + id, | ||
6398 | + handler, originalHandler, newType; | ||
6399 | + | ||
6400 | + if (obj[key]) { return this; } | ||
6401 | + | ||
6402 | + handler = function (e) { | ||
6403 | + return fn.call(context || obj, e || L.DomEvent._getEvent()); | ||
6404 | + }; | ||
6405 | + | ||
6406 | + if (L.Browser.pointer && type.indexOf('touch') === 0) { | ||
6407 | + return this.addPointerListener(obj, type, handler, id); | ||
6408 | + } | ||
6409 | + if (L.Browser.touch && (type === 'dblclick') && this.addDoubleTapListener) { | ||
6410 | + this.addDoubleTapListener(obj, handler, id); | ||
6411 | + } | ||
6412 | + | ||
6413 | + if ('addEventListener' in obj) { | ||
6414 | + | ||
6415 | + if (type === 'mousewheel') { | ||
6416 | + obj.addEventListener('DOMMouseScroll', handler, false); | ||
6417 | + obj.addEventListener(type, handler, false); | ||
6418 | + | ||
6419 | + } else if ((type === 'mouseenter') || (type === 'mouseleave')) { | ||
6420 | + | ||
6421 | + originalHandler = handler; | ||
6422 | + newType = (type === 'mouseenter' ? 'mouseover' : 'mouseout'); | ||
6423 | + | ||
6424 | + handler = function (e) { | ||
6425 | + if (!L.DomEvent._checkMouse(obj, e)) { return; } | ||
6426 | + return originalHandler(e); | ||
6427 | + }; | ||
6428 | + | ||
6429 | + obj.addEventListener(newType, handler, false); | ||
6430 | + | ||
6431 | + } else if (type === 'click' && L.Browser.android) { | ||
6432 | + originalHandler = handler; | ||
6433 | + handler = function (e) { | ||
6434 | + return L.DomEvent._filterClick(e, originalHandler); | ||
6435 | + }; | ||
6436 | + | ||
6437 | + obj.addEventListener(type, handler, false); | ||
6438 | + } else { | ||
6439 | + obj.addEventListener(type, handler, false); | ||
6440 | + } | ||
6441 | + | ||
6442 | + } else if ('attachEvent' in obj) { | ||
6443 | + obj.attachEvent('on' + type, handler); | ||
6444 | + } | ||
6445 | + | ||
6446 | + obj[key] = handler; | ||
6447 | + | ||
6448 | + return this; | ||
6449 | + }, | ||
6450 | + | ||
6451 | + removeListener: function (obj, type, fn) { // (HTMLElement, String, Function) | ||
6452 | + | ||
6453 | + var id = L.stamp(fn), | ||
6454 | + key = '_leaflet_' + type + id, | ||
6455 | + handler = obj[key]; | ||
6456 | + | ||
6457 | + if (!handler) { return this; } | ||
6458 | + | ||
6459 | + if (L.Browser.pointer && type.indexOf('touch') === 0) { | ||
6460 | + this.removePointerListener(obj, type, id); | ||
6461 | + } else if (L.Browser.touch && (type === 'dblclick') && this.removeDoubleTapListener) { | ||
6462 | + this.removeDoubleTapListener(obj, id); | ||
6463 | + | ||
6464 | + } else if ('removeEventListener' in obj) { | ||
6465 | + | ||
6466 | + if (type === 'mousewheel') { | ||
6467 | + obj.removeEventListener('DOMMouseScroll', handler, false); | ||
6468 | + obj.removeEventListener(type, handler, false); | ||
6469 | + | ||
6470 | + } else if ((type === 'mouseenter') || (type === 'mouseleave')) { | ||
6471 | + obj.removeEventListener((type === 'mouseenter' ? 'mouseover' : 'mouseout'), handler, false); | ||
6472 | + } else { | ||
6473 | + obj.removeEventListener(type, handler, false); | ||
6474 | + } | ||
6475 | + } else if ('detachEvent' in obj) { | ||
6476 | + obj.detachEvent('on' + type, handler); | ||
6477 | + } | ||
6478 | + | ||
6479 | + obj[key] = null; | ||
6480 | + | ||
6481 | + return this; | ||
6482 | + }, | ||
6483 | + | ||
6484 | + stopPropagation: function (e) { | ||
6485 | + | ||
6486 | + if (e.stopPropagation) { | ||
6487 | + e.stopPropagation(); | ||
6488 | + } else { | ||
6489 | + e.cancelBubble = true; | ||
6490 | + } | ||
6491 | + L.DomEvent._skipped(e); | ||
6492 | + | ||
6493 | + return this; | ||
6494 | + }, | ||
6495 | + | ||
6496 | + disableScrollPropagation: function (el) { | ||
6497 | + var stop = L.DomEvent.stopPropagation; | ||
6498 | + | ||
6499 | + return L.DomEvent | ||
6500 | + .on(el, 'mousewheel', stop) | ||
6501 | + .on(el, 'MozMousePixelScroll', stop); | ||
6502 | + }, | ||
6503 | + | ||
6504 | + disableClickPropagation: function (el) { | ||
6505 | + var stop = L.DomEvent.stopPropagation; | ||
6506 | + | ||
6507 | + for (var i = L.Draggable.START.length - 1; i >= 0; i--) { | ||
6508 | + L.DomEvent.on(el, L.Draggable.START[i], stop); | ||
6509 | + } | ||
6510 | + | ||
6511 | + return L.DomEvent | ||
6512 | + .on(el, 'click', L.DomEvent._fakeStop) | ||
6513 | + .on(el, 'dblclick', stop); | ||
6514 | + }, | ||
6515 | + | ||
6516 | + preventDefault: function (e) { | ||
6517 | + | ||
6518 | + if (e.preventDefault) { | ||
6519 | + e.preventDefault(); | ||
6520 | + } else { | ||
6521 | + e.returnValue = false; | ||
6522 | + } | ||
6523 | + return this; | ||
6524 | + }, | ||
6525 | + | ||
6526 | + stop: function (e) { | ||
6527 | + return L.DomEvent | ||
6528 | + .preventDefault(e) | ||
6529 | + .stopPropagation(e); | ||
6530 | + }, | ||
6531 | + | ||
6532 | + getMousePosition: function (e, container) { | ||
6533 | + if (!container) { | ||
6534 | + return new L.Point(e.clientX, e.clientY); | ||
6535 | + } | ||
6536 | + | ||
6537 | + var rect = container.getBoundingClientRect(); | ||
6538 | + | ||
6539 | + return new L.Point( | ||
6540 | + e.clientX - rect.left - container.clientLeft, | ||
6541 | + e.clientY - rect.top - container.clientTop); | ||
6542 | + }, | ||
6543 | + | ||
6544 | + getWheelDelta: function (e) { | ||
6545 | + | ||
6546 | + var delta = 0; | ||
6547 | + | ||
6548 | + if (e.wheelDelta) { | ||
6549 | + delta = e.wheelDelta / 120; | ||
6550 | + } | ||
6551 | + if (e.detail) { | ||
6552 | + delta = -e.detail / 3; | ||
6553 | + } | ||
6554 | + return delta; | ||
6555 | + }, | ||
6556 | + | ||
6557 | + _skipEvents: {}, | ||
6558 | + | ||
6559 | + _fakeStop: function (e) { | ||
6560 | + // fakes stopPropagation by setting a special event flag, checked/reset with L.DomEvent._skipped(e) | ||
6561 | + L.DomEvent._skipEvents[e.type] = true; | ||
6562 | + }, | ||
6563 | + | ||
6564 | + _skipped: function (e) { | ||
6565 | + var skipped = this._skipEvents[e.type]; | ||
6566 | + // reset when checking, as it's only used in map container and propagates outside of the map | ||
6567 | + this._skipEvents[e.type] = false; | ||
6568 | + return skipped; | ||
6569 | + }, | ||
6570 | + | ||
6571 | + // check if element really left/entered the event target (for mouseenter/mouseleave) | ||
6572 | + _checkMouse: function (el, e) { | ||
6573 | + | ||
6574 | + var related = e.relatedTarget; | ||
6575 | + | ||
6576 | + if (!related) { return true; } | ||
6577 | + | ||
6578 | + try { | ||
6579 | + while (related && (related !== el)) { | ||
6580 | + related = related.parentNode; | ||
6581 | + } | ||
6582 | + } catch (err) { | ||
6583 | + return false; | ||
6584 | + } | ||
6585 | + return (related !== el); | ||
6586 | + }, | ||
6587 | + | ||
6588 | + _getEvent: function () { // evil magic for IE | ||
6589 | + /*jshint noarg:false */ | ||
6590 | + var e = window.event; | ||
6591 | + if (!e) { | ||
6592 | + var caller = arguments.callee.caller; | ||
6593 | + while (caller) { | ||
6594 | + e = caller['arguments'][0]; | ||
6595 | + if (e && window.Event === e.constructor) { | ||
6596 | + break; | ||
6597 | + } | ||
6598 | + caller = caller.caller; | ||
6599 | + } | ||
6600 | + } | ||
6601 | + return e; | ||
6602 | + }, | ||
6603 | + | ||
6604 | + // this is a horrible workaround for a bug in Android where a single touch triggers two click events | ||
6605 | + _filterClick: function (e, handler) { | ||
6606 | + var timeStamp = (e.timeStamp || e.originalEvent.timeStamp), | ||
6607 | + elapsed = L.DomEvent._lastClick && (timeStamp - L.DomEvent._lastClick); | ||
6608 | + | ||
6609 | + // are they closer together than 500ms yet more than 100ms? | ||
6610 | + // Android typically triggers them ~300ms apart while multiple listeners | ||
6611 | + // on the same event should be triggered far faster; | ||
6612 | + // or check if click is simulated on the element, and if it is, reject any non-simulated events | ||
6613 | + | ||
6614 | + if ((elapsed && elapsed > 100 && elapsed < 500) || (e.target._simulatedClick && !e._simulated)) { | ||
6615 | + L.DomEvent.stop(e); | ||
6616 | + return; | ||
6617 | + } | ||
6618 | + L.DomEvent._lastClick = timeStamp; | ||
6619 | + | ||
6620 | + return handler(e); | ||
6621 | + } | ||
6622 | +}; | ||
6623 | + | ||
6624 | +L.DomEvent.on = L.DomEvent.addListener; | ||
6625 | +L.DomEvent.off = L.DomEvent.removeListener; | ||
6626 | + | ||
6627 | + | ||
6628 | +/* | ||
6629 | + * L.Draggable allows you to add dragging capabilities to any element. Supports mobile devices too. | ||
6630 | + */ | ||
6631 | + | ||
6632 | +L.Draggable = L.Class.extend({ | ||
6633 | + includes: L.Mixin.Events, | ||
6634 | + | ||
6635 | + statics: { | ||
6636 | + START: L.Browser.touch ? ['touchstart', 'mousedown'] : ['mousedown'], | ||
6637 | + END: { | ||
6638 | + mousedown: 'mouseup', | ||
6639 | + touchstart: 'touchend', | ||
6640 | + pointerdown: 'touchend', | ||
6641 | + MSPointerDown: 'touchend' | ||
6642 | + }, | ||
6643 | + MOVE: { | ||
6644 | + mousedown: 'mousemove', | ||
6645 | + touchstart: 'touchmove', | ||
6646 | + pointerdown: 'touchmove', | ||
6647 | + MSPointerDown: 'touchmove' | ||
6648 | + } | ||
6649 | + }, | ||
6650 | + | ||
6651 | + initialize: function (element, dragStartTarget) { | ||
6652 | + this._element = element; | ||
6653 | + this._dragStartTarget = dragStartTarget || element; | ||
6654 | + }, | ||
6655 | + | ||
6656 | + enable: function () { | ||
6657 | + if (this._enabled) { return; } | ||
6658 | + | ||
6659 | + for (var i = L.Draggable.START.length - 1; i >= 0; i--) { | ||
6660 | + L.DomEvent.on(this._dragStartTarget, L.Draggable.START[i], this._onDown, this); | ||
6661 | + } | ||
6662 | + | ||
6663 | + this._enabled = true; | ||
6664 | + }, | ||
6665 | + | ||
6666 | + disable: function () { | ||
6667 | + if (!this._enabled) { return; } | ||
6668 | + | ||
6669 | + for (var i = L.Draggable.START.length - 1; i >= 0; i--) { | ||
6670 | + L.DomEvent.off(this._dragStartTarget, L.Draggable.START[i], this._onDown, this); | ||
6671 | + } | ||
6672 | + | ||
6673 | + this._enabled = false; | ||
6674 | + this._moved = false; | ||
6675 | + }, | ||
6676 | + | ||
6677 | + _onDown: function (e) { | ||
6678 | + this._moved = false; | ||
6679 | + | ||
6680 | + if (e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; } | ||
6681 | + | ||
6682 | + L.DomEvent.stopPropagation(e); | ||
6683 | + | ||
6684 | + if (L.Draggable._disabled) { return; } | ||
6685 | + | ||
6686 | + L.DomUtil.disableImageDrag(); | ||
6687 | + L.DomUtil.disableTextSelection(); | ||
6688 | + | ||
6689 | + if (this._moving) { return; } | ||
6690 | + | ||
6691 | + var first = e.touches ? e.touches[0] : e; | ||
6692 | + | ||
6693 | + this._startPoint = new L.Point(first.clientX, first.clientY); | ||
6694 | + this._startPos = this._newPos = L.DomUtil.getPosition(this._element); | ||
6695 | + | ||
6696 | + L.DomEvent | ||
6697 | + .on(document, L.Draggable.MOVE[e.type], this._onMove, this) | ||
6698 | + .on(document, L.Draggable.END[e.type], this._onUp, this); | ||
6699 | + }, | ||
6700 | + | ||
6701 | + _onMove: function (e) { | ||
6702 | + if (e.touches && e.touches.length > 1) { | ||
6703 | + this._moved = true; | ||
6704 | + return; | ||
6705 | + } | ||
6706 | + | ||
6707 | + var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e), | ||
6708 | + newPoint = new L.Point(first.clientX, first.clientY), | ||
6709 | + offset = newPoint.subtract(this._startPoint); | ||
6710 | + | ||
6711 | + if (!offset.x && !offset.y) { return; } | ||
6712 | + if (L.Browser.touch && Math.abs(offset.x) + Math.abs(offset.y) < 3) { return; } | ||
6713 | + | ||
6714 | + L.DomEvent.preventDefault(e); | ||
6715 | + | ||
6716 | + if (!this._moved) { | ||
6717 | + this.fire('dragstart'); | ||
6718 | + | ||
6719 | + this._moved = true; | ||
6720 | + this._startPos = L.DomUtil.getPosition(this._element).subtract(offset); | ||
6721 | + | ||
6722 | + L.DomUtil.addClass(document.body, 'leaflet-dragging'); | ||
6723 | + this._lastTarget = e.target || e.srcElement; | ||
6724 | + L.DomUtil.addClass(this._lastTarget, 'leaflet-drag-target'); | ||
6725 | + } | ||
6726 | + | ||
6727 | + this._newPos = this._startPos.add(offset); | ||
6728 | + this._moving = true; | ||
6729 | + | ||
6730 | + L.Util.cancelAnimFrame(this._animRequest); | ||
6731 | + this._animRequest = L.Util.requestAnimFrame(this._updatePosition, this, true, this._dragStartTarget); | ||
6732 | + }, | ||
6733 | + | ||
6734 | + _updatePosition: function () { | ||
6735 | + this.fire('predrag'); | ||
6736 | + L.DomUtil.setPosition(this._element, this._newPos); | ||
6737 | + this.fire('drag'); | ||
6738 | + }, | ||
6739 | + | ||
6740 | + _onUp: function () { | ||
6741 | + L.DomUtil.removeClass(document.body, 'leaflet-dragging'); | ||
6742 | + | ||
6743 | + if (this._lastTarget) { | ||
6744 | + L.DomUtil.removeClass(this._lastTarget, 'leaflet-drag-target'); | ||
6745 | + this._lastTarget = null; | ||
6746 | + } | ||
6747 | + | ||
6748 | + for (var i in L.Draggable.MOVE) { | ||
6749 | + L.DomEvent | ||
6750 | + .off(document, L.Draggable.MOVE[i], this._onMove) | ||
6751 | + .off(document, L.Draggable.END[i], this._onUp); | ||
6752 | + } | ||
6753 | + | ||
6754 | + L.DomUtil.enableImageDrag(); | ||
6755 | + L.DomUtil.enableTextSelection(); | ||
6756 | + | ||
6757 | + if (this._moved && this._moving) { | ||
6758 | + // ensure drag is not fired after dragend | ||
6759 | + L.Util.cancelAnimFrame(this._animRequest); | ||
6760 | + | ||
6761 | + this.fire('dragend', { | ||
6762 | + distance: this._newPos.distanceTo(this._startPos) | ||
6763 | + }); | ||
6764 | + } | ||
6765 | + | ||
6766 | + this._moving = false; | ||
6767 | + } | ||
6768 | +}); | ||
6769 | + | ||
6770 | + | ||
6771 | +/* | ||
6772 | + L.Handler is a base class for handler classes that are used internally to inject | ||
6773 | + interaction features like dragging to classes like Map and Marker. | ||
6774 | +*/ | ||
6775 | + | ||
6776 | +L.Handler = L.Class.extend({ | ||
6777 | + initialize: function (map) { | ||
6778 | + this._map = map; | ||
6779 | + }, | ||
6780 | + | ||
6781 | + enable: function () { | ||
6782 | + if (this._enabled) { return; } | ||
6783 | + | ||
6784 | + this._enabled = true; | ||
6785 | + this.addHooks(); | ||
6786 | + }, | ||
6787 | + | ||
6788 | + disable: function () { | ||
6789 | + if (!this._enabled) { return; } | ||
6790 | + | ||
6791 | + this._enabled = false; | ||
6792 | + this.removeHooks(); | ||
6793 | + }, | ||
6794 | + | ||
6795 | + enabled: function () { | ||
6796 | + return !!this._enabled; | ||
6797 | + } | ||
6798 | +}); | ||
6799 | + | ||
6800 | + | ||
6801 | +/* | ||
6802 | + * L.Handler.MapDrag is used to make the map draggable (with panning inertia), enabled by default. | ||
6803 | + */ | ||
6804 | + | ||
6805 | +L.Map.mergeOptions({ | ||
6806 | + dragging: true, | ||
6807 | + | ||
6808 | + inertia: !L.Browser.android23, | ||
6809 | + inertiaDeceleration: 3400, // px/s^2 | ||
6810 | + inertiaMaxSpeed: Infinity, // px/s | ||
6811 | + inertiaThreshold: L.Browser.touch ? 32 : 18, // ms | ||
6812 | + easeLinearity: 0.25, | ||
6813 | + | ||
6814 | + // TODO refactor, move to CRS | ||
6815 | + worldCopyJump: false | ||
6816 | +}); | ||
6817 | + | ||
6818 | +L.Map.Drag = L.Handler.extend({ | ||
6819 | + addHooks: function () { | ||
6820 | + if (!this._draggable) { | ||
6821 | + var map = this._map; | ||
6822 | + | ||
6823 | + this._draggable = new L.Draggable(map._mapPane, map._container); | ||
6824 | + | ||
6825 | + this._draggable.on({ | ||
6826 | + 'dragstart': this._onDragStart, | ||
6827 | + 'drag': this._onDrag, | ||
6828 | + 'dragend': this._onDragEnd | ||
6829 | + }, this); | ||
6830 | + | ||
6831 | + if (map.options.worldCopyJump) { | ||
6832 | + this._draggable.on('predrag', this._onPreDrag, this); | ||
6833 | + map.on('viewreset', this._onViewReset, this); | ||
6834 | + | ||
6835 | + map.whenReady(this._onViewReset, this); | ||
6836 | + } | ||
6837 | + } | ||
6838 | + this._draggable.enable(); | ||
6839 | + }, | ||
6840 | + | ||
6841 | + removeHooks: function () { | ||
6842 | + this._draggable.disable(); | ||
6843 | + }, | ||
6844 | + | ||
6845 | + moved: function () { | ||
6846 | + return this._draggable && this._draggable._moved; | ||
6847 | + }, | ||
6848 | + | ||
6849 | + _onDragStart: function () { | ||
6850 | + var map = this._map; | ||
6851 | + | ||
6852 | + if (map._panAnim) { | ||
6853 | + map._panAnim.stop(); | ||
6854 | + } | ||
6855 | + | ||
6856 | + map | ||
6857 | + .fire('movestart') | ||
6858 | + .fire('dragstart'); | ||
6859 | + | ||
6860 | + if (map.options.inertia) { | ||
6861 | + this._positions = []; | ||
6862 | + this._times = []; | ||
6863 | + } | ||
6864 | + }, | ||
6865 | + | ||
6866 | + _onDrag: function () { | ||
6867 | + if (this._map.options.inertia) { | ||
6868 | + var time = this._lastTime = +new Date(), | ||
6869 | + pos = this._lastPos = this._draggable._newPos; | ||
6870 | + | ||
6871 | + this._positions.push(pos); | ||
6872 | + this._times.push(time); | ||
6873 | + | ||
6874 | + if (time - this._times[0] > 200) { | ||
6875 | + this._positions.shift(); | ||
6876 | + this._times.shift(); | ||
6877 | + } | ||
6878 | + } | ||
6879 | + | ||
6880 | + this._map | ||
6881 | + .fire('move') | ||
6882 | + .fire('drag'); | ||
6883 | + }, | ||
6884 | + | ||
6885 | + _onViewReset: function () { | ||
6886 | + // TODO fix hardcoded Earth values | ||
6887 | + var pxCenter = this._map.getSize()._divideBy(2), | ||
6888 | + pxWorldCenter = this._map.latLngToLayerPoint([0, 0]); | ||
6889 | + | ||
6890 | + this._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x; | ||
6891 | + this._worldWidth = this._map.project([0, 180]).x; | ||
6892 | + }, | ||
6893 | + | ||
6894 | + _onPreDrag: function () { | ||
6895 | + // TODO refactor to be able to adjust map pane position after zoom | ||
6896 | + var worldWidth = this._worldWidth, | ||
6897 | + halfWidth = Math.round(worldWidth / 2), | ||
6898 | + dx = this._initialWorldOffset, | ||
6899 | + x = this._draggable._newPos.x, | ||
6900 | + newX1 = (x - halfWidth + dx) % worldWidth + halfWidth - dx, | ||
6901 | + newX2 = (x + halfWidth + dx) % worldWidth - halfWidth - dx, | ||
6902 | + newX = Math.abs(newX1 + dx) < Math.abs(newX2 + dx) ? newX1 : newX2; | ||
6903 | + | ||
6904 | + this._draggable._newPos.x = newX; | ||
6905 | + }, | ||
6906 | + | ||
6907 | + _onDragEnd: function (e) { | ||
6908 | + var map = this._map, | ||
6909 | + options = map.options, | ||
6910 | + delay = +new Date() - this._lastTime, | ||
6911 | + | ||
6912 | + noInertia = !options.inertia || delay > options.inertiaThreshold || !this._positions[0]; | ||
6913 | + | ||
6914 | + map.fire('dragend', e); | ||
6915 | + | ||
6916 | + if (noInertia) { | ||
6917 | + map.fire('moveend'); | ||
6918 | + | ||
6919 | + } else { | ||
6920 | + | ||
6921 | + var direction = this._lastPos.subtract(this._positions[0]), | ||
6922 | + duration = (this._lastTime + delay - this._times[0]) / 1000, | ||
6923 | + ease = options.easeLinearity, | ||
6924 | + | ||
6925 | + speedVector = direction.multiplyBy(ease / duration), | ||
6926 | + speed = speedVector.distanceTo([0, 0]), | ||
6927 | + | ||
6928 | + limitedSpeed = Math.min(options.inertiaMaxSpeed, speed), | ||
6929 | + limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed), | ||
6930 | + | ||
6931 | + decelerationDuration = limitedSpeed / (options.inertiaDeceleration * ease), | ||
6932 | + offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round(); | ||
6933 | + | ||
6934 | + if (!offset.x || !offset.y) { | ||
6935 | + map.fire('moveend'); | ||
6936 | + | ||
6937 | + } else { | ||
6938 | + offset = map._limitOffset(offset, map.options.maxBounds); | ||
6939 | + | ||
6940 | + L.Util.requestAnimFrame(function () { | ||
6941 | + map.panBy(offset, { | ||
6942 | + duration: decelerationDuration, | ||
6943 | + easeLinearity: ease, | ||
6944 | + noMoveStart: true | ||
6945 | + }); | ||
6946 | + }); | ||
6947 | + } | ||
6948 | + } | ||
6949 | + } | ||
6950 | +}); | ||
6951 | + | ||
6952 | +L.Map.addInitHook('addHandler', 'dragging', L.Map.Drag); | ||
6953 | + | ||
6954 | + | ||
6955 | +/* | ||
6956 | + * L.Handler.DoubleClickZoom is used to handle double-click zoom on the map, enabled by default. | ||
6957 | + */ | ||
6958 | + | ||
6959 | +L.Map.mergeOptions({ | ||
6960 | + doubleClickZoom: true | ||
6961 | +}); | ||
6962 | + | ||
6963 | +L.Map.DoubleClickZoom = L.Handler.extend({ | ||
6964 | + addHooks: function () { | ||
6965 | + this._map.on('dblclick', this._onDoubleClick, this); | ||
6966 | + }, | ||
6967 | + | ||
6968 | + removeHooks: function () { | ||
6969 | + this._map.off('dblclick', this._onDoubleClick, this); | ||
6970 | + }, | ||
6971 | + | ||
6972 | + _onDoubleClick: function (e) { | ||
6973 | + var map = this._map, | ||
6974 | + zoom = map.getZoom() + (e.originalEvent.shiftKey ? -1 : 1); | ||
6975 | + | ||
6976 | + if (map.options.doubleClickZoom === 'center') { | ||
6977 | + map.setZoom(zoom); | ||
6978 | + } else { | ||
6979 | + map.setZoomAround(e.containerPoint, zoom); | ||
6980 | + } | ||
6981 | + } | ||
6982 | +}); | ||
6983 | + | ||
6984 | +L.Map.addInitHook('addHandler', 'doubleClickZoom', L.Map.DoubleClickZoom); | ||
6985 | + | ||
6986 | + | ||
6987 | +/* | ||
6988 | + * L.Handler.ScrollWheelZoom is used by L.Map to enable mouse scroll wheel zoom on the map. | ||
6989 | + */ | ||
6990 | + | ||
6991 | +L.Map.mergeOptions({ | ||
6992 | + scrollWheelZoom: true | ||
6993 | +}); | ||
6994 | + | ||
6995 | +L.Map.ScrollWheelZoom = L.Handler.extend({ | ||
6996 | + addHooks: function () { | ||
6997 | + L.DomEvent.on(this._map._container, 'mousewheel', this._onWheelScroll, this); | ||
6998 | + L.DomEvent.on(this._map._container, 'MozMousePixelScroll', L.DomEvent.preventDefault); | ||
6999 | + this._delta = 0; | ||
7000 | + }, | ||
7001 | + | ||
7002 | + removeHooks: function () { | ||
7003 | + L.DomEvent.off(this._map._container, 'mousewheel', this._onWheelScroll); | ||
7004 | + L.DomEvent.off(this._map._container, 'MozMousePixelScroll', L.DomEvent.preventDefault); | ||
7005 | + }, | ||
7006 | + | ||
7007 | + _onWheelScroll: function (e) { | ||
7008 | + var delta = L.DomEvent.getWheelDelta(e); | ||
7009 | + | ||
7010 | + this._delta += delta; | ||
7011 | + this._lastMousePos = this._map.mouseEventToContainerPoint(e); | ||
7012 | + | ||
7013 | + if (!this._startTime) { | ||
7014 | + this._startTime = +new Date(); | ||
7015 | + } | ||
7016 | + | ||
7017 | + var left = Math.max(40 - (+new Date() - this._startTime), 0); | ||
7018 | + | ||
7019 | + clearTimeout(this._timer); | ||
7020 | + this._timer = setTimeout(L.bind(this._performZoom, this), left); | ||
7021 | + | ||
7022 | + L.DomEvent.preventDefault(e); | ||
7023 | + L.DomEvent.stopPropagation(e); | ||
7024 | + }, | ||
7025 | + | ||
7026 | + _performZoom: function () { | ||
7027 | + var map = this._map, | ||
7028 | + delta = this._delta, | ||
7029 | + zoom = map.getZoom(); | ||
7030 | + | ||
7031 | + delta = delta > 0 ? Math.ceil(delta) : Math.floor(delta); | ||
7032 | + delta = Math.max(Math.min(delta, 4), -4); | ||
7033 | + delta = map._limitZoom(zoom + delta) - zoom; | ||
7034 | + | ||
7035 | + this._delta = 0; | ||
7036 | + this._startTime = null; | ||
7037 | + | ||
7038 | + if (!delta) { return; } | ||
7039 | + | ||
7040 | + if (map.options.scrollWheelZoom === 'center') { | ||
7041 | + map.setZoom(zoom + delta); | ||
7042 | + } else { | ||
7043 | + map.setZoomAround(this._lastMousePos, zoom + delta); | ||
7044 | + } | ||
7045 | + } | ||
7046 | +}); | ||
7047 | + | ||
7048 | +L.Map.addInitHook('addHandler', 'scrollWheelZoom', L.Map.ScrollWheelZoom); | ||
7049 | + | ||
7050 | + | ||
7051 | +/* | ||
7052 | + * Extends the event handling code with double tap support for mobile browsers. | ||
7053 | + */ | ||
7054 | + | ||
7055 | +L.extend(L.DomEvent, { | ||
7056 | + | ||
7057 | + _touchstart: L.Browser.msPointer ? 'MSPointerDown' : L.Browser.pointer ? 'pointerdown' : 'touchstart', | ||
7058 | + _touchend: L.Browser.msPointer ? 'MSPointerUp' : L.Browser.pointer ? 'pointerup' : 'touchend', | ||
7059 | + | ||
7060 | + // inspired by Zepto touch code by Thomas Fuchs | ||
7061 | + addDoubleTapListener: function (obj, handler, id) { | ||
7062 | + var last, | ||
7063 | + doubleTap = false, | ||
7064 | + delay = 250, | ||
7065 | + touch, | ||
7066 | + pre = '_leaflet_', | ||
7067 | + touchstart = this._touchstart, | ||
7068 | + touchend = this._touchend, | ||
7069 | + trackedTouches = []; | ||
7070 | + | ||
7071 | + function onTouchStart(e) { | ||
7072 | + var count; | ||
7073 | + | ||
7074 | + if (L.Browser.pointer) { | ||
7075 | + trackedTouches.push(e.pointerId); | ||
7076 | + count = trackedTouches.length; | ||
7077 | + } else { | ||
7078 | + count = e.touches.length; | ||
7079 | + } | ||
7080 | + if (count > 1) { | ||
7081 | + return; | ||
7082 | + } | ||
7083 | + | ||
7084 | + var now = Date.now(), | ||
7085 | + delta = now - (last || now); | ||
7086 | + | ||
7087 | + touch = e.touches ? e.touches[0] : e; | ||
7088 | + doubleTap = (delta > 0 && delta <= delay); | ||
7089 | + last = now; | ||
7090 | + } | ||
7091 | + | ||
7092 | + function onTouchEnd(e) { | ||
7093 | + if (L.Browser.pointer) { | ||
7094 | + var idx = trackedTouches.indexOf(e.pointerId); | ||
7095 | + if (idx === -1) { | ||
7096 | + return; | ||
7097 | + } | ||
7098 | + trackedTouches.splice(idx, 1); | ||
7099 | + } | ||
7100 | + | ||
7101 | + if (doubleTap) { | ||
7102 | + if (L.Browser.pointer) { | ||
7103 | + // work around .type being readonly with MSPointer* events | ||
7104 | + var newTouch = { }, | ||
7105 | + prop; | ||
7106 | + | ||
7107 | + // jshint forin:false | ||
7108 | + for (var i in touch) { | ||
7109 | + prop = touch[i]; | ||
7110 | + if (typeof prop === 'function') { | ||
7111 | + newTouch[i] = prop.bind(touch); | ||
7112 | + } else { | ||
7113 | + newTouch[i] = prop; | ||
7114 | + } | ||
7115 | + } | ||
7116 | + touch = newTouch; | ||
7117 | + } | ||
7118 | + touch.type = 'dblclick'; | ||
7119 | + handler(touch); | ||
7120 | + last = null; | ||
7121 | + } | ||
7122 | + } | ||
7123 | + obj[pre + touchstart + id] = onTouchStart; | ||
7124 | + obj[pre + touchend + id] = onTouchEnd; | ||
7125 | + | ||
7126 | + // on pointer we need to listen on the document, otherwise a drag starting on the map and moving off screen | ||
7127 | + // will not come through to us, so we will lose track of how many touches are ongoing | ||
7128 | + var endElement = L.Browser.pointer ? document.documentElement : obj; | ||
7129 | + | ||
7130 | + obj.addEventListener(touchstart, onTouchStart, false); | ||
7131 | + endElement.addEventListener(touchend, onTouchEnd, false); | ||
7132 | + | ||
7133 | + if (L.Browser.pointer) { | ||
7134 | + endElement.addEventListener(L.DomEvent.POINTER_CANCEL, onTouchEnd, false); | ||
7135 | + } | ||
7136 | + | ||
7137 | + return this; | ||
7138 | + }, | ||
7139 | + | ||
7140 | + removeDoubleTapListener: function (obj, id) { | ||
7141 | + var pre = '_leaflet_'; | ||
7142 | + | ||
7143 | + obj.removeEventListener(this._touchstart, obj[pre + this._touchstart + id], false); | ||
7144 | + (L.Browser.pointer ? document.documentElement : obj).removeEventListener( | ||
7145 | + this._touchend, obj[pre + this._touchend + id], false); | ||
7146 | + | ||
7147 | + if (L.Browser.pointer) { | ||
7148 | + document.documentElement.removeEventListener(L.DomEvent.POINTER_CANCEL, obj[pre + this._touchend + id], | ||
7149 | + false); | ||
7150 | + } | ||
7151 | + | ||
7152 | + return this; | ||
7153 | + } | ||
7154 | +}); | ||
7155 | + | ||
7156 | + | ||
7157 | +/* | ||
7158 | + * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices. | ||
7159 | + */ | ||
7160 | + | ||
7161 | +L.extend(L.DomEvent, { | ||
7162 | + | ||
7163 | + //static | ||
7164 | + POINTER_DOWN: L.Browser.msPointer ? 'MSPointerDown' : 'pointerdown', | ||
7165 | + POINTER_MOVE: L.Browser.msPointer ? 'MSPointerMove' : 'pointermove', | ||
7166 | + POINTER_UP: L.Browser.msPointer ? 'MSPointerUp' : 'pointerup', | ||
7167 | + POINTER_CANCEL: L.Browser.msPointer ? 'MSPointerCancel' : 'pointercancel', | ||
7168 | + | ||
7169 | + _pointers: [], | ||
7170 | + _pointerDocumentListener: false, | ||
7171 | + | ||
7172 | + // Provides a touch events wrapper for (ms)pointer events. | ||
7173 | + // Based on changes by veproza https://github.com/CloudMade/Leaflet/pull/1019 | ||
7174 | + //ref http://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890 | ||
7175 | + | ||
7176 | + addPointerListener: function (obj, type, handler, id) { | ||
7177 | + | ||
7178 | + switch (type) { | ||
7179 | + case 'touchstart': | ||
7180 | + return this.addPointerListenerStart(obj, type, handler, id); | ||
7181 | + case 'touchend': | ||
7182 | + return this.addPointerListenerEnd(obj, type, handler, id); | ||
7183 | + case 'touchmove': | ||
7184 | + return this.addPointerListenerMove(obj, type, handler, id); | ||
7185 | + default: | ||
7186 | + throw 'Unknown touch event type'; | ||
7187 | + } | ||
7188 | + }, | ||
7189 | + | ||
7190 | + addPointerListenerStart: function (obj, type, handler, id) { | ||
7191 | + var pre = '_leaflet_', | ||
7192 | + pointers = this._pointers; | ||
7193 | + | ||
7194 | + var cb = function (e) { | ||
7195 | + | ||
7196 | + L.DomEvent.preventDefault(e); | ||
7197 | + | ||
7198 | + var alreadyInArray = false; | ||
7199 | + for (var i = 0; i < pointers.length; i++) { | ||
7200 | + if (pointers[i].pointerId === e.pointerId) { | ||
7201 | + alreadyInArray = true; | ||
7202 | + break; | ||
7203 | + } | ||
7204 | + } | ||
7205 | + if (!alreadyInArray) { | ||
7206 | + pointers.push(e); | ||
7207 | + } | ||
7208 | + | ||
7209 | + e.touches = pointers.slice(); | ||
7210 | + e.changedTouches = [e]; | ||
7211 | + | ||
7212 | + handler(e); | ||
7213 | + }; | ||
7214 | + | ||
7215 | + obj[pre + 'touchstart' + id] = cb; | ||
7216 | + obj.addEventListener(this.POINTER_DOWN, cb, false); | ||
7217 | + | ||
7218 | + // need to also listen for end events to keep the _pointers list accurate | ||
7219 | + // this needs to be on the body and never go away | ||
7220 | + if (!this._pointerDocumentListener) { | ||
7221 | + var internalCb = function (e) { | ||
7222 | + for (var i = 0; i < pointers.length; i++) { | ||
7223 | + if (pointers[i].pointerId === e.pointerId) { | ||
7224 | + pointers.splice(i, 1); | ||
7225 | + break; | ||
7226 | + } | ||
7227 | + } | ||
7228 | + }; | ||
7229 | + //We listen on the documentElement as any drags that end by moving the touch off the screen get fired there | ||
7230 | + document.documentElement.addEventListener(this.POINTER_UP, internalCb, false); | ||
7231 | + document.documentElement.addEventListener(this.POINTER_CANCEL, internalCb, false); | ||
7232 | + | ||
7233 | + this._pointerDocumentListener = true; | ||
7234 | + } | ||
7235 | + | ||
7236 | + return this; | ||
7237 | + }, | ||
7238 | + | ||
7239 | + addPointerListenerMove: function (obj, type, handler, id) { | ||
7240 | + var pre = '_leaflet_', | ||
7241 | + touches = this._pointers; | ||
7242 | + | ||
7243 | + function cb(e) { | ||
7244 | + | ||
7245 | + // don't fire touch moves when mouse isn't down | ||
7246 | + if ((e.pointerType === e.MSPOINTER_TYPE_MOUSE || e.pointerType === 'mouse') && e.buttons === 0) { return; } | ||
7247 | + | ||
7248 | + for (var i = 0; i < touches.length; i++) { | ||
7249 | + if (touches[i].pointerId === e.pointerId) { | ||
7250 | + touches[i] = e; | ||
7251 | + break; | ||
7252 | + } | ||
7253 | + } | ||
7254 | + | ||
7255 | + e.touches = touches.slice(); | ||
7256 | + e.changedTouches = [e]; | ||
7257 | + | ||
7258 | + handler(e); | ||
7259 | + } | ||
7260 | + | ||
7261 | + obj[pre + 'touchmove' + id] = cb; | ||
7262 | + obj.addEventListener(this.POINTER_MOVE, cb, false); | ||
7263 | + | ||
7264 | + return this; | ||
7265 | + }, | ||
7266 | + | ||
7267 | + addPointerListenerEnd: function (obj, type, handler, id) { | ||
7268 | + var pre = '_leaflet_', | ||
7269 | + touches = this._pointers; | ||
7270 | + | ||
7271 | + var cb = function (e) { | ||
7272 | + for (var i = 0; i < touches.length; i++) { | ||
7273 | + if (touches[i].pointerId === e.pointerId) { | ||
7274 | + touches.splice(i, 1); | ||
7275 | + break; | ||
7276 | + } | ||
7277 | + } | ||
7278 | + | ||
7279 | + e.touches = touches.slice(); | ||
7280 | + e.changedTouches = [e]; | ||
7281 | + | ||
7282 | + handler(e); | ||
7283 | + }; | ||
7284 | + | ||
7285 | + obj[pre + 'touchend' + id] = cb; | ||
7286 | + obj.addEventListener(this.POINTER_UP, cb, false); | ||
7287 | + obj.addEventListener(this.POINTER_CANCEL, cb, false); | ||
7288 | + | ||
7289 | + return this; | ||
7290 | + }, | ||
7291 | + | ||
7292 | + removePointerListener: function (obj, type, id) { | ||
7293 | + var pre = '_leaflet_', | ||
7294 | + cb = obj[pre + type + id]; | ||
7295 | + | ||
7296 | + switch (type) { | ||
7297 | + case 'touchstart': | ||
7298 | + obj.removeEventListener(this.POINTER_DOWN, cb, false); | ||
7299 | + break; | ||
7300 | + case 'touchmove': | ||
7301 | + obj.removeEventListener(this.POINTER_MOVE, cb, false); | ||
7302 | + break; | ||
7303 | + case 'touchend': | ||
7304 | + obj.removeEventListener(this.POINTER_UP, cb, false); | ||
7305 | + obj.removeEventListener(this.POINTER_CANCEL, cb, false); | ||
7306 | + break; | ||
7307 | + } | ||
7308 | + | ||
7309 | + return this; | ||
7310 | + } | ||
7311 | +}); | ||
7312 | + | ||
7313 | + | ||
7314 | +/* | ||
7315 | + * L.Handler.TouchZoom is used by L.Map to add pinch zoom on supported mobile browsers. | ||
7316 | + */ | ||
7317 | + | ||
7318 | +L.Map.mergeOptions({ | ||
7319 | + touchZoom: L.Browser.touch && !L.Browser.android23, | ||
7320 | + bounceAtZoomLimits: true | ||
7321 | +}); | ||
7322 | + | ||
7323 | +L.Map.TouchZoom = L.Handler.extend({ | ||
7324 | + addHooks: function () { | ||
7325 | + L.DomEvent.on(this._map._container, 'touchstart', this._onTouchStart, this); | ||
7326 | + }, | ||
7327 | + | ||
7328 | + removeHooks: function () { | ||
7329 | + L.DomEvent.off(this._map._container, 'touchstart', this._onTouchStart, this); | ||
7330 | + }, | ||
7331 | + | ||
7332 | + _onTouchStart: function (e) { | ||
7333 | + var map = this._map; | ||
7334 | + | ||
7335 | + if (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming) { return; } | ||
7336 | + | ||
7337 | + var p1 = map.mouseEventToLayerPoint(e.touches[0]), | ||
7338 | + p2 = map.mouseEventToLayerPoint(e.touches[1]), | ||
7339 | + viewCenter = map._getCenterLayerPoint(); | ||
7340 | + | ||
7341 | + this._startCenter = p1.add(p2)._divideBy(2); | ||
7342 | + this._startDist = p1.distanceTo(p2); | ||
7343 | + | ||
7344 | + this._moved = false; | ||
7345 | + this._zooming = true; | ||
7346 | + | ||
7347 | + this._centerOffset = viewCenter.subtract(this._startCenter); | ||
7348 | + | ||
7349 | + if (map._panAnim) { | ||
7350 | + map._panAnim.stop(); | ||
7351 | + } | ||
7352 | + | ||
7353 | + L.DomEvent | ||
7354 | + .on(document, 'touchmove', this._onTouchMove, this) | ||
7355 | + .on(document, 'touchend', this._onTouchEnd, this); | ||
7356 | + | ||
7357 | + L.DomEvent.preventDefault(e); | ||
7358 | + }, | ||
7359 | + | ||
7360 | + _onTouchMove: function (e) { | ||
7361 | + var map = this._map; | ||
7362 | + | ||
7363 | + if (!e.touches || e.touches.length !== 2 || !this._zooming) { return; } | ||
7364 | + | ||
7365 | + var p1 = map.mouseEventToLayerPoint(e.touches[0]), | ||
7366 | + p2 = map.mouseEventToLayerPoint(e.touches[1]); | ||
7367 | + | ||
7368 | + this._scale = p1.distanceTo(p2) / this._startDist; | ||
7369 | + this._delta = p1._add(p2)._divideBy(2)._subtract(this._startCenter); | ||
7370 | + | ||
7371 | + if (this._scale === 1) { return; } | ||
7372 | + | ||
7373 | + if (!map.options.bounceAtZoomLimits) { | ||
7374 | + if ((map.getZoom() === map.getMinZoom() && this._scale < 1) || | ||
7375 | + (map.getZoom() === map.getMaxZoom() && this._scale > 1)) { return; } | ||
7376 | + } | ||
7377 | + | ||
7378 | + if (!this._moved) { | ||
7379 | + L.DomUtil.addClass(map._mapPane, 'leaflet-touching'); | ||
7380 | + | ||
7381 | + map | ||
7382 | + .fire('movestart') | ||
7383 | + .fire('zoomstart'); | ||
7384 | + | ||
7385 | + this._moved = true; | ||
7386 | + } | ||
7387 | + | ||
7388 | + L.Util.cancelAnimFrame(this._animRequest); | ||
7389 | + this._animRequest = L.Util.requestAnimFrame( | ||
7390 | + this._updateOnMove, this, true, this._map._container); | ||
7391 | + | ||
7392 | + L.DomEvent.preventDefault(e); | ||
7393 | + }, | ||
7394 | + | ||
7395 | + _updateOnMove: function () { | ||
7396 | + var map = this._map, | ||
7397 | + origin = this._getScaleOrigin(), | ||
7398 | + center = map.layerPointToLatLng(origin), | ||
7399 | + zoom = map.getScaleZoom(this._scale); | ||
7400 | + | ||
7401 | + map._animateZoom(center, zoom, this._startCenter, this._scale, this._delta, false, true); | ||
7402 | + }, | ||
7403 | + | ||
7404 | + _onTouchEnd: function () { | ||
7405 | + if (!this._moved || !this._zooming) { | ||
7406 | + this._zooming = false; | ||
7407 | + return; | ||
7408 | + } | ||
7409 | + | ||
7410 | + var map = this._map; | ||
7411 | + | ||
7412 | + this._zooming = false; | ||
7413 | + L.DomUtil.removeClass(map._mapPane, 'leaflet-touching'); | ||
7414 | + L.Util.cancelAnimFrame(this._animRequest); | ||
7415 | + | ||
7416 | + L.DomEvent | ||
7417 | + .off(document, 'touchmove', this._onTouchMove) | ||
7418 | + .off(document, 'touchend', this._onTouchEnd); | ||
7419 | + | ||
7420 | + var origin = this._getScaleOrigin(), | ||
7421 | + center = map.layerPointToLatLng(origin), | ||
7422 | + | ||
7423 | + oldZoom = map.getZoom(), | ||
7424 | + floatZoomDelta = map.getScaleZoom(this._scale) - oldZoom, | ||
7425 | + roundZoomDelta = (floatZoomDelta > 0 ? | ||
7426 | + Math.ceil(floatZoomDelta) : Math.floor(floatZoomDelta)), | ||
7427 | + | ||
7428 | + zoom = map._limitZoom(oldZoom + roundZoomDelta), | ||
7429 | + scale = map.getZoomScale(zoom) / this._scale; | ||
7430 | + | ||
7431 | + map._animateZoom(center, zoom, origin, scale); | ||
7432 | + }, | ||
7433 | + | ||
7434 | + _getScaleOrigin: function () { | ||
7435 | + var centerOffset = this._centerOffset.subtract(this._delta).divideBy(this._scale); | ||
7436 | + return this._startCenter.add(centerOffset); | ||
7437 | + } | ||
7438 | +}); | ||
7439 | + | ||
7440 | +L.Map.addInitHook('addHandler', 'touchZoom', L.Map.TouchZoom); | ||
7441 | + | ||
7442 | + | ||
7443 | +/* | ||
7444 | + * L.Map.Tap is used to enable mobile hacks like quick taps and long hold. | ||
7445 | + */ | ||
7446 | + | ||
7447 | +L.Map.mergeOptions({ | ||
7448 | + tap: true, | ||
7449 | + tapTolerance: 15 | ||
7450 | +}); | ||
7451 | + | ||
7452 | +L.Map.Tap = L.Handler.extend({ | ||
7453 | + addHooks: function () { | ||
7454 | + L.DomEvent.on(this._map._container, 'touchstart', this._onDown, this); | ||
7455 | + }, | ||
7456 | + | ||
7457 | + removeHooks: function () { | ||
7458 | + L.DomEvent.off(this._map._container, 'touchstart', this._onDown, this); | ||
7459 | + }, | ||
7460 | + | ||
7461 | + _onDown: function (e) { | ||
7462 | + if (!e.touches) { return; } | ||
7463 | + | ||
7464 | + L.DomEvent.preventDefault(e); | ||
7465 | + | ||
7466 | + this._fireClick = true; | ||
7467 | + | ||
7468 | + // don't simulate click or track longpress if more than 1 touch | ||
7469 | + if (e.touches.length > 1) { | ||
7470 | + this._fireClick = false; | ||
7471 | + clearTimeout(this._holdTimeout); | ||
7472 | + return; | ||
7473 | + } | ||
7474 | + | ||
7475 | + var first = e.touches[0], | ||
7476 | + el = first.target; | ||
7477 | + | ||
7478 | + this._startPos = this._newPos = new L.Point(first.clientX, first.clientY); | ||
7479 | + | ||
7480 | + // if touching a link, highlight it | ||
7481 | + if (el.tagName && el.tagName.toLowerCase() === 'a') { | ||
7482 | + L.DomUtil.addClass(el, 'leaflet-active'); | ||
7483 | + } | ||
7484 | + | ||
7485 | + // simulate long hold but setting a timeout | ||
7486 | + this._holdTimeout = setTimeout(L.bind(function () { | ||
7487 | + if (this._isTapValid()) { | ||
7488 | + this._fireClick = false; | ||
7489 | + this._onUp(); | ||
7490 | + this._simulateEvent('contextmenu', first); | ||
7491 | + } | ||
7492 | + }, this), 1000); | ||
7493 | + | ||
7494 | + L.DomEvent | ||
7495 | + .on(document, 'touchmove', this._onMove, this) | ||
7496 | + .on(document, 'touchend', this._onUp, this); | ||
7497 | + }, | ||
7498 | + | ||
7499 | + _onUp: function (e) { | ||
7500 | + clearTimeout(this._holdTimeout); | ||
7501 | + | ||
7502 | + L.DomEvent | ||
7503 | + .off(document, 'touchmove', this._onMove, this) | ||
7504 | + .off(document, 'touchend', this._onUp, this); | ||
7505 | + | ||
7506 | + if (this._fireClick && e && e.changedTouches) { | ||
7507 | + | ||
7508 | + var first = e.changedTouches[0], | ||
7509 | + el = first.target; | ||
7510 | + | ||
7511 | + if (el && el.tagName && el.tagName.toLowerCase() === 'a') { | ||
7512 | + L.DomUtil.removeClass(el, 'leaflet-active'); | ||
7513 | + } | ||
7514 | + | ||
7515 | + // simulate click if the touch didn't move too much | ||
7516 | + if (this._isTapValid()) { | ||
7517 | + this._simulateEvent('click', first); | ||
7518 | + } | ||
7519 | + } | ||
7520 | + }, | ||
7521 | + | ||
7522 | + _isTapValid: function () { | ||
7523 | + return this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance; | ||
7524 | + }, | ||
7525 | + | ||
7526 | + _onMove: function (e) { | ||
7527 | + var first = e.touches[0]; | ||
7528 | + this._newPos = new L.Point(first.clientX, first.clientY); | ||
7529 | + }, | ||
7530 | + | ||
7531 | + _simulateEvent: function (type, e) { | ||
7532 | + var simulatedEvent = document.createEvent('MouseEvents'); | ||
7533 | + | ||
7534 | + simulatedEvent._simulated = true; | ||
7535 | + e.target._simulatedClick = true; | ||
7536 | + | ||
7537 | + simulatedEvent.initMouseEvent( | ||
7538 | + type, true, true, window, 1, | ||
7539 | + e.screenX, e.screenY, | ||
7540 | + e.clientX, e.clientY, | ||
7541 | + false, false, false, false, 0, null); | ||
7542 | + | ||
7543 | + e.target.dispatchEvent(simulatedEvent); | ||
7544 | + } | ||
7545 | +}); | ||
7546 | + | ||
7547 | +if (L.Browser.touch && !L.Browser.pointer) { | ||
7548 | + L.Map.addInitHook('addHandler', 'tap', L.Map.Tap); | ||
7549 | +} | ||
7550 | + | ||
7551 | + | ||
7552 | +/* | ||
7553 | + * L.Handler.ShiftDragZoom is used to add shift-drag zoom interaction to the map | ||
7554 | + * (zoom to a selected bounding box), enabled by default. | ||
7555 | + */ | ||
7556 | + | ||
7557 | +L.Map.mergeOptions({ | ||
7558 | + boxZoom: true | ||
7559 | +}); | ||
7560 | + | ||
7561 | +L.Map.BoxZoom = L.Handler.extend({ | ||
7562 | + initialize: function (map) { | ||
7563 | + this._map = map; | ||
7564 | + this._container = map._container; | ||
7565 | + this._pane = map._panes.overlayPane; | ||
7566 | + this._moved = false; | ||
7567 | + }, | ||
7568 | + | ||
7569 | + addHooks: function () { | ||
7570 | + L.DomEvent.on(this._container, 'mousedown', this._onMouseDown, this); | ||
7571 | + }, | ||
7572 | + | ||
7573 | + removeHooks: function () { | ||
7574 | + L.DomEvent.off(this._container, 'mousedown', this._onMouseDown); | ||
7575 | + this._moved = false; | ||
7576 | + }, | ||
7577 | + | ||
7578 | + moved: function () { | ||
7579 | + return this._moved; | ||
7580 | + }, | ||
7581 | + | ||
7582 | + _onMouseDown: function (e) { | ||
7583 | + this._moved = false; | ||
7584 | + | ||
7585 | + if (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; } | ||
7586 | + | ||
7587 | + L.DomUtil.disableTextSelection(); | ||
7588 | + L.DomUtil.disableImageDrag(); | ||
7589 | + | ||
7590 | + this._startLayerPoint = this._map.mouseEventToLayerPoint(e); | ||
7591 | + | ||
7592 | + L.DomEvent | ||
7593 | + .on(document, 'mousemove', this._onMouseMove, this) | ||
7594 | + .on(document, 'mouseup', this._onMouseUp, this) | ||
7595 | + .on(document, 'keydown', this._onKeyDown, this); | ||
7596 | + }, | ||
7597 | + | ||
7598 | + _onMouseMove: function (e) { | ||
7599 | + if (!this._moved) { | ||
7600 | + this._box = L.DomUtil.create('div', 'leaflet-zoom-box', this._pane); | ||
7601 | + L.DomUtil.setPosition(this._box, this._startLayerPoint); | ||
7602 | + | ||
7603 | + //TODO refactor: move cursor to styles | ||
7604 | + this._container.style.cursor = 'crosshair'; | ||
7605 | + this._map.fire('boxzoomstart'); | ||
7606 | + } | ||
7607 | + | ||
7608 | + var startPoint = this._startLayerPoint, | ||
7609 | + box = this._box, | ||
7610 | + | ||
7611 | + layerPoint = this._map.mouseEventToLayerPoint(e), | ||
7612 | + offset = layerPoint.subtract(startPoint), | ||
7613 | + | ||
7614 | + newPos = new L.Point( | ||
7615 | + Math.min(layerPoint.x, startPoint.x), | ||
7616 | + Math.min(layerPoint.y, startPoint.y)); | ||
7617 | + | ||
7618 | + L.DomUtil.setPosition(box, newPos); | ||
7619 | + | ||
7620 | + this._moved = true; | ||
7621 | + | ||
7622 | + // TODO refactor: remove hardcoded 4 pixels | ||
7623 | + box.style.width = (Math.max(0, Math.abs(offset.x) - 4)) + 'px'; | ||
7624 | + box.style.height = (Math.max(0, Math.abs(offset.y) - 4)) + 'px'; | ||
7625 | + }, | ||
7626 | + | ||
7627 | + _finish: function () { | ||
7628 | + if (this._moved) { | ||
7629 | + this._pane.removeChild(this._box); | ||
7630 | + this._container.style.cursor = ''; | ||
7631 | + } | ||
7632 | + | ||
7633 | + L.DomUtil.enableTextSelection(); | ||
7634 | + L.DomUtil.enableImageDrag(); | ||
7635 | + | ||
7636 | + L.DomEvent | ||
7637 | + .off(document, 'mousemove', this._onMouseMove) | ||
7638 | + .off(document, 'mouseup', this._onMouseUp) | ||
7639 | + .off(document, 'keydown', this._onKeyDown); | ||
7640 | + }, | ||
7641 | + | ||
7642 | + _onMouseUp: function (e) { | ||
7643 | + | ||
7644 | + this._finish(); | ||
7645 | + | ||
7646 | + var map = this._map, | ||
7647 | + layerPoint = map.mouseEventToLayerPoint(e); | ||
7648 | + | ||
7649 | + if (this._startLayerPoint.equals(layerPoint)) { return; } | ||
7650 | + | ||
7651 | + var bounds = new L.LatLngBounds( | ||
7652 | + map.layerPointToLatLng(this._startLayerPoint), | ||
7653 | + map.layerPointToLatLng(layerPoint)); | ||
7654 | + | ||
7655 | + map.fitBounds(bounds); | ||
7656 | + | ||
7657 | + map.fire('boxzoomend', { | ||
7658 | + boxZoomBounds: bounds | ||
7659 | + }); | ||
7660 | + }, | ||
7661 | + | ||
7662 | + _onKeyDown: function (e) { | ||
7663 | + if (e.keyCode === 27) { | ||
7664 | + this._finish(); | ||
7665 | + } | ||
7666 | + } | ||
7667 | +}); | ||
7668 | + | ||
7669 | +L.Map.addInitHook('addHandler', 'boxZoom', L.Map.BoxZoom); | ||
7670 | + | ||
7671 | + | ||
7672 | +/* | ||
7673 | + * L.Map.Keyboard is handling keyboard interaction with the map, enabled by default. | ||
7674 | + */ | ||
7675 | + | ||
7676 | +L.Map.mergeOptions({ | ||
7677 | + keyboard: true, | ||
7678 | + keyboardPanOffset: 80, | ||
7679 | + keyboardZoomOffset: 1 | ||
7680 | +}); | ||
7681 | + | ||
7682 | +L.Map.Keyboard = L.Handler.extend({ | ||
7683 | + | ||
7684 | + keyCodes: { | ||
7685 | + left: [37], | ||
7686 | + right: [39], | ||
7687 | + down: [40], | ||
7688 | + up: [38], | ||
7689 | + zoomIn: [187, 107, 61, 171], | ||
7690 | + zoomOut: [189, 109, 173] | ||
7691 | + }, | ||
7692 | + | ||
7693 | + initialize: function (map) { | ||
7694 | + this._map = map; | ||
7695 | + | ||
7696 | + this._setPanOffset(map.options.keyboardPanOffset); | ||
7697 | + this._setZoomOffset(map.options.keyboardZoomOffset); | ||
7698 | + }, | ||
7699 | + | ||
7700 | + addHooks: function () { | ||
7701 | + var container = this._map._container; | ||
7702 | + | ||
7703 | + // make the container focusable by tabbing | ||
7704 | + if (container.tabIndex === -1) { | ||
7705 | + container.tabIndex = '0'; | ||
7706 | + } | ||
7707 | + | ||
7708 | + L.DomEvent | ||
7709 | + .on(container, 'focus', this._onFocus, this) | ||
7710 | + .on(container, 'blur', this._onBlur, this) | ||
7711 | + .on(container, 'mousedown', this._onMouseDown, this); | ||
7712 | + | ||
7713 | + this._map | ||
7714 | + .on('focus', this._addHooks, this) | ||
7715 | + .on('blur', this._removeHooks, this); | ||
7716 | + }, | ||
7717 | + | ||
7718 | + removeHooks: function () { | ||
7719 | + this._removeHooks(); | ||
7720 | + | ||
7721 | + var container = this._map._container; | ||
7722 | + | ||
7723 | + L.DomEvent | ||
7724 | + .off(container, 'focus', this._onFocus, this) | ||
7725 | + .off(container, 'blur', this._onBlur, this) | ||
7726 | + .off(container, 'mousedown', this._onMouseDown, this); | ||
7727 | + | ||
7728 | + this._map | ||
7729 | + .off('focus', this._addHooks, this) | ||
7730 | + .off('blur', this._removeHooks, this); | ||
7731 | + }, | ||
7732 | + | ||
7733 | + _onMouseDown: function () { | ||
7734 | + if (this._focused) { return; } | ||
7735 | + | ||
7736 | + var body = document.body, | ||
7737 | + docEl = document.documentElement, | ||
7738 | + top = body.scrollTop || docEl.scrollTop, | ||
7739 | + left = body.scrollLeft || docEl.scrollLeft; | ||
7740 | + | ||
7741 | + this._map._container.focus(); | ||
7742 | + | ||
7743 | + window.scrollTo(left, top); | ||
7744 | + }, | ||
7745 | + | ||
7746 | + _onFocus: function () { | ||
7747 | + this._focused = true; | ||
7748 | + this._map.fire('focus'); | ||
7749 | + }, | ||
7750 | + | ||
7751 | + _onBlur: function () { | ||
7752 | + this._focused = false; | ||
7753 | + this._map.fire('blur'); | ||
7754 | + }, | ||
7755 | + | ||
7756 | + _setPanOffset: function (pan) { | ||
7757 | + var keys = this._panKeys = {}, | ||
7758 | + codes = this.keyCodes, | ||
7759 | + i, len; | ||
7760 | + | ||
7761 | + for (i = 0, len = codes.left.length; i < len; i++) { | ||
7762 | + keys[codes.left[i]] = [-1 * pan, 0]; | ||
7763 | + } | ||
7764 | + for (i = 0, len = codes.right.length; i < len; i++) { | ||
7765 | + keys[codes.right[i]] = [pan, 0]; | ||
7766 | + } | ||
7767 | + for (i = 0, len = codes.down.length; i < len; i++) { | ||
7768 | + keys[codes.down[i]] = [0, pan]; | ||
7769 | + } | ||
7770 | + for (i = 0, len = codes.up.length; i < len; i++) { | ||
7771 | + keys[codes.up[i]] = [0, -1 * pan]; | ||
7772 | + } | ||
7773 | + }, | ||
7774 | + | ||
7775 | + _setZoomOffset: function (zoom) { | ||
7776 | + var keys = this._zoomKeys = {}, | ||
7777 | + codes = this.keyCodes, | ||
7778 | + i, len; | ||
7779 | + | ||
7780 | + for (i = 0, len = codes.zoomIn.length; i < len; i++) { | ||
7781 | + keys[codes.zoomIn[i]] = zoom; | ||
7782 | + } | ||
7783 | + for (i = 0, len = codes.zoomOut.length; i < len; i++) { | ||
7784 | + keys[codes.zoomOut[i]] = -zoom; | ||
7785 | + } | ||
7786 | + }, | ||
7787 | + | ||
7788 | + _addHooks: function () { | ||
7789 | + L.DomEvent.on(document, 'keydown', this._onKeyDown, this); | ||
7790 | + }, | ||
7791 | + | ||
7792 | + _removeHooks: function () { | ||
7793 | + L.DomEvent.off(document, 'keydown', this._onKeyDown, this); | ||
7794 | + }, | ||
7795 | + | ||
7796 | + _onKeyDown: function (e) { | ||
7797 | + var key = e.keyCode, | ||
7798 | + map = this._map; | ||
7799 | + | ||
7800 | + if (key in this._panKeys) { | ||
7801 | + | ||
7802 | + if (map._panAnim && map._panAnim._inProgress) { return; } | ||
7803 | + | ||
7804 | + map.panBy(this._panKeys[key]); | ||
7805 | + | ||
7806 | + if (map.options.maxBounds) { | ||
7807 | + map.panInsideBounds(map.options.maxBounds); | ||
7808 | + } | ||
7809 | + | ||
7810 | + } else if (key in this._zoomKeys) { | ||
7811 | + map.setZoom(map.getZoom() + this._zoomKeys[key]); | ||
7812 | + | ||
7813 | + } else { | ||
7814 | + return; | ||
7815 | + } | ||
7816 | + | ||
7817 | + L.DomEvent.stop(e); | ||
7818 | + } | ||
7819 | +}); | ||
7820 | + | ||
7821 | +L.Map.addInitHook('addHandler', 'keyboard', L.Map.Keyboard); | ||
7822 | + | ||
7823 | + | ||
7824 | +/* | ||
7825 | + * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable. | ||
7826 | + */ | ||
7827 | + | ||
7828 | +L.Handler.MarkerDrag = L.Handler.extend({ | ||
7829 | + initialize: function (marker) { | ||
7830 | + this._marker = marker; | ||
7831 | + }, | ||
7832 | + | ||
7833 | + addHooks: function () { | ||
7834 | + var icon = this._marker._icon; | ||
7835 | + if (!this._draggable) { | ||
7836 | + this._draggable = new L.Draggable(icon, icon); | ||
7837 | + } | ||
7838 | + | ||
7839 | + this._draggable | ||
7840 | + .on('dragstart', this._onDragStart, this) | ||
7841 | + .on('drag', this._onDrag, this) | ||
7842 | + .on('dragend', this._onDragEnd, this); | ||
7843 | + this._draggable.enable(); | ||
7844 | + L.DomUtil.addClass(this._marker._icon, 'leaflet-marker-draggable'); | ||
7845 | + }, | ||
7846 | + | ||
7847 | + removeHooks: function () { | ||
7848 | + this._draggable | ||
7849 | + .off('dragstart', this._onDragStart, this) | ||
7850 | + .off('drag', this._onDrag, this) | ||
7851 | + .off('dragend', this._onDragEnd, this); | ||
7852 | + | ||
7853 | + this._draggable.disable(); | ||
7854 | + L.DomUtil.removeClass(this._marker._icon, 'leaflet-marker-draggable'); | ||
7855 | + }, | ||
7856 | + | ||
7857 | + moved: function () { | ||
7858 | + return this._draggable && this._draggable._moved; | ||
7859 | + }, | ||
7860 | + | ||
7861 | + _onDragStart: function () { | ||
7862 | + this._marker | ||
7863 | + .closePopup() | ||
7864 | + .fire('movestart') | ||
7865 | + .fire('dragstart'); | ||
7866 | + }, | ||
7867 | + | ||
7868 | + _onDrag: function () { | ||
7869 | + var marker = this._marker, | ||
7870 | + shadow = marker._shadow, | ||
7871 | + iconPos = L.DomUtil.getPosition(marker._icon), | ||
7872 | + latlng = marker._map.layerPointToLatLng(iconPos); | ||
7873 | + | ||
7874 | + // update shadow position | ||
7875 | + if (shadow) { | ||
7876 | + L.DomUtil.setPosition(shadow, iconPos); | ||
7877 | + } | ||
7878 | + | ||
7879 | + marker._latlng = latlng; | ||
7880 | + | ||
7881 | + marker | ||
7882 | + .fire('move', {latlng: latlng}) | ||
7883 | + .fire('drag'); | ||
7884 | + }, | ||
7885 | + | ||
7886 | + _onDragEnd: function (e) { | ||
7887 | + this._marker | ||
7888 | + .fire('moveend') | ||
7889 | + .fire('dragend', e); | ||
7890 | + } | ||
7891 | +}); | ||
7892 | + | ||
7893 | + | ||
7894 | +/* | ||
7895 | + * L.Control is a base class for implementing map controls. Handles positioning. | ||
7896 | + * All other controls extend from this class. | ||
7897 | + */ | ||
7898 | + | ||
7899 | +L.Control = L.Class.extend({ | ||
7900 | + options: { | ||
7901 | + position: 'topright' | ||
7902 | + }, | ||
7903 | + | ||
7904 | + initialize: function (options) { | ||
7905 | + L.setOptions(this, options); | ||
7906 | + }, | ||
7907 | + | ||
7908 | + getPosition: function () { | ||
7909 | + return this.options.position; | ||
7910 | + }, | ||
7911 | + | ||
7912 | + setPosition: function (position) { | ||
7913 | + var map = this._map; | ||
7914 | + | ||
7915 | + if (map) { | ||
7916 | + map.removeControl(this); | ||
7917 | + } | ||
7918 | + | ||
7919 | + this.options.position = position; | ||
7920 | + | ||
7921 | + if (map) { | ||
7922 | + map.addControl(this); | ||
7923 | + } | ||
7924 | + | ||
7925 | + return this; | ||
7926 | + }, | ||
7927 | + | ||
7928 | + getContainer: function () { | ||
7929 | + return this._container; | ||
7930 | + }, | ||
7931 | + | ||
7932 | + addTo: function (map) { | ||
7933 | + this._map = map; | ||
7934 | + | ||
7935 | + var container = this._container = this.onAdd(map), | ||
7936 | + pos = this.getPosition(), | ||
7937 | + corner = map._controlCorners[pos]; | ||
7938 | + | ||
7939 | + L.DomUtil.addClass(container, 'leaflet-control'); | ||
7940 | + | ||
7941 | + if (pos.indexOf('bottom') !== -1) { | ||
7942 | + corner.insertBefore(container, corner.firstChild); | ||
7943 | + } else { | ||
7944 | + corner.appendChild(container); | ||
7945 | + } | ||
7946 | + | ||
7947 | + return this; | ||
7948 | + }, | ||
7949 | + | ||
7950 | + removeFrom: function (map) { | ||
7951 | + var pos = this.getPosition(), | ||
7952 | + corner = map._controlCorners[pos]; | ||
7953 | + | ||
7954 | + corner.removeChild(this._container); | ||
7955 | + this._map = null; | ||
7956 | + | ||
7957 | + if (this.onRemove) { | ||
7958 | + this.onRemove(map); | ||
7959 | + } | ||
7960 | + | ||
7961 | + return this; | ||
7962 | + }, | ||
7963 | + | ||
7964 | + _refocusOnMap: function () { | ||
7965 | + if (this._map) { | ||
7966 | + this._map.getContainer().focus(); | ||
7967 | + } | ||
7968 | + } | ||
7969 | +}); | ||
7970 | + | ||
7971 | +L.control = function (options) { | ||
7972 | + return new L.Control(options); | ||
7973 | +}; | ||
7974 | + | ||
7975 | + | ||
7976 | +// adds control-related methods to L.Map | ||
7977 | + | ||
7978 | +L.Map.include({ | ||
7979 | + addControl: function (control) { | ||
7980 | + control.addTo(this); | ||
7981 | + return this; | ||
7982 | + }, | ||
7983 | + | ||
7984 | + removeControl: function (control) { | ||
7985 | + control.removeFrom(this); | ||
7986 | + return this; | ||
7987 | + }, | ||
7988 | + | ||
7989 | + _initControlPos: function () { | ||
7990 | + var corners = this._controlCorners = {}, | ||
7991 | + l = 'leaflet-', | ||
7992 | + container = this._controlContainer = | ||
7993 | + L.DomUtil.create('div', l + 'control-container', this._container); | ||
7994 | + | ||
7995 | + function createCorner(vSide, hSide) { | ||
7996 | + var className = l + vSide + ' ' + l + hSide; | ||
7997 | + | ||
7998 | + corners[vSide + hSide] = L.DomUtil.create('div', className, container); | ||
7999 | + } | ||
8000 | + | ||
8001 | + createCorner('top', 'left'); | ||
8002 | + createCorner('top', 'right'); | ||
8003 | + createCorner('bottom', 'left'); | ||
8004 | + createCorner('bottom', 'right'); | ||
8005 | + }, | ||
8006 | + | ||
8007 | + _clearControlPos: function () { | ||
8008 | + this._container.removeChild(this._controlContainer); | ||
8009 | + } | ||
8010 | +}); | ||
8011 | + | ||
8012 | + | ||
8013 | +/* | ||
8014 | + * L.Control.Zoom is used for the default zoom buttons on the map. | ||
8015 | + */ | ||
8016 | + | ||
8017 | +L.Control.Zoom = L.Control.extend({ | ||
8018 | + options: { | ||
8019 | + position: 'topleft', | ||
8020 | + zoomInText: '+', | ||
8021 | + zoomInTitle: 'Zoom in', | ||
8022 | + zoomOutText: '-', | ||
8023 | + zoomOutTitle: 'Zoom out' | ||
8024 | + }, | ||
8025 | + | ||
8026 | + onAdd: function (map) { | ||
8027 | + var zoomName = 'leaflet-control-zoom', | ||
8028 | + container = L.DomUtil.create('div', zoomName + ' leaflet-bar'); | ||
8029 | + | ||
8030 | + this._map = map; | ||
8031 | + | ||
8032 | + this._zoomInButton = this._createButton( | ||
8033 | + this.options.zoomInText, this.options.zoomInTitle, | ||
8034 | + zoomName + '-in', container, this._zoomIn, this); | ||
8035 | + this._zoomOutButton = this._createButton( | ||
8036 | + this.options.zoomOutText, this.options.zoomOutTitle, | ||
8037 | + zoomName + '-out', container, this._zoomOut, this); | ||
8038 | + | ||
8039 | + this._updateDisabled(); | ||
8040 | + map.on('zoomend zoomlevelschange', this._updateDisabled, this); | ||
8041 | + | ||
8042 | + return container; | ||
8043 | + }, | ||
8044 | + | ||
8045 | + onRemove: function (map) { | ||
8046 | + map.off('zoomend zoomlevelschange', this._updateDisabled, this); | ||
8047 | + }, | ||
8048 | + | ||
8049 | + _zoomIn: function (e) { | ||
8050 | + this._map.zoomIn(e.shiftKey ? 3 : 1); | ||
8051 | + }, | ||
8052 | + | ||
8053 | + _zoomOut: function (e) { | ||
8054 | + this._map.zoomOut(e.shiftKey ? 3 : 1); | ||
8055 | + }, | ||
8056 | + | ||
8057 | + _createButton: function (html, title, className, container, fn, context) { | ||
8058 | + var link = L.DomUtil.create('a', className, container); | ||
8059 | + link.innerHTML = html; | ||
8060 | + link.href = '#'; | ||
8061 | + link.title = title; | ||
8062 | + | ||
8063 | + var stop = L.DomEvent.stopPropagation; | ||
8064 | + | ||
8065 | + L.DomEvent | ||
8066 | + .on(link, 'click', stop) | ||
8067 | + .on(link, 'mousedown', stop) | ||
8068 | + .on(link, 'dblclick', stop) | ||
8069 | + .on(link, 'click', L.DomEvent.preventDefault) | ||
8070 | + .on(link, 'click', fn, context) | ||
8071 | + .on(link, 'click', this._refocusOnMap, context); | ||
8072 | + | ||
8073 | + return link; | ||
8074 | + }, | ||
8075 | + | ||
8076 | + _updateDisabled: function () { | ||
8077 | + var map = this._map, | ||
8078 | + className = 'leaflet-disabled'; | ||
8079 | + | ||
8080 | + L.DomUtil.removeClass(this._zoomInButton, className); | ||
8081 | + L.DomUtil.removeClass(this._zoomOutButton, className); | ||
8082 | + | ||
8083 | + if (map._zoom === map.getMinZoom()) { | ||
8084 | + L.DomUtil.addClass(this._zoomOutButton, className); | ||
8085 | + } | ||
8086 | + if (map._zoom === map.getMaxZoom()) { | ||
8087 | + L.DomUtil.addClass(this._zoomInButton, className); | ||
8088 | + } | ||
8089 | + } | ||
8090 | +}); | ||
8091 | + | ||
8092 | +L.Map.mergeOptions({ | ||
8093 | + zoomControl: true | ||
8094 | +}); | ||
8095 | + | ||
8096 | +L.Map.addInitHook(function () { | ||
8097 | + if (this.options.zoomControl) { | ||
8098 | + this.zoomControl = new L.Control.Zoom(); | ||
8099 | + this.addControl(this.zoomControl); | ||
8100 | + } | ||
8101 | +}); | ||
8102 | + | ||
8103 | +L.control.zoom = function (options) { | ||
8104 | + return new L.Control.Zoom(options); | ||
8105 | +}; | ||
8106 | + | ||
8107 | + | ||
8108 | + | ||
8109 | +/* | ||
8110 | + * L.Control.Attribution is used for displaying attribution on the map (added by default). | ||
8111 | + */ | ||
8112 | + | ||
8113 | +L.Control.Attribution = L.Control.extend({ | ||
8114 | + options: { | ||
8115 | + position: 'bottomright', | ||
8116 | + prefix: '<a href="http://leafletjs.com" title="A JS library for interactive maps">Leaflet</a>' | ||
8117 | + }, | ||
8118 | + | ||
8119 | + initialize: function (options) { | ||
8120 | + L.setOptions(this, options); | ||
8121 | + | ||
8122 | + this._attributions = {}; | ||
8123 | + }, | ||
8124 | + | ||
8125 | + onAdd: function (map) { | ||
8126 | + this._container = L.DomUtil.create('div', 'leaflet-control-attribution'); | ||
8127 | + L.DomEvent.disableClickPropagation(this._container); | ||
8128 | + | ||
8129 | + for (var i in map._layers) { | ||
8130 | + if (map._layers[i].getAttribution) { | ||
8131 | + this.addAttribution(map._layers[i].getAttribution()); | ||
8132 | + } | ||
8133 | + } | ||
8134 | + | ||
8135 | + map | ||
8136 | + .on('layeradd', this._onLayerAdd, this) | ||
8137 | + .on('layerremove', this._onLayerRemove, this); | ||
8138 | + | ||
8139 | + this._update(); | ||
8140 | + | ||
8141 | + return this._container; | ||
8142 | + }, | ||
8143 | + | ||
8144 | + onRemove: function (map) { | ||
8145 | + map | ||
8146 | + .off('layeradd', this._onLayerAdd) | ||
8147 | + .off('layerremove', this._onLayerRemove); | ||
8148 | + | ||
8149 | + }, | ||
8150 | + | ||
8151 | + setPrefix: function (prefix) { | ||
8152 | + this.options.prefix = prefix; | ||
8153 | + this._update(); | ||
8154 | + return this; | ||
8155 | + }, | ||
8156 | + | ||
8157 | + addAttribution: function (text) { | ||
8158 | + if (!text) { return; } | ||
8159 | + | ||
8160 | + if (!this._attributions[text]) { | ||
8161 | + this._attributions[text] = 0; | ||
8162 | + } | ||
8163 | + this._attributions[text]++; | ||
8164 | + | ||
8165 | + this._update(); | ||
8166 | + | ||
8167 | + return this; | ||
8168 | + }, | ||
8169 | + | ||
8170 | + removeAttribution: function (text) { | ||
8171 | + if (!text) { return; } | ||
8172 | + | ||
8173 | + if (this._attributions[text]) { | ||
8174 | + this._attributions[text]--; | ||
8175 | + this._update(); | ||
8176 | + } | ||
8177 | + | ||
8178 | + return this; | ||
8179 | + }, | ||
8180 | + | ||
8181 | + _update: function () { | ||
8182 | + if (!this._map) { return; } | ||
8183 | + | ||
8184 | + var attribs = []; | ||
8185 | + | ||
8186 | + for (var i in this._attributions) { | ||
8187 | + if (this._attributions[i]) { | ||
8188 | + attribs.push(i); | ||
8189 | + } | ||
8190 | + } | ||
8191 | + | ||
8192 | + var prefixAndAttribs = []; | ||
8193 | + | ||
8194 | + if (this.options.prefix) { | ||
8195 | + prefixAndAttribs.push(this.options.prefix); | ||
8196 | + } | ||
8197 | + if (attribs.length) { | ||
8198 | + prefixAndAttribs.push(attribs.join(', ')); | ||
8199 | + } | ||
8200 | + | ||
8201 | + this._container.innerHTML = prefixAndAttribs.join(' | '); | ||
8202 | + }, | ||
8203 | + | ||
8204 | + _onLayerAdd: function (e) { | ||
8205 | + if (e.layer.getAttribution) { | ||
8206 | + this.addAttribution(e.layer.getAttribution()); | ||
8207 | + } | ||
8208 | + }, | ||
8209 | + | ||
8210 | + _onLayerRemove: function (e) { | ||
8211 | + if (e.layer.getAttribution) { | ||
8212 | + this.removeAttribution(e.layer.getAttribution()); | ||
8213 | + } | ||
8214 | + } | ||
8215 | +}); | ||
8216 | + | ||
8217 | +L.Map.mergeOptions({ | ||
8218 | + attributionControl: true | ||
8219 | +}); | ||
8220 | + | ||
8221 | +L.Map.addInitHook(function () { | ||
8222 | + if (this.options.attributionControl) { | ||
8223 | + this.attributionControl = (new L.Control.Attribution()).addTo(this); | ||
8224 | + } | ||
8225 | +}); | ||
8226 | + | ||
8227 | +L.control.attribution = function (options) { | ||
8228 | + return new L.Control.Attribution(options); | ||
8229 | +}; | ||
8230 | + | ||
8231 | + | ||
8232 | +/* | ||
8233 | + * L.Control.Scale is used for displaying metric/imperial scale on the map. | ||
8234 | + */ | ||
8235 | + | ||
8236 | +L.Control.Scale = L.Control.extend({ | ||
8237 | + options: { | ||
8238 | + position: 'bottomleft', | ||
8239 | + maxWidth: 100, | ||
8240 | + metric: true, | ||
8241 | + imperial: true, | ||
8242 | + updateWhenIdle: false | ||
8243 | + }, | ||
8244 | + | ||
8245 | + onAdd: function (map) { | ||
8246 | + this._map = map; | ||
8247 | + | ||
8248 | + var className = 'leaflet-control-scale', | ||
8249 | + container = L.DomUtil.create('div', className), | ||
8250 | + options = this.options; | ||
8251 | + | ||
8252 | + this._addScales(options, className, container); | ||
8253 | + | ||
8254 | + map.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this); | ||
8255 | + map.whenReady(this._update, this); | ||
8256 | + | ||
8257 | + return container; | ||
8258 | + }, | ||
8259 | + | ||
8260 | + onRemove: function (map) { | ||
8261 | + map.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this); | ||
8262 | + }, | ||
8263 | + | ||
8264 | + _addScales: function (options, className, container) { | ||
8265 | + if (options.metric) { | ||
8266 | + this._mScale = L.DomUtil.create('div', className + '-line', container); | ||
8267 | + } | ||
8268 | + if (options.imperial) { | ||
8269 | + this._iScale = L.DomUtil.create('div', className + '-line', container); | ||
8270 | + } | ||
8271 | + }, | ||
8272 | + | ||
8273 | + _update: function () { | ||
8274 | + var bounds = this._map.getBounds(), | ||
8275 | + centerLat = bounds.getCenter().lat, | ||
8276 | + halfWorldMeters = 6378137 * Math.PI * Math.cos(centerLat * Math.PI / 180), | ||
8277 | + dist = halfWorldMeters * (bounds.getNorthEast().lng - bounds.getSouthWest().lng) / 180, | ||
8278 | + | ||
8279 | + size = this._map.getSize(), | ||
8280 | + options = this.options, | ||
8281 | + maxMeters = 0; | ||
8282 | + | ||
8283 | + if (size.x > 0) { | ||
8284 | + maxMeters = dist * (options.maxWidth / size.x); | ||
8285 | + } | ||
8286 | + | ||
8287 | + this._updateScales(options, maxMeters); | ||
8288 | + }, | ||
8289 | + | ||
8290 | + _updateScales: function (options, maxMeters) { | ||
8291 | + if (options.metric && maxMeters) { | ||
8292 | + this._updateMetric(maxMeters); | ||
8293 | + } | ||
8294 | + | ||
8295 | + if (options.imperial && maxMeters) { | ||
8296 | + this._updateImperial(maxMeters); | ||
8297 | + } | ||
8298 | + }, | ||
8299 | + | ||
8300 | + _updateMetric: function (maxMeters) { | ||
8301 | + var meters = this._getRoundNum(maxMeters); | ||
8302 | + | ||
8303 | + this._mScale.style.width = this._getScaleWidth(meters / maxMeters) + 'px'; | ||
8304 | + this._mScale.innerHTML = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km'; | ||
8305 | + }, | ||
8306 | + | ||
8307 | + _updateImperial: function (maxMeters) { | ||
8308 | + var maxFeet = maxMeters * 3.2808399, | ||
8309 | + scale = this._iScale, | ||
8310 | + maxMiles, miles, feet; | ||
8311 | + | ||
8312 | + if (maxFeet > 5280) { | ||
8313 | + maxMiles = maxFeet / 5280; | ||
8314 | + miles = this._getRoundNum(maxMiles); | ||
8315 | + | ||
8316 | + scale.style.width = this._getScaleWidth(miles / maxMiles) + 'px'; | ||
8317 | + scale.innerHTML = miles + ' mi'; | ||
8318 | + | ||
8319 | + } else { | ||
8320 | + feet = this._getRoundNum(maxFeet); | ||
8321 | + | ||
8322 | + scale.style.width = this._getScaleWidth(feet / maxFeet) + 'px'; | ||
8323 | + scale.innerHTML = feet + ' ft'; | ||
8324 | + } | ||
8325 | + }, | ||
8326 | + | ||
8327 | + _getScaleWidth: function (ratio) { | ||
8328 | + return Math.round(this.options.maxWidth * ratio) - 10; | ||
8329 | + }, | ||
8330 | + | ||
8331 | + _getRoundNum: function (num) { | ||
8332 | + var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1), | ||
8333 | + d = num / pow10; | ||
8334 | + | ||
8335 | + d = d >= 10 ? 10 : d >= 5 ? 5 : d >= 3 ? 3 : d >= 2 ? 2 : 1; | ||
8336 | + | ||
8337 | + return pow10 * d; | ||
8338 | + } | ||
8339 | +}); | ||
8340 | + | ||
8341 | +L.control.scale = function (options) { | ||
8342 | + return new L.Control.Scale(options); | ||
8343 | +}; | ||
8344 | + | ||
8345 | + | ||
8346 | +/* | ||
8347 | + * L.Control.Layers is a control to allow users to switch between different layers on the map. | ||
8348 | + */ | ||
8349 | + | ||
8350 | +L.Control.Layers = L.Control.extend({ | ||
8351 | + options: { | ||
8352 | + collapsed: true, | ||
8353 | + position: 'topright', | ||
8354 | + autoZIndex: true | ||
8355 | + }, | ||
8356 | + | ||
8357 | + initialize: function (baseLayers, overlays, options) { | ||
8358 | + L.setOptions(this, options); | ||
8359 | + | ||
8360 | + this._layers = {}; | ||
8361 | + this._lastZIndex = 0; | ||
8362 | + this._handlingClick = false; | ||
8363 | + | ||
8364 | + for (var i in baseLayers) { | ||
8365 | + this._addLayer(baseLayers[i], i); | ||
8366 | + } | ||
8367 | + | ||
8368 | + for (i in overlays) { | ||
8369 | + this._addLayer(overlays[i], i, true); | ||
8370 | + } | ||
8371 | + }, | ||
8372 | + | ||
8373 | + onAdd: function (map) { | ||
8374 | + this._initLayout(); | ||
8375 | + this._update(); | ||
8376 | + | ||
8377 | + map | ||
8378 | + .on('layeradd', this._onLayerChange, this) | ||
8379 | + .on('layerremove', this._onLayerChange, this); | ||
8380 | + | ||
8381 | + return this._container; | ||
8382 | + }, | ||
8383 | + | ||
8384 | + onRemove: function (map) { | ||
8385 | + map | ||
8386 | + .off('layeradd', this._onLayerChange, this) | ||
8387 | + .off('layerremove', this._onLayerChange, this); | ||
8388 | + }, | ||
8389 | + | ||
8390 | + addBaseLayer: function (layer, name) { | ||
8391 | + this._addLayer(layer, name); | ||
8392 | + this._update(); | ||
8393 | + return this; | ||
8394 | + }, | ||
8395 | + | ||
8396 | + addOverlay: function (layer, name) { | ||
8397 | + this._addLayer(layer, name, true); | ||
8398 | + this._update(); | ||
8399 | + return this; | ||
8400 | + }, | ||
8401 | + | ||
8402 | + removeLayer: function (layer) { | ||
8403 | + var id = L.stamp(layer); | ||
8404 | + delete this._layers[id]; | ||
8405 | + this._update(); | ||
8406 | + return this; | ||
8407 | + }, | ||
8408 | + | ||
8409 | + _initLayout: function () { | ||
8410 | + var className = 'leaflet-control-layers', | ||
8411 | + container = this._container = L.DomUtil.create('div', className); | ||
8412 | + | ||
8413 | + //Makes this work on IE10 Touch devices by stopping it from firing a mouseout event when the touch is released | ||
8414 | + container.setAttribute('aria-haspopup', true); | ||
8415 | + | ||
8416 | + if (!L.Browser.touch) { | ||
8417 | + L.DomEvent | ||
8418 | + .disableClickPropagation(container) | ||
8419 | + .disableScrollPropagation(container); | ||
8420 | + } else { | ||
8421 | + L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation); | ||
8422 | + } | ||
8423 | + | ||
8424 | + var form = this._form = L.DomUtil.create('form', className + '-list'); | ||
8425 | + | ||
8426 | + if (this.options.collapsed) { | ||
8427 | + if (!L.Browser.android) { | ||
8428 | + L.DomEvent | ||
8429 | + .on(container, 'mouseover', this._expand, this) | ||
8430 | + .on(container, 'mouseout', this._collapse, this); | ||
8431 | + } | ||
8432 | + var link = this._layersLink = L.DomUtil.create('a', className + '-toggle', container); | ||
8433 | + link.href = '#'; | ||
8434 | + link.title = 'Layers'; | ||
8435 | + | ||
8436 | + if (L.Browser.touch) { | ||
8437 | + L.DomEvent | ||
8438 | + .on(link, 'click', L.DomEvent.stop) | ||
8439 | + .on(link, 'click', this._expand, this); | ||
8440 | + } | ||
8441 | + else { | ||
8442 | + L.DomEvent.on(link, 'focus', this._expand, this); | ||
8443 | + } | ||
8444 | + //Work around for Firefox android issue https://github.com/Leaflet/Leaflet/issues/2033 | ||
8445 | + L.DomEvent.on(form, 'click', function () { | ||
8446 | + setTimeout(L.bind(this._onInputClick, this), 0); | ||
8447 | + }, this); | ||
8448 | + | ||
8449 | + this._map.on('click', this._collapse, this); | ||
8450 | + // TODO keyboard accessibility | ||
8451 | + } else { | ||
8452 | + this._expand(); | ||
8453 | + } | ||
8454 | + | ||
8455 | + this._baseLayersList = L.DomUtil.create('div', className + '-base', form); | ||
8456 | + this._separator = L.DomUtil.create('div', className + '-separator', form); | ||
8457 | + this._overlaysList = L.DomUtil.create('div', className + '-overlays', form); | ||
8458 | + | ||
8459 | + container.appendChild(form); | ||
8460 | + }, | ||
8461 | + | ||
8462 | + _addLayer: function (layer, name, overlay) { | ||
8463 | + var id = L.stamp(layer); | ||
8464 | + | ||
8465 | + this._layers[id] = { | ||
8466 | + layer: layer, | ||
8467 | + name: name, | ||
8468 | + overlay: overlay | ||
8469 | + }; | ||
8470 | + | ||
8471 | + if (this.options.autoZIndex && layer.setZIndex) { | ||
8472 | + this._lastZIndex++; | ||
8473 | + layer.setZIndex(this._lastZIndex); | ||
8474 | + } | ||
8475 | + }, | ||
8476 | + | ||
8477 | + _update: function () { | ||
8478 | + if (!this._container) { | ||
8479 | + return; | ||
8480 | + } | ||
8481 | + | ||
8482 | + this._baseLayersList.innerHTML = ''; | ||
8483 | + this._overlaysList.innerHTML = ''; | ||
8484 | + | ||
8485 | + var baseLayersPresent = false, | ||
8486 | + overlaysPresent = false, | ||
8487 | + i, obj; | ||
8488 | + | ||
8489 | + for (i in this._layers) { | ||
8490 | + obj = this._layers[i]; | ||
8491 | + this._addItem(obj); | ||
8492 | + overlaysPresent = overlaysPresent || obj.overlay; | ||
8493 | + baseLayersPresent = baseLayersPresent || !obj.overlay; | ||
8494 | + } | ||
8495 | + | ||
8496 | + this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none'; | ||
8497 | + }, | ||
8498 | + | ||
8499 | + _onLayerChange: function (e) { | ||
8500 | + var obj = this._layers[L.stamp(e.layer)]; | ||
8501 | + | ||
8502 | + if (!obj) { return; } | ||
8503 | + | ||
8504 | + if (!this._handlingClick) { | ||
8505 | + this._update(); | ||
8506 | + } | ||
8507 | + | ||
8508 | + var type = obj.overlay ? | ||
8509 | + (e.type === 'layeradd' ? 'overlayadd' : 'overlayremove') : | ||
8510 | + (e.type === 'layeradd' ? 'baselayerchange' : null); | ||
8511 | + | ||
8512 | + if (type) { | ||
8513 | + this._map.fire(type, obj); | ||
8514 | + } | ||
8515 | + }, | ||
8516 | + | ||
8517 | + // IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe) | ||
8518 | + _createRadioElement: function (name, checked) { | ||
8519 | + | ||
8520 | + var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' + name + '"'; | ||
8521 | + if (checked) { | ||
8522 | + radioHtml += ' checked="checked"'; | ||
8523 | + } | ||
8524 | + radioHtml += '/>'; | ||
8525 | + | ||
8526 | + var radioFragment = document.createElement('div'); | ||
8527 | + radioFragment.innerHTML = radioHtml; | ||
8528 | + | ||
8529 | + return radioFragment.firstChild; | ||
8530 | + }, | ||
8531 | + | ||
8532 | + _addItem: function (obj) { | ||
8533 | + var label = document.createElement('label'), | ||
8534 | + input, | ||
8535 | + checked = this._map.hasLayer(obj.layer); | ||
8536 | + | ||
8537 | + if (obj.overlay) { | ||
8538 | + input = document.createElement('input'); | ||
8539 | + input.type = 'checkbox'; | ||
8540 | + input.className = 'leaflet-control-layers-selector'; | ||
8541 | + input.defaultChecked = checked; | ||
8542 | + } else { | ||
8543 | + input = this._createRadioElement('leaflet-base-layers', checked); | ||
8544 | + } | ||
8545 | + | ||
8546 | + input.layerId = L.stamp(obj.layer); | ||
8547 | + | ||
8548 | + L.DomEvent.on(input, 'click', this._onInputClick, this); | ||
8549 | + | ||
8550 | + var name = document.createElement('span'); | ||
8551 | + name.innerHTML = ' ' + obj.name; | ||
8552 | + | ||
8553 | + label.appendChild(input); | ||
8554 | + label.appendChild(name); | ||
8555 | + | ||
8556 | + var container = obj.overlay ? this._overlaysList : this._baseLayersList; | ||
8557 | + container.appendChild(label); | ||
8558 | + | ||
8559 | + return label; | ||
8560 | + }, | ||
8561 | + | ||
8562 | + _onInputClick: function () { | ||
8563 | + var i, input, obj, | ||
8564 | + inputs = this._form.getElementsByTagName('input'), | ||
8565 | + inputsLen = inputs.length; | ||
8566 | + | ||
8567 | + this._handlingClick = true; | ||
8568 | + | ||
8569 | + for (i = 0; i < inputsLen; i++) { | ||
8570 | + input = inputs[i]; | ||
8571 | + obj = this._layers[input.layerId]; | ||
8572 | + | ||
8573 | + if (input.checked && !this._map.hasLayer(obj.layer)) { | ||
8574 | + this._map.addLayer(obj.layer); | ||
8575 | + | ||
8576 | + } else if (!input.checked && this._map.hasLayer(obj.layer)) { | ||
8577 | + this._map.removeLayer(obj.layer); | ||
8578 | + } | ||
8579 | + } | ||
8580 | + | ||
8581 | + this._handlingClick = false; | ||
8582 | + | ||
8583 | + this._refocusOnMap(); | ||
8584 | + }, | ||
8585 | + | ||
8586 | + _expand: function () { | ||
8587 | + L.DomUtil.addClass(this._container, 'leaflet-control-layers-expanded'); | ||
8588 | + }, | ||
8589 | + | ||
8590 | + _collapse: function () { | ||
8591 | + this._container.className = this._container.className.replace(' leaflet-control-layers-expanded', ''); | ||
8592 | + } | ||
8593 | +}); | ||
8594 | + | ||
8595 | +L.control.layers = function (baseLayers, overlays, options) { | ||
8596 | + return new L.Control.Layers(baseLayers, overlays, options); | ||
8597 | +}; | ||
8598 | + | ||
8599 | + | ||
8600 | +/* | ||
8601 | + * L.PosAnimation is used by Leaflet internally for pan animations. | ||
8602 | + */ | ||
8603 | + | ||
8604 | +L.PosAnimation = L.Class.extend({ | ||
8605 | + includes: L.Mixin.Events, | ||
8606 | + | ||
8607 | + run: function (el, newPos, duration, easeLinearity) { // (HTMLElement, Point[, Number, Number]) | ||
8608 | + this.stop(); | ||
8609 | + | ||
8610 | + this._el = el; | ||
8611 | + this._inProgress = true; | ||
8612 | + this._newPos = newPos; | ||
8613 | + | ||
8614 | + this.fire('start'); | ||
8615 | + | ||
8616 | + el.style[L.DomUtil.TRANSITION] = 'all ' + (duration || 0.25) + | ||
8617 | + 's cubic-bezier(0,0,' + (easeLinearity || 0.5) + ',1)'; | ||
8618 | + | ||
8619 | + L.DomEvent.on(el, L.DomUtil.TRANSITION_END, this._onTransitionEnd, this); | ||
8620 | + L.DomUtil.setPosition(el, newPos); | ||
8621 | + | ||
8622 | + // toggle reflow, Chrome flickers for some reason if you don't do this | ||
8623 | + L.Util.falseFn(el.offsetWidth); | ||
8624 | + | ||
8625 | + // there's no native way to track value updates of transitioned properties, so we imitate this | ||
8626 | + this._stepTimer = setInterval(L.bind(this._onStep, this), 50); | ||
8627 | + }, | ||
8628 | + | ||
8629 | + stop: function () { | ||
8630 | + if (!this._inProgress) { return; } | ||
8631 | + | ||
8632 | + // if we just removed the transition property, the element would jump to its final position, | ||
8633 | + // so we need to make it stay at the current position | ||
8634 | + | ||
8635 | + L.DomUtil.setPosition(this._el, this._getPos()); | ||
8636 | + this._onTransitionEnd(); | ||
8637 | + L.Util.falseFn(this._el.offsetWidth); // force reflow in case we are about to start a new animation | ||
8638 | + }, | ||
8639 | + | ||
8640 | + _onStep: function () { | ||
8641 | + var stepPos = this._getPos(); | ||
8642 | + if (!stepPos) { | ||
8643 | + this._onTransitionEnd(); | ||
8644 | + return; | ||
8645 | + } | ||
8646 | + // jshint camelcase: false | ||
8647 | + // make L.DomUtil.getPosition return intermediate position value during animation | ||
8648 | + this._el._leaflet_pos = stepPos; | ||
8649 | + | ||
8650 | + this.fire('step'); | ||
8651 | + }, | ||
8652 | + | ||
8653 | + // you can't easily get intermediate values of properties animated with CSS3 Transitions, | ||
8654 | + // we need to parse computed style (in case of transform it returns matrix string) | ||
8655 | + | ||
8656 | + _transformRe: /([-+]?(?:\d*\.)?\d+)\D*, ([-+]?(?:\d*\.)?\d+)\D*\)/, | ||
8657 | + | ||
8658 | + _getPos: function () { | ||
8659 | + var left, top, matches, | ||
8660 | + el = this._el, | ||
8661 | + style = window.getComputedStyle(el); | ||
8662 | + | ||
8663 | + if (L.Browser.any3d) { | ||
8664 | + matches = style[L.DomUtil.TRANSFORM].match(this._transformRe); | ||
8665 | + if (!matches) { return; } | ||
8666 | + left = parseFloat(matches[1]); | ||
8667 | + top = parseFloat(matches[2]); | ||
8668 | + } else { | ||
8669 | + left = parseFloat(style.left); | ||
8670 | + top = parseFloat(style.top); | ||
8671 | + } | ||
8672 | + | ||
8673 | + return new L.Point(left, top, true); | ||
8674 | + }, | ||
8675 | + | ||
8676 | + _onTransitionEnd: function () { | ||
8677 | + L.DomEvent.off(this._el, L.DomUtil.TRANSITION_END, this._onTransitionEnd, this); | ||
8678 | + | ||
8679 | + if (!this._inProgress) { return; } | ||
8680 | + this._inProgress = false; | ||
8681 | + | ||
8682 | + this._el.style[L.DomUtil.TRANSITION] = ''; | ||
8683 | + | ||
8684 | + // jshint camelcase: false | ||
8685 | + // make sure L.DomUtil.getPosition returns the final position value after animation | ||
8686 | + this._el._leaflet_pos = this._newPos; | ||
8687 | + | ||
8688 | + clearInterval(this._stepTimer); | ||
8689 | + | ||
8690 | + this.fire('step').fire('end'); | ||
8691 | + } | ||
8692 | + | ||
8693 | +}); | ||
8694 | + | ||
8695 | + | ||
8696 | +/* | ||
8697 | + * Extends L.Map to handle panning animations. | ||
8698 | + */ | ||
8699 | + | ||
8700 | +L.Map.include({ | ||
8701 | + | ||
8702 | + setView: function (center, zoom, options) { | ||
8703 | + | ||
8704 | + zoom = zoom === undefined ? this._zoom : this._limitZoom(zoom); | ||
8705 | + center = this._limitCenter(L.latLng(center), zoom, this.options.maxBounds); | ||
8706 | + options = options || {}; | ||
8707 | + | ||
8708 | + if (this._panAnim) { | ||
8709 | + this._panAnim.stop(); | ||
8710 | + } | ||
8711 | + | ||
8712 | + if (this._loaded && !options.reset && options !== true) { | ||
8713 | + | ||
8714 | + if (options.animate !== undefined) { | ||
8715 | + options.zoom = L.extend({animate: options.animate}, options.zoom); | ||
8716 | + options.pan = L.extend({animate: options.animate}, options.pan); | ||
8717 | + } | ||
8718 | + | ||
8719 | + // try animating pan or zoom | ||
8720 | + var animated = (this._zoom !== zoom) ? | ||
8721 | + this._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom, options.zoom) : | ||
8722 | + this._tryAnimatedPan(center, options.pan); | ||
8723 | + | ||
8724 | + if (animated) { | ||
8725 | + // prevent resize handler call, the view will refresh after animation anyway | ||
8726 | + clearTimeout(this._sizeTimer); | ||
8727 | + return this; | ||
8728 | + } | ||
8729 | + } | ||
8730 | + | ||
8731 | + // animation didn't start, just reset the map view | ||
8732 | + this._resetView(center, zoom); | ||
8733 | + | ||
8734 | + return this; | ||
8735 | + }, | ||
8736 | + | ||
8737 | + panBy: function (offset, options) { | ||
8738 | + offset = L.point(offset).round(); | ||
8739 | + options = options || {}; | ||
8740 | + | ||
8741 | + if (!offset.x && !offset.y) { | ||
8742 | + return this; | ||
8743 | + } | ||
8744 | + | ||
8745 | + if (!this._panAnim) { | ||
8746 | + this._panAnim = new L.PosAnimation(); | ||
8747 | + | ||
8748 | + this._panAnim.on({ | ||
8749 | + 'step': this._onPanTransitionStep, | ||
8750 | + 'end': this._onPanTransitionEnd | ||
8751 | + }, this); | ||
8752 | + } | ||
8753 | + | ||
8754 | + // don't fire movestart if animating inertia | ||
8755 | + if (!options.noMoveStart) { | ||
8756 | + this.fire('movestart'); | ||
8757 | + } | ||
8758 | + | ||
8759 | + // animate pan unless animate: false specified | ||
8760 | + if (options.animate !== false) { | ||
8761 | + L.DomUtil.addClass(this._mapPane, 'leaflet-pan-anim'); | ||
8762 | + | ||
8763 | + var newPos = this._getMapPanePos().subtract(offset); | ||
8764 | + this._panAnim.run(this._mapPane, newPos, options.duration || 0.25, options.easeLinearity); | ||
8765 | + } else { | ||
8766 | + this._rawPanBy(offset); | ||
8767 | + this.fire('move').fire('moveend'); | ||
8768 | + } | ||
8769 | + | ||
8770 | + return this; | ||
8771 | + }, | ||
8772 | + | ||
8773 | + _onPanTransitionStep: function () { | ||
8774 | + this.fire('move'); | ||
8775 | + }, | ||
8776 | + | ||
8777 | + _onPanTransitionEnd: function () { | ||
8778 | + L.DomUtil.removeClass(this._mapPane, 'leaflet-pan-anim'); | ||
8779 | + this.fire('moveend'); | ||
8780 | + }, | ||
8781 | + | ||
8782 | + _tryAnimatedPan: function (center, options) { | ||
8783 | + // difference between the new and current centers in pixels | ||
8784 | + var offset = this._getCenterOffset(center)._floor(); | ||
8785 | + | ||
8786 | + // don't animate too far unless animate: true specified in options | ||
8787 | + if ((options && options.animate) !== true && !this.getSize().contains(offset)) { return false; } | ||
8788 | + | ||
8789 | + this.panBy(offset, options); | ||
8790 | + | ||
8791 | + return true; | ||
8792 | + } | ||
8793 | +}); | ||
8794 | + | ||
8795 | + | ||
8796 | +/* | ||
8797 | + * L.PosAnimation fallback implementation that powers Leaflet pan animations | ||
8798 | + * in browsers that don't support CSS3 Transitions. | ||
8799 | + */ | ||
8800 | + | ||
8801 | +L.PosAnimation = L.DomUtil.TRANSITION ? L.PosAnimation : L.PosAnimation.extend({ | ||
8802 | + | ||
8803 | + run: function (el, newPos, duration, easeLinearity) { // (HTMLElement, Point[, Number, Number]) | ||
8804 | + this.stop(); | ||
8805 | + | ||
8806 | + this._el = el; | ||
8807 | + this._inProgress = true; | ||
8808 | + this._duration = duration || 0.25; | ||
8809 | + this._easeOutPower = 1 / Math.max(easeLinearity || 0.5, 0.2); | ||
8810 | + | ||
8811 | + this._startPos = L.DomUtil.getPosition(el); | ||
8812 | + this._offset = newPos.subtract(this._startPos); | ||
8813 | + this._startTime = +new Date(); | ||
8814 | + | ||
8815 | + this.fire('start'); | ||
8816 | + | ||
8817 | + this._animate(); | ||
8818 | + }, | ||
8819 | + | ||
8820 | + stop: function () { | ||
8821 | + if (!this._inProgress) { return; } | ||
8822 | + | ||
8823 | + this._step(); | ||
8824 | + this._complete(); | ||
8825 | + }, | ||
8826 | + | ||
8827 | + _animate: function () { | ||
8828 | + // animation loop | ||
8829 | + this._animId = L.Util.requestAnimFrame(this._animate, this); | ||
8830 | + this._step(); | ||
8831 | + }, | ||
8832 | + | ||
8833 | + _step: function () { | ||
8834 | + var elapsed = (+new Date()) - this._startTime, | ||
8835 | + duration = this._duration * 1000; | ||
8836 | + | ||
8837 | + if (elapsed < duration) { | ||
8838 | + this._runFrame(this._easeOut(elapsed / duration)); | ||
8839 | + } else { | ||
8840 | + this._runFrame(1); | ||
8841 | + this._complete(); | ||
8842 | + } | ||
8843 | + }, | ||
8844 | + | ||
8845 | + _runFrame: function (progress) { | ||
8846 | + var pos = this._startPos.add(this._offset.multiplyBy(progress)); | ||
8847 | + L.DomUtil.setPosition(this._el, pos); | ||
8848 | + | ||
8849 | + this.fire('step'); | ||
8850 | + }, | ||
8851 | + | ||
8852 | + _complete: function () { | ||
8853 | + L.Util.cancelAnimFrame(this._animId); | ||
8854 | + | ||
8855 | + this._inProgress = false; | ||
8856 | + this.fire('end'); | ||
8857 | + }, | ||
8858 | + | ||
8859 | + _easeOut: function (t) { | ||
8860 | + return 1 - Math.pow(1 - t, this._easeOutPower); | ||
8861 | + } | ||
8862 | +}); | ||
8863 | + | ||
8864 | + | ||
8865 | +/* | ||
8866 | + * Extends L.Map to handle zoom animations. | ||
8867 | + */ | ||
8868 | + | ||
8869 | +L.Map.mergeOptions({ | ||
8870 | + zoomAnimation: true, | ||
8871 | + zoomAnimationThreshold: 4 | ||
8872 | +}); | ||
8873 | + | ||
8874 | +if (L.DomUtil.TRANSITION) { | ||
8875 | + | ||
8876 | + L.Map.addInitHook(function () { | ||
8877 | + // don't animate on browsers without hardware-accelerated transitions or old Android/Opera | ||
8878 | + this._zoomAnimated = this.options.zoomAnimation && L.DomUtil.TRANSITION && | ||
8879 | + L.Browser.any3d && !L.Browser.android23 && !L.Browser.mobileOpera; | ||
8880 | + | ||
8881 | + // zoom transitions run with the same duration for all layers, so if one of transitionend events | ||
8882 | + // happens after starting zoom animation (propagating to the map pane), we know that it ended globally | ||
8883 | + if (this._zoomAnimated) { | ||
8884 | + L.DomEvent.on(this._mapPane, L.DomUtil.TRANSITION_END, this._catchTransitionEnd, this); | ||
8885 | + } | ||
8886 | + }); | ||
8887 | +} | ||
8888 | + | ||
8889 | +L.Map.include(!L.DomUtil.TRANSITION ? {} : { | ||
8890 | + | ||
8891 | + _catchTransitionEnd: function (e) { | ||
8892 | + if (this._animatingZoom && e.propertyName.indexOf('transform') >= 0) { | ||
8893 | + this._onZoomTransitionEnd(); | ||
8894 | + } | ||
8895 | + }, | ||
8896 | + | ||
8897 | + _nothingToAnimate: function () { | ||
8898 | + return !this._container.getElementsByClassName('leaflet-zoom-animated').length; | ||
8899 | + }, | ||
8900 | + | ||
8901 | + _tryAnimatedZoom: function (center, zoom, options) { | ||
8902 | + | ||
8903 | + if (this._animatingZoom) { return true; } | ||
8904 | + | ||
8905 | + options = options || {}; | ||
8906 | + | ||
8907 | + // don't animate if disabled, not supported or zoom difference is too large | ||
8908 | + if (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() || | ||
8909 | + Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; } | ||
8910 | + | ||
8911 | + // offset is the pixel coords of the zoom origin relative to the current center | ||
8912 | + var scale = this.getZoomScale(zoom), | ||
8913 | + offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale), | ||
8914 | + origin = this._getCenterLayerPoint()._add(offset); | ||
8915 | + | ||
8916 | + // don't animate if the zoom origin isn't within one screen from the current center, unless forced | ||
8917 | + if (options.animate !== true && !this.getSize().contains(offset)) { return false; } | ||
8918 | + | ||
8919 | + this | ||
8920 | + .fire('movestart') | ||
8921 | + .fire('zoomstart'); | ||
8922 | + | ||
8923 | + this._animateZoom(center, zoom, origin, scale, null, true); | ||
8924 | + | ||
8925 | + return true; | ||
8926 | + }, | ||
8927 | + | ||
8928 | + _animateZoom: function (center, zoom, origin, scale, delta, backwards, forTouchZoom) { | ||
8929 | + | ||
8930 | + if (!forTouchZoom) { | ||
8931 | + this._animatingZoom = true; | ||
8932 | + } | ||
8933 | + | ||
8934 | + // put transform transition on all layers with leaflet-zoom-animated class | ||
8935 | + L.DomUtil.addClass(this._mapPane, 'leaflet-zoom-anim'); | ||
8936 | + | ||
8937 | + // remember what center/zoom to set after animation | ||
8938 | + this._animateToCenter = center; | ||
8939 | + this._animateToZoom = zoom; | ||
8940 | + | ||
8941 | + // disable any dragging during animation | ||
8942 | + if (L.Draggable) { | ||
8943 | + L.Draggable._disabled = true; | ||
8944 | + } | ||
8945 | + | ||
8946 | + L.Util.requestAnimFrame(function () { | ||
8947 | + this.fire('zoomanim', { | ||
8948 | + center: center, | ||
8949 | + zoom: zoom, | ||
8950 | + origin: origin, | ||
8951 | + scale: scale, | ||
8952 | + delta: delta, | ||
8953 | + backwards: backwards | ||
8954 | + }); | ||
8955 | + }, this); | ||
8956 | + }, | ||
8957 | + | ||
8958 | + _onZoomTransitionEnd: function () { | ||
8959 | + | ||
8960 | + this._animatingZoom = false; | ||
8961 | + | ||
8962 | + L.DomUtil.removeClass(this._mapPane, 'leaflet-zoom-anim'); | ||
8963 | + | ||
8964 | + this._resetView(this._animateToCenter, this._animateToZoom, true, true); | ||
8965 | + | ||
8966 | + if (L.Draggable) { | ||
8967 | + L.Draggable._disabled = false; | ||
8968 | + } | ||
8969 | + } | ||
8970 | +}); | ||
8971 | + | ||
8972 | + | ||
8973 | +/* | ||
8974 | + Zoom animation logic for L.TileLayer. | ||
8975 | +*/ | ||
8976 | + | ||
8977 | +L.TileLayer.include({ | ||
8978 | + _animateZoom: function (e) { | ||
8979 | + if (!this._animating) { | ||
8980 | + this._animating = true; | ||
8981 | + this._prepareBgBuffer(); | ||
8982 | + } | ||
8983 | + | ||
8984 | + var bg = this._bgBuffer, | ||
8985 | + transform = L.DomUtil.TRANSFORM, | ||
8986 | + initialTransform = e.delta ? L.DomUtil.getTranslateString(e.delta) : bg.style[transform], | ||
8987 | + scaleStr = L.DomUtil.getScaleString(e.scale, e.origin); | ||
8988 | + | ||
8989 | + bg.style[transform] = e.backwards ? | ||
8990 | + scaleStr + ' ' + initialTransform : | ||
8991 | + initialTransform + ' ' + scaleStr; | ||
8992 | + }, | ||
8993 | + | ||
8994 | + _endZoomAnim: function () { | ||
8995 | + var front = this._tileContainer, | ||
8996 | + bg = this._bgBuffer; | ||
8997 | + | ||
8998 | + front.style.visibility = ''; | ||
8999 | + front.parentNode.appendChild(front); // Bring to fore | ||
9000 | + | ||
9001 | + // force reflow | ||
9002 | + L.Util.falseFn(bg.offsetWidth); | ||
9003 | + | ||
9004 | + this._animating = false; | ||
9005 | + }, | ||
9006 | + | ||
9007 | + _clearBgBuffer: function () { | ||
9008 | + var map = this._map; | ||
9009 | + | ||
9010 | + if (map && !map._animatingZoom && !map.touchZoom._zooming) { | ||
9011 | + this._bgBuffer.innerHTML = ''; | ||
9012 | + this._bgBuffer.style[L.DomUtil.TRANSFORM] = ''; | ||
9013 | + } | ||
9014 | + }, | ||
9015 | + | ||
9016 | + _prepareBgBuffer: function () { | ||
9017 | + | ||
9018 | + var front = this._tileContainer, | ||
9019 | + bg = this._bgBuffer; | ||
9020 | + | ||
9021 | + // if foreground layer doesn't have many tiles but bg layer does, | ||
9022 | + // keep the existing bg layer and just zoom it some more | ||
9023 | + | ||
9024 | + var bgLoaded = this._getLoadedTilesPercentage(bg), | ||
9025 | + frontLoaded = this._getLoadedTilesPercentage(front); | ||
9026 | + | ||
9027 | + if (bg && bgLoaded > 0.5 && frontLoaded < 0.5) { | ||
9028 | + | ||
9029 | + front.style.visibility = 'hidden'; | ||
9030 | + this._stopLoadingImages(front); | ||
9031 | + return; | ||
9032 | + } | ||
9033 | + | ||
9034 | + // prepare the buffer to become the front tile pane | ||
9035 | + bg.style.visibility = 'hidden'; | ||
9036 | + bg.style[L.DomUtil.TRANSFORM] = ''; | ||
9037 | + | ||
9038 | + // switch out the current layer to be the new bg layer (and vice-versa) | ||
9039 | + this._tileContainer = bg; | ||
9040 | + bg = this._bgBuffer = front; | ||
9041 | + | ||
9042 | + this._stopLoadingImages(bg); | ||
9043 | + | ||
9044 | + //prevent bg buffer from clearing right after zoom | ||
9045 | + clearTimeout(this._clearBgBufferTimer); | ||
9046 | + }, | ||
9047 | + | ||
9048 | + _getLoadedTilesPercentage: function (container) { | ||
9049 | + var tiles = container.getElementsByTagName('img'), | ||
9050 | + i, len, count = 0; | ||
9051 | + | ||
9052 | + for (i = 0, len = tiles.length; i < len; i++) { | ||
9053 | + if (tiles[i].complete) { | ||
9054 | + count++; | ||
9055 | + } | ||
9056 | + } | ||
9057 | + return count / len; | ||
9058 | + }, | ||
9059 | + | ||
9060 | + // stops loading all tiles in the background layer | ||
9061 | + _stopLoadingImages: function (container) { | ||
9062 | + var tiles = Array.prototype.slice.call(container.getElementsByTagName('img')), | ||
9063 | + i, len, tile; | ||
9064 | + | ||
9065 | + for (i = 0, len = tiles.length; i < len; i++) { | ||
9066 | + tile = tiles[i]; | ||
9067 | + | ||
9068 | + if (!tile.complete) { | ||
9069 | + tile.onload = L.Util.falseFn; | ||
9070 | + tile.onerror = L.Util.falseFn; | ||
9071 | + tile.src = L.Util.emptyImageUrl; | ||
9072 | + | ||
9073 | + tile.parentNode.removeChild(tile); | ||
9074 | + } | ||
9075 | + } | ||
9076 | + } | ||
9077 | +}); | ||
9078 | + | ||
9079 | + | ||
9080 | +/* | ||
9081 | + * Provides L.Map with convenient shortcuts for using browser geolocation features. | ||
9082 | + */ | ||
9083 | + | ||
9084 | +L.Map.include({ | ||
9085 | + _defaultLocateOptions: { | ||
9086 | + watch: false, | ||
9087 | + setView: false, | ||
9088 | + maxZoom: Infinity, | ||
9089 | + timeout: 10000, | ||
9090 | + maximumAge: 0, | ||
9091 | + enableHighAccuracy: false | ||
9092 | + }, | ||
9093 | + | ||
9094 | + locate: function (/*Object*/ options) { | ||
9095 | + | ||
9096 | + options = this._locateOptions = L.extend(this._defaultLocateOptions, options); | ||
9097 | + | ||
9098 | + if (!navigator.geolocation) { | ||
9099 | + this._handleGeolocationError({ | ||
9100 | + code: 0, | ||
9101 | + message: 'Geolocation not supported.' | ||
9102 | + }); | ||
9103 | + return this; | ||
9104 | + } | ||
9105 | + | ||
9106 | + var onResponse = L.bind(this._handleGeolocationResponse, this), | ||
9107 | + onError = L.bind(this._handleGeolocationError, this); | ||
9108 | + | ||
9109 | + if (options.watch) { | ||
9110 | + this._locationWatchId = | ||
9111 | + navigator.geolocation.watchPosition(onResponse, onError, options); | ||
9112 | + } else { | ||
9113 | + navigator.geolocation.getCurrentPosition(onResponse, onError, options); | ||
9114 | + } | ||
9115 | + return this; | ||
9116 | + }, | ||
9117 | + | ||
9118 | + stopLocate: function () { | ||
9119 | + if (navigator.geolocation) { | ||
9120 | + navigator.geolocation.clearWatch(this._locationWatchId); | ||
9121 | + } | ||
9122 | + if (this._locateOptions) { | ||
9123 | + this._locateOptions.setView = false; | ||
9124 | + } | ||
9125 | + return this; | ||
9126 | + }, | ||
9127 | + | ||
9128 | + _handleGeolocationError: function (error) { | ||
9129 | + var c = error.code, | ||
9130 | + message = error.message || | ||
9131 | + (c === 1 ? 'permission denied' : | ||
9132 | + (c === 2 ? 'position unavailable' : 'timeout')); | ||
9133 | + | ||
9134 | + if (this._locateOptions.setView && !this._loaded) { | ||
9135 | + this.fitWorld(); | ||
9136 | + } | ||
9137 | + | ||
9138 | + this.fire('locationerror', { | ||
9139 | + code: c, | ||
9140 | + message: 'Geolocation error: ' + message + '.' | ||
9141 | + }); | ||
9142 | + }, | ||
9143 | + | ||
9144 | + _handleGeolocationResponse: function (pos) { | ||
9145 | + var lat = pos.coords.latitude, | ||
9146 | + lng = pos.coords.longitude, | ||
9147 | + latlng = new L.LatLng(lat, lng), | ||
9148 | + | ||
9149 | + latAccuracy = 180 * pos.coords.accuracy / 40075017, | ||
9150 | + lngAccuracy = latAccuracy / Math.cos(L.LatLng.DEG_TO_RAD * lat), | ||
9151 | + | ||
9152 | + bounds = L.latLngBounds( | ||
9153 | + [lat - latAccuracy, lng - lngAccuracy], | ||
9154 | + [lat + latAccuracy, lng + lngAccuracy]), | ||
9155 | + | ||
9156 | + options = this._locateOptions; | ||
9157 | + | ||
9158 | + if (options.setView) { | ||
9159 | + var zoom = Math.min(this.getBoundsZoom(bounds), options.maxZoom); | ||
9160 | + this.setView(latlng, zoom); | ||
9161 | + } | ||
9162 | + | ||
9163 | + var data = { | ||
9164 | + latlng: latlng, | ||
9165 | + bounds: bounds, | ||
9166 | + timestamp: pos.timestamp | ||
9167 | + }; | ||
9168 | + | ||
9169 | + for (var i in pos.coords) { | ||
9170 | + if (typeof pos.coords[i] === 'number') { | ||
9171 | + data[i] = pos.coords[i]; | ||
9172 | + } | ||
9173 | + } | ||
9174 | + | ||
9175 | + this.fire('locationfound', data); | ||
9176 | + } | ||
9177 | +}); | ||
9178 | + | ||
9179 | + | ||
9180 | +}(window, document)); | ||
0 | \ No newline at end of file | 9181 | \ No newline at end of file |
datalets/leafletjs-geojson-datalet/leafletsjs/leaflet.css
0 โ 100755
1 | +/* required styles */ | ||
2 | + | ||
3 | + .leaflet-map-pane, | ||
4 | +.leaflet-tile, | ||
5 | +.leaflet-marker-icon, | ||
6 | +.leaflet-marker-shadow, | ||
7 | +.leaflet-tile-pane, | ||
8 | +.leaflet-tile-container, | ||
9 | +.leaflet-overlay-pane, | ||
10 | +.leaflet-shadow-pane, | ||
11 | +.leaflet-marker-pane, | ||
12 | +.leaflet-popup-pane, | ||
13 | +.leaflet-overlay-pane svg, | ||
14 | +.leaflet-zoom-box, | ||
15 | +.leaflet-image-layer, | ||
16 | +.leaflet-layer { | ||
17 | + position: absolute; | ||
18 | + left: 0; | ||
19 | + top: 0; | ||
20 | + } | ||
21 | + .leaflet-container { | ||
22 | + overflow: hidden; | ||
23 | + -ms-touch-action: none; | ||
24 | + } | ||
25 | +.leaflet-tile, | ||
26 | +.leaflet-marker-icon, | ||
27 | +.leaflet-marker-shadow { | ||
28 | + -webkit-user-select: none; | ||
29 | + -moz-user-select: none; | ||
30 | + user-select: none; | ||
31 | + -webkit-user-drag: none; | ||
32 | + } | ||
33 | +.leaflet-marker-icon, | ||
34 | +.leaflet-marker-shadow { | ||
35 | + display: block; | ||
36 | + } | ||
37 | +/* map is broken in FF if you have max-width: 100% on tiles */ | ||
38 | +.leaflet-container img { | ||
39 | + max-width: none !important; | ||
40 | + } | ||
41 | +/* stupid Android 2 doesn't understand "max-width: none" properly */ | ||
42 | +.leaflet-container img.leaflet-image-layer { | ||
43 | + max-width: 15000px !important; | ||
44 | + } | ||
45 | +.leaflet-tile { | ||
46 | + filter: inherit; | ||
47 | + visibility: hidden; | ||
48 | + } | ||
49 | +.leaflet-tile-loaded { | ||
50 | + visibility: inherit; | ||
51 | + } | ||
52 | +.leaflet-zoom-box { | ||
53 | + width: 0; | ||
54 | + height: 0; | ||
55 | + } | ||
56 | +/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */ | ||
57 | +.leaflet-overlay-pane svg { | ||
58 | + -moz-user-select: none; | ||
59 | + } | ||
60 | +.leaflet-tile-pane { z-index: 2; } | ||
61 | +.leaflet-objects-pane { z-index: 3; } | ||
62 | +.leaflet-overlay-pane { z-index: 4; } | ||
63 | +.leaflet-shadow-pane { z-index: 5; } | ||
64 | +.leaflet-marker-pane { z-index: 6; } | ||
65 | +.leaflet-popup-pane { z-index: 7; } | ||
66 | + | ||
67 | +.leaflet-vml-shape { | ||
68 | + width: 1px; | ||
69 | + height: 1px; | ||
70 | + } | ||
71 | +.lvml { | ||
72 | + behavior: url(#default#VML); | ||
73 | + display: inline-block; | ||
74 | + position: absolute; | ||
75 | + } | ||
76 | + | ||
77 | + | ||
78 | +/* control positioning */ | ||
79 | + | ||
80 | +.leaflet-control { | ||
81 | + position: relative; | ||
82 | + z-index: 7; | ||
83 | + pointer-events: auto; | ||
84 | + } | ||
85 | +.leaflet-top, | ||
86 | +.leaflet-bottom { | ||
87 | + position: absolute; | ||
88 | + /*z-index: 1000;*/ | ||
89 | + pointer-events: none; | ||
90 | + } | ||
91 | +.leaflet-top { | ||
92 | + top: 0; | ||
93 | + } | ||
94 | +.leaflet-right { | ||
95 | + right: 0; | ||
96 | + } | ||
97 | +.leaflet-bottom { | ||
98 | + bottom: 0; | ||
99 | + } | ||
100 | +.leaflet-left { | ||
101 | + left: 0; | ||
102 | + } | ||
103 | +.leaflet-control { | ||
104 | + float: left; | ||
105 | + clear: both; | ||
106 | + } | ||
107 | +.leaflet-right .leaflet-control { | ||
108 | + float: right; | ||
109 | + } | ||
110 | +.leaflet-top .leaflet-control { | ||
111 | + margin-top: 10px; | ||
112 | + } | ||
113 | +.leaflet-bottom .leaflet-control { | ||
114 | + margin-bottom: 10px; | ||
115 | + } | ||
116 | +.leaflet-left .leaflet-control { | ||
117 | + margin-left: 10px; | ||
118 | + } | ||
119 | +.leaflet-right .leaflet-control { | ||
120 | + margin-right: 10px; | ||
121 | + } | ||
122 | + | ||
123 | + | ||
124 | +/* zoom and fade animations */ | ||
125 | + | ||
126 | +.leaflet-fade-anim .leaflet-tile, | ||
127 | +.leaflet-fade-anim .leaflet-popup { | ||
128 | + opacity: 0; | ||
129 | + -webkit-transition: opacity 0.2s linear; | ||
130 | + -moz-transition: opacity 0.2s linear; | ||
131 | + -o-transition: opacity 0.2s linear; | ||
132 | + transition: opacity 0.2s linear; | ||
133 | + } | ||
134 | +.leaflet-fade-anim .leaflet-tile-loaded, | ||
135 | +.leaflet-fade-anim .leaflet-map-pane .leaflet-popup { | ||
136 | + opacity: 1; | ||
137 | + } | ||
138 | + | ||
139 | +.leaflet-zoom-anim .leaflet-zoom-animated { | ||
140 | + -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); | ||
141 | + -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); | ||
142 | + -o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1); | ||
143 | + transition: transform 0.25s cubic-bezier(0,0,0.25,1); | ||
144 | + } | ||
145 | +.leaflet-zoom-anim .leaflet-tile, | ||
146 | +.leaflet-pan-anim .leaflet-tile, | ||
147 | +.leaflet-touching .leaflet-zoom-animated { | ||
148 | + -webkit-transition: none; | ||
149 | + -moz-transition: none; | ||
150 | + -o-transition: none; | ||
151 | + transition: none; | ||
152 | + } | ||
153 | + | ||
154 | +.leaflet-zoom-anim .leaflet-zoom-hide { | ||
155 | + visibility: hidden; | ||
156 | + } | ||
157 | + | ||
158 | + | ||
159 | +/* cursors */ | ||
160 | + | ||
161 | +.leaflet-clickable { | ||
162 | + cursor: pointer; | ||
163 | + } | ||
164 | +.leaflet-container { | ||
165 | + cursor: -webkit-grab; | ||
166 | + cursor: -moz-grab; | ||
167 | + } | ||
168 | +.leaflet-popup-pane, | ||
169 | +.leaflet-control { | ||
170 | + cursor: auto; | ||
171 | + } | ||
172 | +.leaflet-dragging .leaflet-container, | ||
173 | +.leaflet-dragging .leaflet-clickable { | ||
174 | + cursor: move; | ||
175 | + cursor: -webkit-grabbing; | ||
176 | + cursor: -moz-grabbing; | ||
177 | + } | ||
178 | + | ||
179 | + | ||
180 | +/* visual tweaks */ | ||
181 | + | ||
182 | +.leaflet-container { | ||
183 | + background: #ddd; | ||
184 | + outline: 0; | ||
185 | + } | ||
186 | +.leaflet-container a { | ||
187 | + color: #0078A8; | ||
188 | + } | ||
189 | +.leaflet-container a.leaflet-active { | ||
190 | + outline: 2px solid orange; | ||
191 | + } | ||
192 | +.leaflet-zoom-box { | ||
193 | + border: 2px dotted #38f; | ||
194 | + background: rgba(255,255,255,0.5); | ||
195 | + } | ||
196 | + | ||
197 | + | ||
198 | +/* general typography */ | ||
199 | +.leaflet-container { | ||
200 | + font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; | ||
201 | + } | ||
202 | + | ||
203 | + | ||
204 | +/* general toolbar styles */ | ||
205 | + | ||
206 | +.leaflet-bar { | ||
207 | + box-shadow: 0 1px 5px rgba(0,0,0,0.65); | ||
208 | + border-radius: 4px; | ||
209 | + } | ||
210 | +.leaflet-bar a, | ||
211 | +.leaflet-bar a:hover { | ||
212 | + background-color: #fff; | ||
213 | + border-bottom: 1px solid #ccc; | ||
214 | + width: 26px; | ||
215 | + height: 26px; | ||
216 | + line-height: 26px; | ||
217 | + display: block; | ||
218 | + text-align: center; | ||
219 | + text-decoration: none; | ||
220 | + color: black; | ||
221 | + } | ||
222 | +.leaflet-bar a, | ||
223 | +.leaflet-control-layers-toggle { | ||
224 | + background-position: 50% 50%; | ||
225 | + background-repeat: no-repeat; | ||
226 | + display: block; | ||
227 | + } | ||
228 | +.leaflet-bar a:hover { | ||
229 | + background-color: #f4f4f4; | ||
230 | + } | ||
231 | +.leaflet-bar a:first-child { | ||
232 | + border-top-left-radius: 4px; | ||
233 | + border-top-right-radius: 4px; | ||
234 | + } | ||
235 | +.leaflet-bar a:last-child { | ||
236 | + border-bottom-left-radius: 4px; | ||
237 | + border-bottom-right-radius: 4px; | ||
238 | + border-bottom: none; | ||
239 | + } | ||
240 | +.leaflet-bar a.leaflet-disabled { | ||
241 | + cursor: default; | ||
242 | + background-color: #f4f4f4; | ||
243 | + color: #bbb; | ||
244 | + } | ||
245 | + | ||
246 | +.leaflet-touch .leaflet-bar a { | ||
247 | + width: 30px; | ||
248 | + height: 30px; | ||
249 | + line-height: 30px; | ||
250 | + } | ||
251 | + | ||
252 | + | ||
253 | +/* zoom control */ | ||
254 | + | ||
255 | +.leaflet-control-zoom-in, | ||
256 | +.leaflet-control-zoom-out { | ||
257 | + font: bold 18px 'Lucida Console', Monaco, monospace; | ||
258 | + text-indent: 1px; | ||
259 | + } | ||
260 | +.leaflet-control-zoom-out { | ||
261 | + font-size: 20px; | ||
262 | + } | ||
263 | + | ||
264 | +.leaflet-touch .leaflet-control-zoom-in { | ||
265 | + font-size: 22px; | ||
266 | + } | ||
267 | +.leaflet-touch .leaflet-control-zoom-out { | ||
268 | + font-size: 24px; | ||
269 | + } | ||
270 | + | ||
271 | + | ||
272 | +/* layers control */ | ||
273 | + | ||
274 | +.leaflet-control-layers { | ||
275 | + box-shadow: 0 1px 5px rgba(0,0,0,0.4); | ||
276 | + background: #fff; | ||
277 | + border-radius: 5px; | ||
278 | + } | ||
279 | +.leaflet-control-layers-toggle { | ||
280 | + background-image: url(images/layers.png); | ||
281 | + width: 36px; | ||
282 | + height: 36px; | ||
283 | + } | ||
284 | +.leaflet-retina .leaflet-control-layers-toggle { | ||
285 | + background-image: url(images/layers-2x.png); | ||
286 | + background-size: 26px 26px; | ||
287 | + } | ||
288 | +.leaflet-touch .leaflet-control-layers-toggle { | ||
289 | + width: 44px; | ||
290 | + height: 44px; | ||
291 | + } | ||
292 | +.leaflet-control-layers .leaflet-control-layers-list, | ||
293 | +.leaflet-control-layers-expanded .leaflet-control-layers-toggle { | ||
294 | + display: none; | ||
295 | + } | ||
296 | +.leaflet-control-layers-expanded .leaflet-control-layers-list { | ||
297 | + display: block; | ||
298 | + position: relative; | ||
299 | + } | ||
300 | +.leaflet-control-layers-expanded { | ||
301 | + padding: 6px 10px 6px 6px; | ||
302 | + color: #333; | ||
303 | + background: #fff; | ||
304 | + } | ||
305 | +.leaflet-control-layers-selector { | ||
306 | + margin-top: 2px; | ||
307 | + position: relative; | ||
308 | + top: 1px; | ||
309 | + } | ||
310 | +.leaflet-control-layers label { | ||
311 | + display: block; | ||
312 | + } | ||
313 | +.leaflet-control-layers-separator { | ||
314 | + height: 0; | ||
315 | + border-top: 1px solid #ddd; | ||
316 | + margin: 5px -10px 5px -6px; | ||
317 | + } | ||
318 | + | ||
319 | + | ||
320 | +/* attribution and scale controls */ | ||
321 | + | ||
322 | +.leaflet-container .leaflet-control-attribution { | ||
323 | + background: #fff; | ||
324 | + background: rgba(255, 255, 255, 0.7); | ||
325 | + margin: 0; | ||
326 | + } | ||
327 | +.leaflet-control-attribution, | ||
328 | +.leaflet-control-scale-line { | ||
329 | + padding: 0 5px; | ||
330 | + color: #333; | ||
331 | + } | ||
332 | +.leaflet-control-attribution a { | ||
333 | + text-decoration: none; | ||
334 | + } | ||
335 | +.leaflet-control-attribution a:hover { | ||
336 | + text-decoration: underline; | ||
337 | + } | ||
338 | +.leaflet-container .leaflet-control-attribution, | ||
339 | +.leaflet-container .leaflet-control-scale { | ||
340 | + font-size: 11px; | ||
341 | + } | ||
342 | +.leaflet-left .leaflet-control-scale { | ||
343 | + margin-left: 5px; | ||
344 | + } | ||
345 | +.leaflet-bottom .leaflet-control-scale { | ||
346 | + margin-bottom: 5px; | ||
347 | + } | ||
348 | +.leaflet-control-scale-line { | ||
349 | + border: 2px solid #777; | ||
350 | + border-top: none; | ||
351 | + line-height: 1.1; | ||
352 | + padding: 2px 5px 1px; | ||
353 | + font-size: 11px; | ||
354 | + white-space: nowrap; | ||
355 | + overflow: hidden; | ||
356 | + -moz-box-sizing: content-box; | ||
357 | + box-sizing: content-box; | ||
358 | + | ||
359 | + background: #fff; | ||
360 | + background: rgba(255, 255, 255, 0.5); | ||
361 | + } | ||
362 | +.leaflet-control-scale-line:not(:first-child) { | ||
363 | + border-top: 2px solid #777; | ||
364 | + border-bottom: none; | ||
365 | + margin-top: -2px; | ||
366 | + } | ||
367 | +.leaflet-control-scale-line:not(:first-child):not(:last-child) { | ||
368 | + border-bottom: 2px solid #777; | ||
369 | + } | ||
370 | + | ||
371 | +.leaflet-touch .leaflet-control-attribution, | ||
372 | +.leaflet-touch .leaflet-control-layers, | ||
373 | +.leaflet-touch .leaflet-bar { | ||
374 | + box-shadow: none; | ||
375 | + } | ||
376 | +.leaflet-touch .leaflet-control-layers, | ||
377 | +.leaflet-touch .leaflet-bar { | ||
378 | + border: 2px solid rgba(0,0,0,0.2); | ||
379 | + background-clip: padding-box; | ||
380 | + } | ||
381 | + | ||
382 | + | ||
383 | +/* popup */ | ||
384 | + | ||
385 | +.leaflet-popup { | ||
386 | + position: absolute; | ||
387 | + text-align: center; | ||
388 | + } | ||
389 | +.leaflet-popup-content-wrapper { | ||
390 | + padding: 1px; | ||
391 | + text-align: left; | ||
392 | + border-radius: 12px; | ||
393 | + } | ||
394 | +.leaflet-popup-content { | ||
395 | + margin: 13px 19px; | ||
396 | + line-height: 1.4; | ||
397 | + } | ||
398 | +.leaflet-popup-content p { | ||
399 | + margin: 18px 0; | ||
400 | + } | ||
401 | +.leaflet-popup-tip-container { | ||
402 | + margin: 0 auto; | ||
403 | + width: 40px; | ||
404 | + height: 20px; | ||
405 | + position: relative; | ||
406 | + overflow: hidden; | ||
407 | + } | ||
408 | +.leaflet-popup-tip { | ||
409 | + width: 17px; | ||
410 | + height: 17px; | ||
411 | + padding: 1px; | ||
412 | + | ||
413 | + margin: -10px auto 0; | ||
414 | + | ||
415 | + -webkit-transform: rotate(45deg); | ||
416 | + -moz-transform: rotate(45deg); | ||
417 | + -ms-transform: rotate(45deg); | ||
418 | + -o-transform: rotate(45deg); | ||
419 | + transform: rotate(45deg); | ||
420 | + } | ||
421 | +.leaflet-popup-content-wrapper, | ||
422 | +.leaflet-popup-tip { | ||
423 | + background: white; | ||
424 | + | ||
425 | + box-shadow: 0 3px 14px rgba(0,0,0,0.4); | ||
426 | + } | ||
427 | +.leaflet-container a.leaflet-popup-close-button { | ||
428 | + position: absolute; | ||
429 | + top: 0; | ||
430 | + right: 0; | ||
431 | + padding: 4px 4px 0 0; | ||
432 | + text-align: center; | ||
433 | + width: 18px; | ||
434 | + height: 14px; | ||
435 | + font: 16px/14px Tahoma, Verdana, sans-serif; | ||
436 | + color: #c3c3c3; | ||
437 | + text-decoration: none; | ||
438 | + font-weight: bold; | ||
439 | + background: transparent; | ||
440 | + } | ||
441 | +.leaflet-container a.leaflet-popup-close-button:hover { | ||
442 | + color: #999; | ||
443 | + } | ||
444 | +.leaflet-popup-scrolled { | ||
445 | + overflow: auto; | ||
446 | + border-bottom: 1px solid #ddd; | ||
447 | + border-top: 1px solid #ddd; | ||
448 | + } | ||
449 | + | ||
450 | +.leaflet-oldie .leaflet-popup-content-wrapper { | ||
451 | + zoom: 1; | ||
452 | + } | ||
453 | +.leaflet-oldie .leaflet-popup-tip { | ||
454 | + width: 24px; | ||
455 | + margin: 0 auto; | ||
456 | + | ||
457 | + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; | ||
458 | + filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); | ||
459 | + } | ||
460 | +.leaflet-oldie .leaflet-popup-tip-container { | ||
461 | + margin-top: -1px; | ||
462 | + } | ||
463 | + | ||
464 | +.leaflet-oldie .leaflet-control-zoom, | ||
465 | +.leaflet-oldie .leaflet-control-layers, | ||
466 | +.leaflet-oldie .leaflet-popup-content-wrapper, | ||
467 | +.leaflet-oldie .leaflet-popup-tip { | ||
468 | + border: 1px solid #999; | ||
469 | + } | ||
470 | + | ||
471 | + | ||
472 | +/* div icon */ | ||
473 | + | ||
474 | +.leaflet-div-icon { | ||
475 | + background: #fff; | ||
476 | + border: 1px solid #666; | ||
477 | + } | ||
0 | \ No newline at end of file | 478 | \ No newline at end of file |
datalets/leafletjs-geojson-datalet/leafletsjs/leaflet.js
0 โ 100755
1 | +/* | ||
2 | + Leaflet, a JavaScript library for mobile-friendly interactive maps. http://leafletjs.com | ||
3 | + (c) 2010-2013, Vladimir Agafonkin | ||
4 | + (c) 2010-2011, CloudMade | ||
5 | +*/ | ||
6 | +!function(t,e,i){var n=t.L,o={};o.version="0.7.3","object"==typeof module&&"object"==typeof module.exports?module.exports=o:"function"==typeof define&&define.amd&&define(o),o.noConflict=function(){return t.L=n,this},t.L=o,o.Util={extend:function(t){var e,i,n,o,s=Array.prototype.slice.call(arguments,1);for(i=0,n=s.length;n>i;i++){o=s[i]||{};for(e in o)o.hasOwnProperty(e)&&(t[e]=o[e])}return t},bind:function(t,e){var i=arguments.length>2?Array.prototype.slice.call(arguments,2):null;return function(){return t.apply(e,i||arguments)}},stamp:function(){var t=0,e="_leaflet_id";return function(i){return i[e]=i[e]||++t,i[e]}}(),invokeEach:function(t,e,i){var n,o;if("object"==typeof t){o=Array.prototype.slice.call(arguments,3);for(n in t)e.apply(i,[n,t[n]].concat(o));return!0}return!1},limitExecByInterval:function(t,e,i){var n,o;return function s(){var a=arguments;return n?void(o=!0):(n=!0,setTimeout(function(){n=!1,o&&(s.apply(i,a),o=!1)},e),void t.apply(i,a))}},falseFn:function(){return!1},formatNum:function(t,e){var i=Math.pow(10,e||5);return Math.round(t*i)/i},trim:function(t){return t.trim?t.trim():t.replace(/^\s+|\s+$/g,"")},splitWords:function(t){return o.Util.trim(t).split(/\s+/)},setOptions:function(t,e){return t.options=o.extend({},t.options,e),t.options},getParamString:function(t,e,i){var n=[];for(var o in t)n.push(encodeURIComponent(i?o.toUpperCase():o)+"="+encodeURIComponent(t[o]));return(e&&-1!==e.indexOf("?")?"&":"?")+n.join("&")},template:function(t,e){return t.replace(/\{ *([\w_]+) *\}/g,function(t,n){var o=e[n];if(o===i)throw new Error("No value provided for variable "+t);return"function"==typeof o&&(o=o(e)),o})},isArray:Array.isArray||function(t){return"[object Array]"===Object.prototype.toString.call(t)},emptyImageUrl:"data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="},function(){function e(e){var i,n,o=["webkit","moz","o","ms"];for(i=0;i<o.length&&!n;i++)n=t[o[i]+e];return n}function i(e){var i=+new Date,o=Math.max(0,16-(i-n));return n=i+o,t.setTimeout(e,o)}var n=0,s=t.requestAnimationFrame||e("RequestAnimationFrame")||i,a=t.cancelAnimationFrame||e("CancelAnimationFrame")||e("CancelRequestAnimationFrame")||function(e){t.clearTimeout(e)};o.Util.requestAnimFrame=function(e,n,a,r){return e=o.bind(e,n),a&&s===i?void e():s.call(t,e,r)},o.Util.cancelAnimFrame=function(e){e&&a.call(t,e)}}(),o.extend=o.Util.extend,o.bind=o.Util.bind,o.stamp=o.Util.stamp,o.setOptions=o.Util.setOptions,o.Class=function(){},o.Class.extend=function(t){var e=function(){this.initialize&&this.initialize.apply(this,arguments),this._initHooks&&this.callInitHooks()},i=function(){};i.prototype=this.prototype;var n=new i;n.constructor=e,e.prototype=n;for(var s in this)this.hasOwnProperty(s)&&"prototype"!==s&&(e[s]=this[s]);t.statics&&(o.extend(e,t.statics),delete t.statics),t.includes&&(o.Util.extend.apply(null,[n].concat(t.includes)),delete t.includes),t.options&&n.options&&(t.options=o.extend({},n.options,t.options)),o.extend(n,t),n._initHooks=[];var a=this;return e.__super__=a.prototype,n.callInitHooks=function(){if(!this._initHooksCalled){a.prototype.callInitHooks&&a.prototype.callInitHooks.call(this),this._initHooksCalled=!0;for(var t=0,e=n._initHooks.length;e>t;t++)n._initHooks[t].call(this)}},e},o.Class.include=function(t){o.extend(this.prototype,t)},o.Class.mergeOptions=function(t){o.extend(this.prototype.options,t)},o.Class.addInitHook=function(t){var e=Array.prototype.slice.call(arguments,1),i="function"==typeof t?t:function(){this[t].apply(this,e)};this.prototype._initHooks=this.prototype._initHooks||[],this.prototype._initHooks.push(i)};var s="_leaflet_events";o.Mixin={},o.Mixin.Events={addEventListener:function(t,e,i){if(o.Util.invokeEach(t,this.addEventListener,this,e,i))return this;var n,a,r,h,l,u,c,d=this[s]=this[s]||{},p=i&&i!==this&&o.stamp(i);for(t=o.Util.splitWords(t),n=0,a=t.length;a>n;n++)r={action:e,context:i||this},h=t[n],p?(l=h+"_idx",u=l+"_len",c=d[l]=d[l]||{},c[p]||(c[p]=[],d[u]=(d[u]||0)+1),c[p].push(r)):(d[h]=d[h]||[],d[h].push(r));return this},hasEventListeners:function(t){var e=this[s];return!!e&&(t in e&&e[t].length>0||t+"_idx"in e&&e[t+"_idx_len"]>0)},removeEventListener:function(t,e,i){if(!this[s])return this;if(!t)return this.clearAllEventListeners();if(o.Util.invokeEach(t,this.removeEventListener,this,e,i))return this;var n,a,r,h,l,u,c,d,p,_=this[s],m=i&&i!==this&&o.stamp(i);for(t=o.Util.splitWords(t),n=0,a=t.length;a>n;n++)if(r=t[n],u=r+"_idx",c=u+"_len",d=_[u],e){if(h=m&&d?d[m]:_[r]){for(l=h.length-1;l>=0;l--)h[l].action!==e||i&&h[l].context!==i||(p=h.splice(l,1),p[0].action=o.Util.falseFn);i&&d&&0===h.length&&(delete d[m],_[c]--)}}else delete _[r],delete _[u],delete _[c];return this},clearAllEventListeners:function(){return delete this[s],this},fireEvent:function(t,e){if(!this.hasEventListeners(t))return this;var i,n,a,r,h,l=o.Util.extend({},e,{type:t,target:this}),u=this[s];if(u[t])for(i=u[t].slice(),n=0,a=i.length;a>n;n++)i[n].action.call(i[n].context,l);r=u[t+"_idx"];for(h in r)if(i=r[h].slice())for(n=0,a=i.length;a>n;n++)i[n].action.call(i[n].context,l);return this},addOneTimeEventListener:function(t,e,i){if(o.Util.invokeEach(t,this.addOneTimeEventListener,this,e,i))return this;var n=o.bind(function(){this.removeEventListener(t,e,i).removeEventListener(t,n,i)},this);return this.addEventListener(t,e,i).addEventListener(t,n,i)}},o.Mixin.Events.on=o.Mixin.Events.addEventListener,o.Mixin.Events.off=o.Mixin.Events.removeEventListener,o.Mixin.Events.once=o.Mixin.Events.addOneTimeEventListener,o.Mixin.Events.fire=o.Mixin.Events.fireEvent,function(){var n="ActiveXObject"in t,s=n&&!e.addEventListener,a=navigator.userAgent.toLowerCase(),r=-1!==a.indexOf("webkit"),h=-1!==a.indexOf("chrome"),l=-1!==a.indexOf("phantom"),u=-1!==a.indexOf("android"),c=-1!==a.search("android [23]"),d=-1!==a.indexOf("gecko"),p=typeof orientation!=i+"",_=t.navigator&&t.navigator.msPointerEnabled&&t.navigator.msMaxTouchPoints&&!t.PointerEvent,m=t.PointerEvent&&t.navigator.pointerEnabled&&t.navigator.maxTouchPoints||_,f="devicePixelRatio"in t&&t.devicePixelRatio>1||"matchMedia"in t&&t.matchMedia("(min-resolution:144dpi)")&&t.matchMedia("(min-resolution:144dpi)").matches,g=e.documentElement,v=n&&"transition"in g.style,y="WebKitCSSMatrix"in t&&"m11"in new t.WebKitCSSMatrix&&!c,P="MozPerspective"in g.style,L="OTransition"in g.style,x=!t.L_DISABLE_3D&&(v||y||P||L)&&!l,w=!t.L_NO_TOUCH&&!l&&function(){var t="ontouchstart";if(m||t in g)return!0;var i=e.createElement("div"),n=!1;return i.setAttribute?(i.setAttribute(t,"return;"),"function"==typeof i[t]&&(n=!0),i.removeAttribute(t),i=null,n):!1}();o.Browser={ie:n,ielt9:s,webkit:r,gecko:d&&!r&&!t.opera&&!n,android:u,android23:c,chrome:h,ie3d:v,webkit3d:y,gecko3d:P,opera3d:L,any3d:x,mobile:p,mobileWebkit:p&&r,mobileWebkit3d:p&&y,mobileOpera:p&&t.opera,touch:w,msPointer:_,pointer:m,retina:f}}(),o.Point=function(t,e,i){this.x=i?Math.round(t):t,this.y=i?Math.round(e):e},o.Point.prototype={clone:function(){return new o.Point(this.x,this.y)},add:function(t){return this.clone()._add(o.point(t))},_add:function(t){return this.x+=t.x,this.y+=t.y,this},subtract:function(t){return this.clone()._subtract(o.point(t))},_subtract:function(t){return this.x-=t.x,this.y-=t.y,this},divideBy:function(t){return this.clone()._divideBy(t)},_divideBy:function(t){return this.x/=t,this.y/=t,this},multiplyBy:function(t){return this.clone()._multiplyBy(t)},_multiplyBy:function(t){return this.x*=t,this.y*=t,this},round:function(){return this.clone()._round()},_round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},floor:function(){return this.clone()._floor()},_floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this},distanceTo:function(t){t=o.point(t);var e=t.x-this.x,i=t.y-this.y;return Math.sqrt(e*e+i*i)},equals:function(t){return t=o.point(t),t.x===this.x&&t.y===this.y},contains:function(t){return t=o.point(t),Math.abs(t.x)<=Math.abs(this.x)&&Math.abs(t.y)<=Math.abs(this.y)},toString:function(){return"Point("+o.Util.formatNum(this.x)+", "+o.Util.formatNum(this.y)+")"}},o.point=function(t,e,n){return t instanceof o.Point?t:o.Util.isArray(t)?new o.Point(t[0],t[1]):t===i||null===t?t:new o.Point(t,e,n)},o.Bounds=function(t,e){if(t)for(var i=e?[t,e]:t,n=0,o=i.length;o>n;n++)this.extend(i[n])},o.Bounds.prototype={extend:function(t){return t=o.point(t),this.min||this.max?(this.min.x=Math.min(t.x,this.min.x),this.max.x=Math.max(t.x,this.max.x),this.min.y=Math.min(t.y,this.min.y),this.max.y=Math.max(t.y,this.max.y)):(this.min=t.clone(),this.max=t.clone()),this},getCenter:function(t){return new o.Point((this.min.x+this.max.x)/2,(this.min.y+this.max.y)/2,t)},getBottomLeft:function(){return new o.Point(this.min.x,this.max.y)},getTopRight:function(){return new o.Point(this.max.x,this.min.y)},getSize:function(){return this.max.subtract(this.min)},contains:function(t){var e,i;return t="number"==typeof t[0]||t instanceof o.Point?o.point(t):o.bounds(t),t instanceof o.Bounds?(e=t.min,i=t.max):e=i=t,e.x>=this.min.x&&i.x<=this.max.x&&e.y>=this.min.y&&i.y<=this.max.y},intersects:function(t){t=o.bounds(t);var e=this.min,i=this.max,n=t.min,s=t.max,a=s.x>=e.x&&n.x<=i.x,r=s.y>=e.y&&n.y<=i.y;return a&&r},isValid:function(){return!(!this.min||!this.max)}},o.bounds=function(t,e){return!t||t instanceof o.Bounds?t:new o.Bounds(t,e)},o.Transformation=function(t,e,i,n){this._a=t,this._b=e,this._c=i,this._d=n},o.Transformation.prototype={transform:function(t,e){return this._transform(t.clone(),e)},_transform:function(t,e){return e=e||1,t.x=e*(this._a*t.x+this._b),t.y=e*(this._c*t.y+this._d),t},untransform:function(t,e){return e=e||1,new o.Point((t.x/e-this._b)/this._a,(t.y/e-this._d)/this._c)}},o.DomUtil={get:function(t){return"string"==typeof t?e.getElementById(t):t},getStyle:function(t,i){var n=t.style[i];if(!n&&t.currentStyle&&(n=t.currentStyle[i]),(!n||"auto"===n)&&e.defaultView){var o=e.defaultView.getComputedStyle(t,null);n=o?o[i]:null}return"auto"===n?null:n},getViewportOffset:function(t){var i,n=0,s=0,a=t,r=e.body,h=e.documentElement;do{if(n+=a.offsetTop||0,s+=a.offsetLeft||0,n+=parseInt(o.DomUtil.getStyle(a,"borderTopWidth"),10)||0,s+=parseInt(o.DomUtil.getStyle(a,"borderLeftWidth"),10)||0,i=o.DomUtil.getStyle(a,"position"),a.offsetParent===r&&"absolute"===i)break;if("fixed"===i){n+=r.scrollTop||h.scrollTop||0,s+=r.scrollLeft||h.scrollLeft||0;break}if("relative"===i&&!a.offsetLeft){var l=o.DomUtil.getStyle(a,"width"),u=o.DomUtil.getStyle(a,"max-width"),c=a.getBoundingClientRect();("none"!==l||"none"!==u)&&(s+=c.left+a.clientLeft),n+=c.top+(r.scrollTop||h.scrollTop||0);break}a=a.offsetParent}while(a);a=t;do{if(a===r)break;n-=a.scrollTop||0,s-=a.scrollLeft||0,a=a.parentNode}while(a);return new o.Point(s,n)},documentIsLtr:function(){return o.DomUtil._docIsLtrCached||(o.DomUtil._docIsLtrCached=!0,o.DomUtil._docIsLtr="ltr"===o.DomUtil.getStyle(e.body,"direction")),o.DomUtil._docIsLtr},create:function(t,i,n){var o=e.createElement(t);return o.className=i,n&&n.appendChild(o),o},hasClass:function(t,e){if(t.classList!==i)return t.classList.contains(e);var n=o.DomUtil._getClass(t);return n.length>0&&new RegExp("(^|\\s)"+e+"(\\s|$)").test(n)},addClass:function(t,e){if(t.classList!==i)for(var n=o.Util.splitWords(e),s=0,a=n.length;a>s;s++)t.classList.add(n[s]);else if(!o.DomUtil.hasClass(t,e)){var r=o.DomUtil._getClass(t);o.DomUtil._setClass(t,(r?r+" ":"")+e)}},removeClass:function(t,e){t.classList!==i?t.classList.remove(e):o.DomUtil._setClass(t,o.Util.trim((" "+o.DomUtil._getClass(t)+" ").replace(" "+e+" "," ")))},_setClass:function(t,e){t.className.baseVal===i?t.className=e:t.className.baseVal=e},_getClass:function(t){return t.className.baseVal===i?t.className:t.className.baseVal},setOpacity:function(t,e){if("opacity"in t.style)t.style.opacity=e;else if("filter"in t.style){var i=!1,n="DXImageTransform.Microsoft.Alpha";try{i=t.filters.item(n)}catch(o){if(1===e)return}e=Math.round(100*e),i?(i.Enabled=100!==e,i.Opacity=e):t.style.filter+=" progid:"+n+"(opacity="+e+")"}},testProp:function(t){for(var i=e.documentElement.style,n=0;n<t.length;n++)if(t[n]in i)return t[n];return!1},getTranslateString:function(t){var e=o.Browser.webkit3d,i="translate"+(e?"3d":"")+"(",n=(e?",0":"")+")";return i+t.x+"px,"+t.y+"px"+n},getScaleString:function(t,e){var i=o.DomUtil.getTranslateString(e.add(e.multiplyBy(-1*t))),n=" scale("+t+") ";return i+n},setPosition:function(t,e,i){t._leaflet_pos=e,!i&&o.Browser.any3d?t.style[o.DomUtil.TRANSFORM]=o.DomUtil.getTranslateString(e):(t.style.left=e.x+"px",t.style.top=e.y+"px")},getPosition:function(t){return t._leaflet_pos}},o.DomUtil.TRANSFORM=o.DomUtil.testProp(["transform","WebkitTransform","OTransform","MozTransform","msTransform"]),o.DomUtil.TRANSITION=o.DomUtil.testProp(["webkitTransition","transition","OTransition","MozTransition","msTransition"]),o.DomUtil.TRANSITION_END="webkitTransition"===o.DomUtil.TRANSITION||"OTransition"===o.DomUtil.TRANSITION?o.DomUtil.TRANSITION+"End":"transitionend",function(){if("onselectstart"in e)o.extend(o.DomUtil,{disableTextSelection:function(){o.DomEvent.on(t,"selectstart",o.DomEvent.preventDefault)},enableTextSelection:function(){o.DomEvent.off(t,"selectstart",o.DomEvent.preventDefault)}});else{var i=o.DomUtil.testProp(["userSelect","WebkitUserSelect","OUserSelect","MozUserSelect","msUserSelect"]);o.extend(o.DomUtil,{disableTextSelection:function(){if(i){var t=e.documentElement.style;this._userSelect=t[i],t[i]="none"}},enableTextSelection:function(){i&&(e.documentElement.style[i]=this._userSelect,delete this._userSelect)}})}o.extend(o.DomUtil,{disableImageDrag:function(){o.DomEvent.on(t,"dragstart",o.DomEvent.preventDefault)},enableImageDrag:function(){o.DomEvent.off(t,"dragstart",o.DomEvent.preventDefault)}})}(),o.LatLng=function(t,e,n){if(t=parseFloat(t),e=parseFloat(e),isNaN(t)||isNaN(e))throw new Error("Invalid LatLng object: ("+t+", "+e+")");this.lat=t,this.lng=e,n!==i&&(this.alt=parseFloat(n))},o.extend(o.LatLng,{DEG_TO_RAD:Math.PI/180,RAD_TO_DEG:180/Math.PI,MAX_MARGIN:1e-9}),o.LatLng.prototype={equals:function(t){if(!t)return!1;t=o.latLng(t);var e=Math.max(Math.abs(this.lat-t.lat),Math.abs(this.lng-t.lng));return e<=o.LatLng.MAX_MARGIN},toString:function(t){return"LatLng("+o.Util.formatNum(this.lat,t)+", "+o.Util.formatNum(this.lng,t)+")"},distanceTo:function(t){t=o.latLng(t);var e=6378137,i=o.LatLng.DEG_TO_RAD,n=(t.lat-this.lat)*i,s=(t.lng-this.lng)*i,a=this.lat*i,r=t.lat*i,h=Math.sin(n/2),l=Math.sin(s/2),u=h*h+l*l*Math.cos(a)*Math.cos(r);return 2*e*Math.atan2(Math.sqrt(u),Math.sqrt(1-u))},wrap:function(t,e){var i=this.lng;return t=t||-180,e=e||180,i=(i+e)%(e-t)+(t>i||i===e?e:t),new o.LatLng(this.lat,i)}},o.latLng=function(t,e){return t instanceof o.LatLng?t:o.Util.isArray(t)?"number"==typeof t[0]||"string"==typeof t[0]?new o.LatLng(t[0],t[1],t[2]):null:t===i||null===t?t:"object"==typeof t&&"lat"in t?new o.LatLng(t.lat,"lng"in t?t.lng:t.lon):e===i?null:new o.LatLng(t,e)},o.LatLngBounds=function(t,e){if(t)for(var i=e?[t,e]:t,n=0,o=i.length;o>n;n++)this.extend(i[n])},o.LatLngBounds.prototype={extend:function(t){if(!t)return this;var e=o.latLng(t);return t=null!==e?e:o.latLngBounds(t),t instanceof o.LatLng?this._southWest||this._northEast?(this._southWest.lat=Math.min(t.lat,this._southWest.lat),this._southWest.lng=Math.min(t.lng,this._southWest.lng),this._northEast.lat=Math.max(t.lat,this._northEast.lat),this._northEast.lng=Math.max(t.lng,this._northEast.lng)):(this._southWest=new o.LatLng(t.lat,t.lng),this._northEast=new o.LatLng(t.lat,t.lng)):t instanceof o.LatLngBounds&&(this.extend(t._southWest),this.extend(t._northEast)),this},pad:function(t){var e=this._southWest,i=this._northEast,n=Math.abs(e.lat-i.lat)*t,s=Math.abs(e.lng-i.lng)*t;return new o.LatLngBounds(new o.LatLng(e.lat-n,e.lng-s),new o.LatLng(i.lat+n,i.lng+s))},getCenter:function(){return new o.LatLng((this._southWest.lat+this._northEast.lat)/2,(this._southWest.lng+this._northEast.lng)/2)},getSouthWest:function(){return this._southWest},getNorthEast:function(){return this._northEast},getNorthWest:function(){return new o.LatLng(this.getNorth(),this.getWest())},getSouthEast:function(){return new o.LatLng(this.getSouth(),this.getEast())},getWest:function(){return this._southWest.lng},getSouth:function(){return this._southWest.lat},getEast:function(){return this._northEast.lng},getNorth:function(){return this._northEast.lat},contains:function(t){t="number"==typeof t[0]||t instanceof o.LatLng?o.latLng(t):o.latLngBounds(t);var e,i,n=this._southWest,s=this._northEast;return t instanceof o.LatLngBounds?(e=t.getSouthWest(),i=t.getNorthEast()):e=i=t,e.lat>=n.lat&&i.lat<=s.lat&&e.lng>=n.lng&&i.lng<=s.lng},intersects:function(t){t=o.latLngBounds(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),s=t.getNorthEast(),a=s.lat>=e.lat&&n.lat<=i.lat,r=s.lng>=e.lng&&n.lng<=i.lng;return a&&r},toBBoxString:function(){return[this.getWest(),this.getSouth(),this.getEast(),this.getNorth()].join(",")},equals:function(t){return t?(t=o.latLngBounds(t),this._southWest.equals(t.getSouthWest())&&this._northEast.equals(t.getNorthEast())):!1},isValid:function(){return!(!this._southWest||!this._northEast)}},o.latLngBounds=function(t,e){return!t||t instanceof o.LatLngBounds?t:new o.LatLngBounds(t,e)},o.Projection={},o.Projection.SphericalMercator={MAX_LATITUDE:85.0511287798,project:function(t){var e=o.LatLng.DEG_TO_RAD,i=this.MAX_LATITUDE,n=Math.max(Math.min(i,t.lat),-i),s=t.lng*e,a=n*e;return a=Math.log(Math.tan(Math.PI/4+a/2)),new o.Point(s,a)},unproject:function(t){var e=o.LatLng.RAD_TO_DEG,i=t.x*e,n=(2*Math.atan(Math.exp(t.y))-Math.PI/2)*e;return new o.LatLng(n,i)}},o.Projection.LonLat={project:function(t){return new o.Point(t.lng,t.lat)},unproject:function(t){return new o.LatLng(t.y,t.x)}},o.CRS={latLngToPoint:function(t,e){var i=this.projection.project(t),n=this.scale(e);return this.transformation._transform(i,n)},pointToLatLng:function(t,e){var i=this.scale(e),n=this.transformation.untransform(t,i);return this.projection.unproject(n)},project:function(t){return this.projection.project(t)},scale:function(t){return 256*Math.pow(2,t)},getSize:function(t){var e=this.scale(t);return o.point(e,e)}},o.CRS.Simple=o.extend({},o.CRS,{projection:o.Projection.LonLat,transformation:new o.Transformation(1,0,-1,0),scale:function(t){return Math.pow(2,t)}}),o.CRS.EPSG3857=o.extend({},o.CRS,{code:"EPSG:3857",projection:o.Projection.SphericalMercator,transformation:new o.Transformation(.5/Math.PI,.5,-.5/Math.PI,.5),project:function(t){var e=this.projection.project(t),i=6378137;return e.multiplyBy(i)}}),o.CRS.EPSG900913=o.extend({},o.CRS.EPSG3857,{code:"EPSG:900913"}),o.CRS.EPSG4326=o.extend({},o.CRS,{code:"EPSG:4326",projection:o.Projection.LonLat,transformation:new o.Transformation(1/360,.5,-1/360,.5)}),o.Map=o.Class.extend({includes:o.Mixin.Events,options:{crs:o.CRS.EPSG3857,fadeAnimation:o.DomUtil.TRANSITION&&!o.Browser.android23,trackResize:!0,markerZoomAnimation:o.DomUtil.TRANSITION&&o.Browser.any3d},initialize:function(t,e){e=o.setOptions(this,e),this._initContainer(t),this._initLayout(),this._onResize=o.bind(this._onResize,this),this._initEvents(),e.maxBounds&&this.setMaxBounds(e.maxBounds),e.center&&e.zoom!==i&&this.setView(o.latLng(e.center),e.zoom,{reset:!0}),this._handlers=[],this._layers={},this._zoomBoundLayers={},this._tileLayersNum=0,this.callInitHooks(),this._addLayers(e.layers)},setView:function(t,e){return e=e===i?this.getZoom():e,this._resetView(o.latLng(t),this._limitZoom(e)),this},setZoom:function(t,e){return this._loaded?this.setView(this.getCenter(),t,{zoom:e}):(this._zoom=this._limitZoom(t),this)},zoomIn:function(t,e){return this.setZoom(this._zoom+(t||1),e)},zoomOut:function(t,e){return this.setZoom(this._zoom-(t||1),e)},setZoomAround:function(t,e,i){var n=this.getZoomScale(e),s=this.getSize().divideBy(2),a=t instanceof o.Point?t:this.latLngToContainerPoint(t),r=a.subtract(s).multiplyBy(1-1/n),h=this.containerPointToLatLng(s.add(r));return this.setView(h,e,{zoom:i})},fitBounds:function(t,e){e=e||{},t=t.getBounds?t.getBounds():o.latLngBounds(t);var i=o.point(e.paddingTopLeft||e.padding||[0,0]),n=o.point(e.paddingBottomRight||e.padding||[0,0]),s=this.getBoundsZoom(t,!1,i.add(n)),a=n.subtract(i).divideBy(2),r=this.project(t.getSouthWest(),s),h=this.project(t.getNorthEast(),s),l=this.unproject(r.add(h).divideBy(2).add(a),s);return s=e&&e.maxZoom?Math.min(e.maxZoom,s):s,this.setView(l,s,e)},fitWorld:function(t){return this.fitBounds([[-90,-180],[90,180]],t)},panTo:function(t,e){return this.setView(t,this._zoom,{pan:e})},panBy:function(t){return this.fire("movestart"),this._rawPanBy(o.point(t)),this.fire("move"),this.fire("moveend")},setMaxBounds:function(t){return t=o.latLngBounds(t),this.options.maxBounds=t,t?(this._loaded&&this._panInsideMaxBounds(),this.on("moveend",this._panInsideMaxBounds,this)):this.off("moveend",this._panInsideMaxBounds,this)},panInsideBounds:function(t,e){var i=this.getCenter(),n=this._limitCenter(i,this._zoom,t);return i.equals(n)?this:this.panTo(n,e)},addLayer:function(t){var e=o.stamp(t);return this._layers[e]?this:(this._layers[e]=t,!t.options||isNaN(t.options.maxZoom)&&isNaN(t.options.minZoom)||(this._zoomBoundLayers[e]=t,this._updateZoomLevels()),this.options.zoomAnimation&&o.TileLayer&&t instanceof o.TileLayer&&(this._tileLayersNum++,this._tileLayersToLoad++,t.on("load",this._onTileLayerLoad,this)),this._loaded&&this._layerAdd(t),this)},removeLayer:function(t){var e=o.stamp(t);return this._layers[e]?(this._loaded&&t.onRemove(this),delete this._layers[e],this._loaded&&this.fire("layerremove",{layer:t}),this._zoomBoundLayers[e]&&(delete this._zoomBoundLayers[e],this._updateZoomLevels()),this.options.zoomAnimation&&o.TileLayer&&t instanceof o.TileLayer&&(this._tileLayersNum--,this._tileLayersToLoad--,t.off("load",this._onTileLayerLoad,this)),this):this},hasLayer:function(t){return t?o.stamp(t)in this._layers:!1},eachLayer:function(t,e){for(var i in this._layers)t.call(e,this._layers[i]);return this},invalidateSize:function(t){if(!this._loaded)return this;t=o.extend({animate:!1,pan:!0},t===!0?{animate:!0}:t);var e=this.getSize();this._sizeChanged=!0,this._initialCenter=null;var i=this.getSize(),n=e.divideBy(2).round(),s=i.divideBy(2).round(),a=n.subtract(s);return a.x||a.y?(t.animate&&t.pan?this.panBy(a):(t.pan&&this._rawPanBy(a),this.fire("move"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(o.bind(this.fire,this,"moveend"),200)):this.fire("moveend")),this.fire("resize",{oldSize:e,newSize:i})):this},addHandler:function(t,e){if(!e)return this;var i=this[t]=new e(this);return this._handlers.push(i),this.options[t]&&i.enable(),this},remove:function(){this._loaded&&this.fire("unload"),this._initEvents("off");try{delete this._container._leaflet}catch(t){this._container._leaflet=i}return this._clearPanes(),this._clearControlPos&&this._clearControlPos(),this._clearHandlers(),this},getCenter:function(){return this._checkIfLoaded(),this._initialCenter&&!this._moved()?this._initialCenter:this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds(),e=this.unproject(t.getBottomLeft()),i=this.unproject(t.getTopRight());return new o.LatLngBounds(e,i)},getMinZoom:function(){return this.options.minZoom===i?this._layersMinZoom===i?0:this._layersMinZoom:this.options.minZoom},getMaxZoom:function(){return this.options.maxZoom===i?this._layersMaxZoom===i?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,e,i){t=o.latLngBounds(t);var n,s=this.getMinZoom()-(e?1:0),a=this.getMaxZoom(),r=this.getSize(),h=t.getNorthWest(),l=t.getSouthEast(),u=!0;i=o.point(i||[0,0]);do s++,n=this.project(l,s).subtract(this.project(h,s)).add(i),u=e?n.x<r.x||n.y<r.y:r.contains(n);while(u&&a>=s);return u&&e?null:e?s:s-1},getSize:function(){return(!this._size||this._sizeChanged)&&(this._size=new o.Point(this._container.clientWidth,this._container.clientHeight),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(){var t=this._getTopLeftPoint();return new o.Bounds(t,t.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._initialTopLeftPoint},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t){var e=this.options.crs;return e.scale(t)/e.scale(this._zoom)},getScaleZoom:function(t){return this._zoom+Math.log(t)/Math.LN2},project:function(t,e){return e=e===i?this._zoom:e,this.options.crs.latLngToPoint(o.latLng(t),e)},unproject:function(t,e){return e=e===i?this._zoom:e,this.options.crs.pointToLatLng(o.point(t),e)},layerPointToLatLng:function(t){var e=o.point(t).add(this.getPixelOrigin());return this.unproject(e)},latLngToLayerPoint:function(t){var e=this.project(o.latLng(t))._round();return e._subtract(this.getPixelOrigin())},containerPointToLayerPoint:function(t){return o.point(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return o.point(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){var e=this.containerPointToLayerPoint(o.point(t));return this.layerPointToLatLng(e)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(o.latLng(t)))},mouseEventToContainerPoint:function(t){return o.DomEvent.getMousePosition(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){var e=this._container=o.DomUtil.get(t);if(!e)throw new Error("Map container not found.");if(e._leaflet)throw new Error("Map container is already initialized.");e._leaflet=!0},_initLayout:function(){var t=this._container;o.DomUtil.addClass(t,"leaflet-container"+(o.Browser.touch?" leaflet-touch":"")+(o.Browser.retina?" leaflet-retina":"")+(o.Browser.ielt9?" leaflet-oldie":"")+(this.options.fadeAnimation?" leaflet-fade-anim":""));var e=o.DomUtil.getStyle(t,"position");"absolute"!==e&&"relative"!==e&&"fixed"!==e&&(t.style.position="relative"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._mapPane=t.mapPane=this._createPane("leaflet-map-pane",this._container),this._tilePane=t.tilePane=this._createPane("leaflet-tile-pane",this._mapPane),t.objectsPane=this._createPane("leaflet-objects-pane",this._mapPane),t.shadowPane=this._createPane("leaflet-shadow-pane"),t.overlayPane=this._createPane("leaflet-overlay-pane"),t.markerPane=this._createPane("leaflet-marker-pane"),t.popupPane=this._createPane("leaflet-popup-pane");var e=" leaflet-zoom-hide";this.options.markerZoomAnimation||(o.DomUtil.addClass(t.markerPane,e),o.DomUtil.addClass(t.shadowPane,e),o.DomUtil.addClass(t.popupPane,e))},_createPane:function(t,e){return o.DomUtil.create("div",t,e||this._panes.objectsPane)},_clearPanes:function(){this._container.removeChild(this._mapPane)},_addLayers:function(t){t=t?o.Util.isArray(t)?t:[t]:[];for(var e=0,i=t.length;i>e;e++)this.addLayer(t[e])},_resetView:function(t,e,i,n){var s=this._zoom!==e;n||(this.fire("movestart"),s&&this.fire("zoomstart")),this._zoom=e,this._initialCenter=t,this._initialTopLeftPoint=this._getNewTopLeftPoint(t),i?this._initialTopLeftPoint._add(this._getMapPanePos()):o.DomUtil.setPosition(this._mapPane,new o.Point(0,0)),this._tileLayersToLoad=this._tileLayersNum;var a=!this._loaded;this._loaded=!0,this.fire("viewreset",{hard:!i}),a&&(this.fire("load"),this.eachLayer(this._layerAdd,this)),this.fire("move"),(s||n)&&this.fire("zoomend"),this.fire("moveend",{hard:!i})},_rawPanBy:function(t){o.DomUtil.setPosition(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_updateZoomLevels:function(){var t,e=1/0,n=-1/0,o=this._getZoomSpan();for(t in this._zoomBoundLayers){var s=this._zoomBoundLayers[t];isNaN(s.options.minZoom)||(e=Math.min(e,s.options.minZoom)),isNaN(s.options.maxZoom)||(n=Math.max(n,s.options.maxZoom))}t===i?this._layersMaxZoom=this._layersMinZoom=i:(this._layersMaxZoom=n,this._layersMinZoom=e),o!==this._getZoomSpan()&&this.fire("zoomlevelschange")},_panInsideMaxBounds:function(){this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(e){if(o.DomEvent){e=e||"on",o.DomEvent[e](this._container,"click",this._onMouseClick,this);var i,n,s=["dblclick","mousedown","mouseup","mouseenter","mouseleave","mousemove","contextmenu"];for(i=0,n=s.length;n>i;i++)o.DomEvent[e](this._container,s[i],this._fireMouseEvent,this);this.options.trackResize&&o.DomEvent[e](t,"resize",this._onResize,this)}},_onResize:function(){o.Util.cancelAnimFrame(this._resizeRequest),this._resizeRequest=o.Util.requestAnimFrame(function(){this.invalidateSize({debounceMoveend:!0})},this,!1,this._container)},_onMouseClick:function(t){!this._loaded||!t._simulated&&(this.dragging&&this.dragging.moved()||this.boxZoom&&this.boxZoom.moved())||o.DomEvent._skipped(t)||(this.fire("preclick"),this._fireMouseEvent(t))},_fireMouseEvent:function(t){if(this._loaded&&!o.DomEvent._skipped(t)){var e=t.type;if(e="mouseenter"===e?"mouseover":"mouseleave"===e?"mouseout":e,this.hasEventListeners(e)){"contextmenu"===e&&o.DomEvent.preventDefault(t);var i=this.mouseEventToContainerPoint(t),n=this.containerPointToLayerPoint(i),s=this.layerPointToLatLng(n);this.fire(e,{latlng:s,layerPoint:n,containerPoint:i,originalEvent:t})}}},_onTileLayerLoad:function(){this._tileLayersToLoad--,this._tileLayersNum&&!this._tileLayersToLoad&&this.fire("tilelayersload")},_clearHandlers:function(){for(var t=0,e=this._handlers.length;e>t;t++)this._handlers[t].disable()},whenReady:function(t,e){return this._loaded?t.call(e||this,this):this.on("load",t,e),this},_layerAdd:function(t){t.onAdd(this),this.fire("layeradd",{layer:t})},_getMapPanePos:function(){return o.DomUtil.getPosition(this._mapPane)},_moved:function(){var t=this._getMapPanePos();return t&&!t.equals([0,0])},_getTopLeftPoint:function(){return this.getPixelOrigin().subtract(this._getMapPanePos())},_getNewTopLeftPoint:function(t,e){var i=this.getSize()._divideBy(2);return this.project(t,e)._subtract(i)._round()},_latLngToNewLayerPoint:function(t,e,i){var n=this._getNewTopLeftPoint(i,e).add(this._getMapPanePos());return this.project(t,e)._subtract(n)},_getCenterLayerPoint:function(){return this.containerPointToLayerPoint(this.getSize()._divideBy(2))},_getCenterOffset:function(t){return this.latLngToLayerPoint(t).subtract(this._getCenterLayerPoint())},_limitCenter:function(t,e,i){if(!i)return t;var n=this.project(t,e),s=this.getSize().divideBy(2),a=new o.Bounds(n.subtract(s),n.add(s)),r=this._getBoundsOffset(a,i,e);return this.unproject(n.add(r),e)},_limitOffset:function(t,e){if(!e)return t;var i=this.getPixelBounds(),n=new o.Bounds(i.min.add(t),i.max.add(t));return t.add(this._getBoundsOffset(n,e))},_getBoundsOffset:function(t,e,i){var n=this.project(e.getNorthWest(),i).subtract(t.min),s=this.project(e.getSouthEast(),i).subtract(t.max),a=this._rebound(n.x,-s.x),r=this._rebound(n.y,-s.y);return new o.Point(a,r)},_rebound:function(t,e){return t+e>0?Math.round(t-e)/2:Math.max(0,Math.ceil(t))-Math.max(0,Math.floor(e))},_limitZoom:function(t){var e=this.getMinZoom(),i=this.getMaxZoom();return Math.max(e,Math.min(i,t))}}),o.map=function(t,e){return new o.Map(t,e)},o.Projection.Mercator={MAX_LATITUDE:85.0840591556,R_MINOR:6356752.314245179,R_MAJOR:6378137,project:function(t){var e=o.LatLng.DEG_TO_RAD,i=this.MAX_LATITUDE,n=Math.max(Math.min(i,t.lat),-i),s=this.R_MAJOR,a=this.R_MINOR,r=t.lng*e*s,h=n*e,l=a/s,u=Math.sqrt(1-l*l),c=u*Math.sin(h);c=Math.pow((1-c)/(1+c),.5*u);var d=Math.tan(.5*(.5*Math.PI-h))/c;return h=-s*Math.log(d),new o.Point(r,h)},unproject:function(t){for(var e,i=o.LatLng.RAD_TO_DEG,n=this.R_MAJOR,s=this.R_MINOR,a=t.x*i/n,r=s/n,h=Math.sqrt(1-r*r),l=Math.exp(-t.y/n),u=Math.PI/2-2*Math.atan(l),c=15,d=1e-7,p=c,_=.1;Math.abs(_)>d&&--p>0;)e=h*Math.sin(u),_=Math.PI/2-2*Math.atan(l*Math.pow((1-e)/(1+e),.5*h))-u,u+=_; | ||
7 | +return new o.LatLng(u*i,a)}},o.CRS.EPSG3395=o.extend({},o.CRS,{code:"EPSG:3395",projection:o.Projection.Mercator,transformation:function(){var t=o.Projection.Mercator,e=t.R_MAJOR,i=.5/(Math.PI*e);return new o.Transformation(i,.5,-i,.5)}()}),o.TileLayer=o.Class.extend({includes:o.Mixin.Events,options:{minZoom:0,maxZoom:18,tileSize:256,subdomains:"abc",errorTileUrl:"",attribution:"",zoomOffset:0,opacity:1,unloadInvisibleTiles:o.Browser.mobile,updateWhenIdle:o.Browser.mobile},initialize:function(t,e){e=o.setOptions(this,e),e.detectRetina&&o.Browser.retina&&e.maxZoom>0&&(e.tileSize=Math.floor(e.tileSize/2),e.zoomOffset++,e.minZoom>0&&e.minZoom--,this.options.maxZoom--),e.bounds&&(e.bounds=o.latLngBounds(e.bounds)),this._url=t;var i=this.options.subdomains;"string"==typeof i&&(this.options.subdomains=i.split(""))},onAdd:function(t){this._map=t,this._animated=t._zoomAnimated,this._initContainer(),t.on({viewreset:this._reset,moveend:this._update},this),this._animated&&t.on({zoomanim:this._animateZoom,zoomend:this._endZoomAnim},this),this.options.updateWhenIdle||(this._limitedUpdate=o.Util.limitExecByInterval(this._update,150,this),t.on("move",this._limitedUpdate,this)),this._reset(),this._update()},addTo:function(t){return t.addLayer(this),this},onRemove:function(t){this._container.parentNode.removeChild(this._container),t.off({viewreset:this._reset,moveend:this._update},this),this._animated&&t.off({zoomanim:this._animateZoom,zoomend:this._endZoomAnim},this),this.options.updateWhenIdle||t.off("move",this._limitedUpdate,this),this._container=null,this._map=null},bringToFront:function(){var t=this._map._panes.tilePane;return this._container&&(t.appendChild(this._container),this._setAutoZIndex(t,Math.max)),this},bringToBack:function(){var t=this._map._panes.tilePane;return this._container&&(t.insertBefore(this._container,t.firstChild),this._setAutoZIndex(t,Math.min)),this},getAttribution:function(){return this.options.attribution},getContainer:function(){return this._container},setOpacity:function(t){return this.options.opacity=t,this._map&&this._updateOpacity(),this},setZIndex:function(t){return this.options.zIndex=t,this._updateZIndex(),this},setUrl:function(t,e){return this._url=t,e||this.redraw(),this},redraw:function(){return this._map&&(this._reset({hard:!0}),this._update()),this},_updateZIndex:function(){this._container&&this.options.zIndex!==i&&(this._container.style.zIndex=this.options.zIndex)},_setAutoZIndex:function(t,e){var i,n,o,s=t.children,a=-e(1/0,-1/0);for(n=0,o=s.length;o>n;n++)s[n]!==this._container&&(i=parseInt(s[n].style.zIndex,10),isNaN(i)||(a=e(a,i)));this.options.zIndex=this._container.style.zIndex=(isFinite(a)?a:0)+e(1,-1)},_updateOpacity:function(){var t,e=this._tiles;if(o.Browser.ielt9)for(t in e)o.DomUtil.setOpacity(e[t],this.options.opacity);else o.DomUtil.setOpacity(this._container,this.options.opacity)},_initContainer:function(){var t=this._map._panes.tilePane;if(!this._container){if(this._container=o.DomUtil.create("div","leaflet-layer"),this._updateZIndex(),this._animated){var e="leaflet-tile-container";this._bgBuffer=o.DomUtil.create("div",e,this._container),this._tileContainer=o.DomUtil.create("div",e,this._container)}else this._tileContainer=this._container;t.appendChild(this._container),this.options.opacity<1&&this._updateOpacity()}},_reset:function(t){for(var e in this._tiles)this.fire("tileunload",{tile:this._tiles[e]});this._tiles={},this._tilesToLoad=0,this.options.reuseTiles&&(this._unusedTiles=[]),this._tileContainer.innerHTML="",this._animated&&t&&t.hard&&this._clearBgBuffer(),this._initContainer()},_getTileSize:function(){var t=this._map,e=t.getZoom()+this.options.zoomOffset,i=this.options.maxNativeZoom,n=this.options.tileSize;return i&&e>i&&(n=Math.round(t.getZoomScale(e)/t.getZoomScale(i)*n)),n},_update:function(){if(this._map){var t=this._map,e=t.getPixelBounds(),i=t.getZoom(),n=this._getTileSize();if(!(i>this.options.maxZoom||i<this.options.minZoom)){var s=o.bounds(e.min.divideBy(n)._floor(),e.max.divideBy(n)._floor());this._addTilesFromCenterOut(s),(this.options.unloadInvisibleTiles||this.options.reuseTiles)&&this._removeOtherTiles(s)}}},_addTilesFromCenterOut:function(t){var i,n,s,a=[],r=t.getCenter();for(i=t.min.y;i<=t.max.y;i++)for(n=t.min.x;n<=t.max.x;n++)s=new o.Point(n,i),this._tileShouldBeLoaded(s)&&a.push(s);var h=a.length;if(0!==h){a.sort(function(t,e){return t.distanceTo(r)-e.distanceTo(r)});var l=e.createDocumentFragment();for(this._tilesToLoad||this.fire("loading"),this._tilesToLoad+=h,n=0;h>n;n++)this._addTile(a[n],l);this._tileContainer.appendChild(l)}},_tileShouldBeLoaded:function(t){if(t.x+":"+t.y in this._tiles)return!1;var e=this.options;if(!e.continuousWorld){var i=this._getWrapTileNum();if(e.noWrap&&(t.x<0||t.x>=i.x)||t.y<0||t.y>=i.y)return!1}if(e.bounds){var n=e.tileSize,o=t.multiplyBy(n),s=o.add([n,n]),a=this._map.unproject(o),r=this._map.unproject(s);if(e.continuousWorld||e.noWrap||(a=a.wrap(),r=r.wrap()),!e.bounds.intersects([a,r]))return!1}return!0},_removeOtherTiles:function(t){var e,i,n,o;for(o in this._tiles)e=o.split(":"),i=parseInt(e[0],10),n=parseInt(e[1],10),(i<t.min.x||i>t.max.x||n<t.min.y||n>t.max.y)&&this._removeTile(o)},_removeTile:function(t){var e=this._tiles[t];this.fire("tileunload",{tile:e,url:e.src}),this.options.reuseTiles?(o.DomUtil.removeClass(e,"leaflet-tile-loaded"),this._unusedTiles.push(e)):e.parentNode===this._tileContainer&&this._tileContainer.removeChild(e),o.Browser.android||(e.onload=null,e.src=o.Util.emptyImageUrl),delete this._tiles[t]},_addTile:function(t,e){var i=this._getTilePos(t),n=this._getTile();o.DomUtil.setPosition(n,i,o.Browser.chrome),this._tiles[t.x+":"+t.y]=n,this._loadTile(n,t),n.parentNode!==this._tileContainer&&e.appendChild(n)},_getZoomForUrl:function(){var t=this.options,e=this._map.getZoom();return t.zoomReverse&&(e=t.maxZoom-e),e+=t.zoomOffset,t.maxNativeZoom?Math.min(e,t.maxNativeZoom):e},_getTilePos:function(t){var e=this._map.getPixelOrigin(),i=this._getTileSize();return t.multiplyBy(i).subtract(e)},getTileUrl:function(t){return o.Util.template(this._url,o.extend({s:this._getSubdomain(t),z:t.z,x:t.x,y:t.y},this.options))},_getWrapTileNum:function(){var t=this._map.options.crs,e=t.getSize(this._map.getZoom());return e.divideBy(this._getTileSize())._floor()},_adjustTilePoint:function(t){var e=this._getWrapTileNum();this.options.continuousWorld||this.options.noWrap||(t.x=(t.x%e.x+e.x)%e.x),this.options.tms&&(t.y=e.y-t.y-1),t.z=this._getZoomForUrl()},_getSubdomain:function(t){var e=Math.abs(t.x+t.y)%this.options.subdomains.length;return this.options.subdomains[e]},_getTile:function(){if(this.options.reuseTiles&&this._unusedTiles.length>0){var t=this._unusedTiles.pop();return this._resetTile(t),t}return this._createTile()},_resetTile:function(){},_createTile:function(){var t=o.DomUtil.create("img","leaflet-tile");return t.style.width=t.style.height=this._getTileSize()+"px",t.galleryimg="no",t.onselectstart=t.onmousemove=o.Util.falseFn,o.Browser.ielt9&&this.options.opacity!==i&&o.DomUtil.setOpacity(t,this.options.opacity),o.Browser.mobileWebkit3d&&(t.style.WebkitBackfaceVisibility="hidden"),t},_loadTile:function(t,e){t._layer=this,t.onload=this._tileOnLoad,t.onerror=this._tileOnError,this._adjustTilePoint(e),t.src=this.getTileUrl(e),this.fire("tileloadstart",{tile:t,url:t.src})},_tileLoaded:function(){this._tilesToLoad--,this._animated&&o.DomUtil.addClass(this._tileContainer,"leaflet-zoom-animated"),this._tilesToLoad||(this.fire("load"),this._animated&&(clearTimeout(this._clearBgBufferTimer),this._clearBgBufferTimer=setTimeout(o.bind(this._clearBgBuffer,this),500)))},_tileOnLoad:function(){var t=this._layer;this.src!==o.Util.emptyImageUrl&&(o.DomUtil.addClass(this,"leaflet-tile-loaded"),t.fire("tileload",{tile:this,url:this.src})),t._tileLoaded()},_tileOnError:function(){var t=this._layer;t.fire("tileerror",{tile:this,url:this.src});var e=t.options.errorTileUrl;e&&(this.src=e),t._tileLoaded()}}),o.tileLayer=function(t,e){return new o.TileLayer(t,e)},o.TileLayer.WMS=o.TileLayer.extend({defaultWmsParams:{service:"WMS",request:"GetMap",version:"1.1.1",layers:"",styles:"",format:"image/jpeg",transparent:!1},initialize:function(t,e){this._url=t;var i=o.extend({},this.defaultWmsParams),n=e.tileSize||this.options.tileSize;i.width=i.height=e.detectRetina&&o.Browser.retina?2*n:n;for(var s in e)this.options.hasOwnProperty(s)||"crs"===s||(i[s]=e[s]);this.wmsParams=i,o.setOptions(this,e)},onAdd:function(t){this._crs=this.options.crs||t.options.crs,this._wmsVersion=parseFloat(this.wmsParams.version);var e=this._wmsVersion>=1.3?"crs":"srs";this.wmsParams[e]=this._crs.code,o.TileLayer.prototype.onAdd.call(this,t)},getTileUrl:function(t){var e=this._map,i=this.options.tileSize,n=t.multiplyBy(i),s=n.add([i,i]),a=this._crs.project(e.unproject(n,t.z)),r=this._crs.project(e.unproject(s,t.z)),h=this._wmsVersion>=1.3&&this._crs===o.CRS.EPSG4326?[r.y,a.x,a.y,r.x].join(","):[a.x,r.y,r.x,a.y].join(","),l=o.Util.template(this._url,{s:this._getSubdomain(t)});return l+o.Util.getParamString(this.wmsParams,l,!0)+"&BBOX="+h},setParams:function(t,e){return o.extend(this.wmsParams,t),e||this.redraw(),this}}),o.tileLayer.wms=function(t,e){return new o.TileLayer.WMS(t,e)},o.TileLayer.Canvas=o.TileLayer.extend({options:{async:!1},initialize:function(t){o.setOptions(this,t)},redraw:function(){this._map&&(this._reset({hard:!0}),this._update());for(var t in this._tiles)this._redrawTile(this._tiles[t]);return this},_redrawTile:function(t){this.drawTile(t,t._tilePoint,this._map._zoom)},_createTile:function(){var t=o.DomUtil.create("canvas","leaflet-tile");return t.width=t.height=this.options.tileSize,t.onselectstart=t.onmousemove=o.Util.falseFn,t},_loadTile:function(t,e){t._layer=this,t._tilePoint=e,this._redrawTile(t),this.options.async||this.tileDrawn(t)},drawTile:function(){},tileDrawn:function(t){this._tileOnLoad.call(t)}}),o.tileLayer.canvas=function(t){return new o.TileLayer.Canvas(t)},o.ImageOverlay=o.Class.extend({includes:o.Mixin.Events,options:{opacity:1},initialize:function(t,e,i){this._url=t,this._bounds=o.latLngBounds(e),o.setOptions(this,i)},onAdd:function(t){this._map=t,this._image||this._initImage(),t._panes.overlayPane.appendChild(this._image),t.on("viewreset",this._reset,this),t.options.zoomAnimation&&o.Browser.any3d&&t.on("zoomanim",this._animateZoom,this),this._reset()},onRemove:function(t){t.getPanes().overlayPane.removeChild(this._image),t.off("viewreset",this._reset,this),t.options.zoomAnimation&&t.off("zoomanim",this._animateZoom,this)},addTo:function(t){return t.addLayer(this),this},setOpacity:function(t){return this.options.opacity=t,this._updateOpacity(),this},bringToFront:function(){return this._image&&this._map._panes.overlayPane.appendChild(this._image),this},bringToBack:function(){var t=this._map._panes.overlayPane;return this._image&&t.insertBefore(this._image,t.firstChild),this},setUrl:function(t){this._url=t,this._image.src=this._url},getAttribution:function(){return this.options.attribution},_initImage:function(){this._image=o.DomUtil.create("img","leaflet-image-layer"),this._map.options.zoomAnimation&&o.Browser.any3d?o.DomUtil.addClass(this._image,"leaflet-zoom-animated"):o.DomUtil.addClass(this._image,"leaflet-zoom-hide"),this._updateOpacity(),o.extend(this._image,{galleryimg:"no",onselectstart:o.Util.falseFn,onmousemove:o.Util.falseFn,onload:o.bind(this._onImageLoad,this),src:this._url})},_animateZoom:function(t){var e=this._map,i=this._image,n=e.getZoomScale(t.zoom),s=this._bounds.getNorthWest(),a=this._bounds.getSouthEast(),r=e._latLngToNewLayerPoint(s,t.zoom,t.center),h=e._latLngToNewLayerPoint(a,t.zoom,t.center)._subtract(r),l=r._add(h._multiplyBy(.5*(1-1/n)));i.style[o.DomUtil.TRANSFORM]=o.DomUtil.getTranslateString(l)+" scale("+n+") "},_reset:function(){var t=this._image,e=this._map.latLngToLayerPoint(this._bounds.getNorthWest()),i=this._map.latLngToLayerPoint(this._bounds.getSouthEast())._subtract(e);o.DomUtil.setPosition(t,e),t.style.width=i.x+"px",t.style.height=i.y+"px"},_onImageLoad:function(){this.fire("load")},_updateOpacity:function(){o.DomUtil.setOpacity(this._image,this.options.opacity)}}),o.imageOverlay=function(t,e,i){return new o.ImageOverlay(t,e,i)},o.Icon=o.Class.extend({options:{className:""},initialize:function(t){o.setOptions(this,t)},createIcon:function(t){return this._createIcon("icon",t)},createShadow:function(t){return this._createIcon("shadow",t)},_createIcon:function(t,e){var i=this._getIconUrl(t);if(!i){if("icon"===t)throw new Error("iconUrl not set in Icon options (see the docs).");return null}var n;return n=e&&"IMG"===e.tagName?this._createImg(i,e):this._createImg(i),this._setIconStyles(n,t),n},_setIconStyles:function(t,e){var i,n=this.options,s=o.point(n[e+"Size"]);i=o.point("shadow"===e?n.shadowAnchor||n.iconAnchor:n.iconAnchor),!i&&s&&(i=s.divideBy(2,!0)),t.className="leaflet-marker-"+e+" "+n.className,i&&(t.style.marginLeft=-i.x+"px",t.style.marginTop=-i.y+"px"),s&&(t.style.width=s.x+"px",t.style.height=s.y+"px")},_createImg:function(t,i){return i=i||e.createElement("img"),i.src=t,i},_getIconUrl:function(t){return o.Browser.retina&&this.options[t+"RetinaUrl"]?this.options[t+"RetinaUrl"]:this.options[t+"Url"]}}),o.icon=function(t){return new o.Icon(t)},o.Icon.Default=o.Icon.extend({options:{iconSize:[25,41],iconAnchor:[12,41],popupAnchor:[1,-34],shadowSize:[41,41]},_getIconUrl:function(t){var e=t+"Url";if(this.options[e])return this.options[e];o.Browser.retina&&"icon"===t&&(t+="-2x");var i=o.Icon.Default.imagePath;if(!i)throw new Error("Couldn't autodetect L.Icon.Default.imagePath, set it manually.");return i+"/marker-"+t+".png"}}),o.Icon.Default.imagePath=function(){var t,i,n,o,s,a=e.getElementsByTagName("script"),r=/[\/^]leaflet[\-\._]?([\w\-\._]*)\.js\??/;for(t=0,i=a.length;i>t;t++)if(n=a[t].src,o=n.match(r))return s=n.split(r)[0],(s?s+"/":"")+"images"}(),o.Marker=o.Class.extend({includes:o.Mixin.Events,options:{icon:new o.Icon.Default,title:"",alt:"",clickable:!0,draggable:!1,keyboard:!0,zIndexOffset:0,opacity:1,riseOnHover:!1,riseOffset:250},initialize:function(t,e){o.setOptions(this,e),this._latlng=o.latLng(t)},onAdd:function(t){this._map=t,t.on("viewreset",this.update,this),this._initIcon(),this.update(),this.fire("add"),t.options.zoomAnimation&&t.options.markerZoomAnimation&&t.on("zoomanim",this._animateZoom,this)},addTo:function(t){return t.addLayer(this),this},onRemove:function(t){this.dragging&&this.dragging.disable(),this._removeIcon(),this._removeShadow(),this.fire("remove"),t.off({viewreset:this.update,zoomanim:this._animateZoom},this),this._map=null},getLatLng:function(){return this._latlng},setLatLng:function(t){return this._latlng=o.latLng(t),this.update(),this.fire("move",{latlng:this._latlng})},setZIndexOffset:function(t){return this.options.zIndexOffset=t,this.update(),this},setIcon:function(t){return this.options.icon=t,this._map&&(this._initIcon(),this.update()),this._popup&&this.bindPopup(this._popup),this},update:function(){if(this._icon){var t=this._map.latLngToLayerPoint(this._latlng).round();this._setPos(t)}return this},_initIcon:function(){var t=this.options,e=this._map,i=e.options.zoomAnimation&&e.options.markerZoomAnimation,n=i?"leaflet-zoom-animated":"leaflet-zoom-hide",s=t.icon.createIcon(this._icon),a=!1;s!==this._icon&&(this._icon&&this._removeIcon(),a=!0,t.title&&(s.title=t.title),t.alt&&(s.alt=t.alt)),o.DomUtil.addClass(s,n),t.keyboard&&(s.tabIndex="0"),this._icon=s,this._initInteraction(),t.riseOnHover&&o.DomEvent.on(s,"mouseover",this._bringToFront,this).on(s,"mouseout",this._resetZIndex,this);var r=t.icon.createShadow(this._shadow),h=!1;r!==this._shadow&&(this._removeShadow(),h=!0),r&&o.DomUtil.addClass(r,n),this._shadow=r,t.opacity<1&&this._updateOpacity();var l=this._map._panes;a&&l.markerPane.appendChild(this._icon),r&&h&&l.shadowPane.appendChild(this._shadow)},_removeIcon:function(){this.options.riseOnHover&&o.DomEvent.off(this._icon,"mouseover",this._bringToFront).off(this._icon,"mouseout",this._resetZIndex),this._map._panes.markerPane.removeChild(this._icon),this._icon=null},_removeShadow:function(){this._shadow&&this._map._panes.shadowPane.removeChild(this._shadow),this._shadow=null},_setPos:function(t){o.DomUtil.setPosition(this._icon,t),this._shadow&&o.DomUtil.setPosition(this._shadow,t),this._zIndex=t.y+this.options.zIndexOffset,this._resetZIndex()},_updateZIndex:function(t){this._icon.style.zIndex=this._zIndex+t},_animateZoom:function(t){var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center).round();this._setPos(e)},_initInteraction:function(){if(this.options.clickable){var t=this._icon,e=["dblclick","mousedown","mouseover","mouseout","contextmenu"];o.DomUtil.addClass(t,"leaflet-clickable"),o.DomEvent.on(t,"click",this._onMouseClick,this),o.DomEvent.on(t,"keypress",this._onKeyPress,this);for(var i=0;i<e.length;i++)o.DomEvent.on(t,e[i],this._fireMouseEvent,this);o.Handler.MarkerDrag&&(this.dragging=new o.Handler.MarkerDrag(this),this.options.draggable&&this.dragging.enable())}},_onMouseClick:function(t){var e=this.dragging&&this.dragging.moved();(this.hasEventListeners(t.type)||e)&&o.DomEvent.stopPropagation(t),e||(this.dragging&&this.dragging._enabled||!this._map.dragging||!this._map.dragging.moved())&&this.fire(t.type,{originalEvent:t,latlng:this._latlng})},_onKeyPress:function(t){13===t.keyCode&&this.fire("click",{originalEvent:t,latlng:this._latlng})},_fireMouseEvent:function(t){this.fire(t.type,{originalEvent:t,latlng:this._latlng}),"contextmenu"===t.type&&this.hasEventListeners(t.type)&&o.DomEvent.preventDefault(t),"mousedown"!==t.type?o.DomEvent.stopPropagation(t):o.DomEvent.preventDefault(t)},setOpacity:function(t){return this.options.opacity=t,this._map&&this._updateOpacity(),this},_updateOpacity:function(){o.DomUtil.setOpacity(this._icon,this.options.opacity),this._shadow&&o.DomUtil.setOpacity(this._shadow,this.options.opacity)},_bringToFront:function(){this._updateZIndex(this.options.riseOffset)},_resetZIndex:function(){this._updateZIndex(0)}}),o.marker=function(t,e){return new o.Marker(t,e)},o.DivIcon=o.Icon.extend({options:{iconSize:[12,12],className:"leaflet-div-icon",html:!1},createIcon:function(t){var i=t&&"DIV"===t.tagName?t:e.createElement("div"),n=this.options;return i.innerHTML=n.html!==!1?n.html:"",n.bgPos&&(i.style.backgroundPosition=-n.bgPos.x+"px "+-n.bgPos.y+"px"),this._setIconStyles(i,"icon"),i},createShadow:function(){return null}}),o.divIcon=function(t){return new o.DivIcon(t)},o.Map.mergeOptions({closePopupOnClick:!0}),o.Popup=o.Class.extend({includes:o.Mixin.Events,options:{minWidth:50,maxWidth:300,autoPan:!0,closeButton:!0,offset:[0,7],autoPanPadding:[5,5],keepInView:!1,className:"",zoomAnimation:!0},initialize:function(t,e){o.setOptions(this,t),this._source=e,this._animated=o.Browser.any3d&&this.options.zoomAnimation,this._isOpen=!1},onAdd:function(t){this._map=t,this._container||this._initLayout();var e=t.options.fadeAnimation;e&&o.DomUtil.setOpacity(this._container,0),t._panes.popupPane.appendChild(this._container),t.on(this._getEvents(),this),this.update(),e&&o.DomUtil.setOpacity(this._container,1),this.fire("open"),t.fire("popupopen",{popup:this}),this._source&&this._source.fire("popupopen",{popup:this})},addTo:function(t){return t.addLayer(this),this},openOn:function(t){return t.openPopup(this),this},onRemove:function(t){t._panes.popupPane.removeChild(this._container),o.Util.falseFn(this._container.offsetWidth),t.off(this._getEvents(),this),t.options.fadeAnimation&&o.DomUtil.setOpacity(this._container,0),this._map=null,this.fire("close"),t.fire("popupclose",{popup:this}),this._source&&this._source.fire("popupclose",{popup:this})},getLatLng:function(){return this._latlng},setLatLng:function(t){return this._latlng=o.latLng(t),this._map&&(this._updatePosition(),this._adjustPan()),this},getContent:function(){return this._content},setContent:function(t){return this._content=t,this.update(),this},update:function(){this._map&&(this._container.style.visibility="hidden",this._updateContent(),this._updateLayout(),this._updatePosition(),this._container.style.visibility="",this._adjustPan())},_getEvents:function(){var t={viewreset:this._updatePosition};return this._animated&&(t.zoomanim=this._zoomAnimation),("closeOnClick"in this.options?this.options.closeOnClick:this._map.options.closePopupOnClick)&&(t.preclick=this._close),this.options.keepInView&&(t.moveend=this._adjustPan),t},_close:function(){this._map&&this._map.closePopup(this)},_initLayout:function(){var t,e="leaflet-popup",i=e+" "+this.options.className+" leaflet-zoom-"+(this._animated?"animated":"hide"),n=this._container=o.DomUtil.create("div",i);this.options.closeButton&&(t=this._closeButton=o.DomUtil.create("a",e+"-close-button",n),t.href="#close",t.innerHTML="×",o.DomEvent.disableClickPropagation(t),o.DomEvent.on(t,"click",this._onCloseButtonClick,this));var s=this._wrapper=o.DomUtil.create("div",e+"-content-wrapper",n);o.DomEvent.disableClickPropagation(s),this._contentNode=o.DomUtil.create("div",e+"-content",s),o.DomEvent.disableScrollPropagation(this._contentNode),o.DomEvent.on(s,"contextmenu",o.DomEvent.stopPropagation),this._tipContainer=o.DomUtil.create("div",e+"-tip-container",n),this._tip=o.DomUtil.create("div",e+"-tip",this._tipContainer)},_updateContent:function(){if(this._content){if("string"==typeof this._content)this._contentNode.innerHTML=this._content;else{for(;this._contentNode.hasChildNodes();)this._contentNode.removeChild(this._contentNode.firstChild);this._contentNode.appendChild(this._content)}this.fire("contentupdate")}},_updateLayout:function(){var t=this._contentNode,e=t.style;e.width="",e.whiteSpace="nowrap";var i=t.offsetWidth;i=Math.min(i,this.options.maxWidth),i=Math.max(i,this.options.minWidth),e.width=i+1+"px",e.whiteSpace="",e.height="";var n=t.offsetHeight,s=this.options.maxHeight,a="leaflet-popup-scrolled";s&&n>s?(e.height=s+"px",o.DomUtil.addClass(t,a)):o.DomUtil.removeClass(t,a),this._containerWidth=this._container.offsetWidth},_updatePosition:function(){if(this._map){var t=this._map.latLngToLayerPoint(this._latlng),e=this._animated,i=o.point(this.options.offset);e&&o.DomUtil.setPosition(this._container,t),this._containerBottom=-i.y-(e?0:t.y),this._containerLeft=-Math.round(this._containerWidth/2)+i.x+(e?0:t.x),this._container.style.bottom=this._containerBottom+"px",this._container.style.left=this._containerLeft+"px"}},_zoomAnimation:function(t){var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center);o.DomUtil.setPosition(this._container,e)},_adjustPan:function(){if(this.options.autoPan){var t=this._map,e=this._container.offsetHeight,i=this._containerWidth,n=new o.Point(this._containerLeft,-e-this._containerBottom);this._animated&&n._add(o.DomUtil.getPosition(this._container));var s=t.layerPointToContainerPoint(n),a=o.point(this.options.autoPanPadding),r=o.point(this.options.autoPanPaddingTopLeft||a),h=o.point(this.options.autoPanPaddingBottomRight||a),l=t.getSize(),u=0,c=0;s.x+i+h.x>l.x&&(u=s.x+i-l.x+h.x),s.x-u-r.x<0&&(u=s.x-r.x),s.y+e+h.y>l.y&&(c=s.y+e-l.y+h.y),s.y-c-r.y<0&&(c=s.y-r.y),(u||c)&&t.fire("autopanstart").panBy([u,c])}},_onCloseButtonClick:function(t){this._close(),o.DomEvent.stop(t)}}),o.popup=function(t,e){return new o.Popup(t,e)},o.Map.include({openPopup:function(t,e,i){if(this.closePopup(),!(t instanceof o.Popup)){var n=t;t=new o.Popup(i).setLatLng(e).setContent(n)}return t._isOpen=!0,this._popup=t,this.addLayer(t)},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&(this.removeLayer(t),t._isOpen=!1),this}}),o.Marker.include({openPopup:function(){return this._popup&&this._map&&!this._map.hasLayer(this._popup)&&(this._popup.setLatLng(this._latlng),this._map.openPopup(this._popup)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(){return this._popup&&(this._popup._isOpen?this.closePopup():this.openPopup()),this},bindPopup:function(t,e){var i=o.point(this.options.icon.options.popupAnchor||[0,0]);return i=i.add(o.Popup.prototype.options.offset),e&&e.offset&&(i=i.add(e.offset)),e=o.extend({offset:i},e),this._popupHandlersAdded||(this.on("click",this.togglePopup,this).on("remove",this.closePopup,this).on("move",this._movePopup,this),this._popupHandlersAdded=!0),t instanceof o.Popup?(o.setOptions(t,e),this._popup=t):this._popup=new o.Popup(e,this).setContent(t),this},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},unbindPopup:function(){return this._popup&&(this._popup=null,this.off("click",this.togglePopup,this).off("remove",this.closePopup,this).off("move",this._movePopup,this),this._popupHandlersAdded=!1),this},getPopup:function(){return this._popup},_movePopup:function(t){this._popup.setLatLng(t.latlng)}}),o.LayerGroup=o.Class.extend({initialize:function(t){this._layers={};var e,i;if(t)for(e=0,i=t.length;i>e;e++)this.addLayer(t[e])},addLayer:function(t){var e=this.getLayerId(t);return this._layers[e]=t,this._map&&this._map.addLayer(t),this},removeLayer:function(t){var e=t in this._layers?t:this.getLayerId(t);return this._map&&this._layers[e]&&this._map.removeLayer(this._layers[e]),delete this._layers[e],this},hasLayer:function(t){return t?t in this._layers||this.getLayerId(t)in this._layers:!1},clearLayers:function(){return this.eachLayer(this.removeLayer,this),this},invoke:function(t){var e,i,n=Array.prototype.slice.call(arguments,1);for(e in this._layers)i=this._layers[e],i[t]&&i[t].apply(i,n);return this},onAdd:function(t){this._map=t,this.eachLayer(t.addLayer,t)},onRemove:function(t){this.eachLayer(t.removeLayer,t),this._map=null},addTo:function(t){return t.addLayer(this),this},eachLayer:function(t,e){for(var i in this._layers)t.call(e,this._layers[i]);return this},getLayer:function(t){return this._layers[t]},getLayers:function(){var t=[];for(var e in this._layers)t.push(this._layers[e]);return t},setZIndex:function(t){return this.invoke("setZIndex",t)},getLayerId:function(t){return o.stamp(t)}}),o.layerGroup=function(t){return new o.LayerGroup(t)},o.FeatureGroup=o.LayerGroup.extend({includes:o.Mixin.Events,statics:{EVENTS:"click dblclick mouseover mouseout mousemove contextmenu popupopen popupclose"},addLayer:function(t){return this.hasLayer(t)?this:("on"in t&&t.on(o.FeatureGroup.EVENTS,this._propagateEvent,this),o.LayerGroup.prototype.addLayer.call(this,t),this._popupContent&&t.bindPopup&&t.bindPopup(this._popupContent,this._popupOptions),this.fire("layeradd",{layer:t}))},removeLayer:function(t){return this.hasLayer(t)?(t in this._layers&&(t=this._layers[t]),t.off(o.FeatureGroup.EVENTS,this._propagateEvent,this),o.LayerGroup.prototype.removeLayer.call(this,t),this._popupContent&&this.invoke("unbindPopup"),this.fire("layerremove",{layer:t})):this},bindPopup:function(t,e){return this._popupContent=t,this._popupOptions=e,this.invoke("bindPopup",t,e)},openPopup:function(t){for(var e in this._layers){this._layers[e].openPopup(t);break}return this},setStyle:function(t){return this.invoke("setStyle",t)},bringToFront:function(){return this.invoke("bringToFront")},bringToBack:function(){return this.invoke("bringToBack")},getBounds:function(){var t=new o.LatLngBounds;return this.eachLayer(function(e){t.extend(e instanceof o.Marker?e.getLatLng():e.getBounds())}),t},_propagateEvent:function(t){t=o.extend({layer:t.target,target:this},t),this.fire(t.type,t)}}),o.featureGroup=function(t){return new o.FeatureGroup(t)},o.Path=o.Class.extend({includes:[o.Mixin.Events],statics:{CLIP_PADDING:function(){var e=o.Browser.mobile?1280:2e3,i=(e/Math.max(t.outerWidth,t.outerHeight)-1)/2;return Math.max(0,Math.min(.5,i))}()},options:{stroke:!0,color:"#0033ff",dashArray:null,lineCap:null,lineJoin:null,weight:5,opacity:.5,fill:!1,fillColor:null,fillOpacity:.2,clickable:!0},initialize:function(t){o.setOptions(this,t)},onAdd:function(t){this._map=t,this._container||(this._initElements(),this._initEvents()),this.projectLatlngs(),this._updatePath(),this._container&&this._map._pathRoot.appendChild(this._container),this.fire("add"),t.on({viewreset:this.projectLatlngs,moveend:this._updatePath},this)},addTo:function(t){return t.addLayer(this),this},onRemove:function(t){t._pathRoot.removeChild(this._container),this.fire("remove"),this._map=null,o.Browser.vml&&(this._container=null,this._stroke=null,this._fill=null),t.off({viewreset:this.projectLatlngs,moveend:this._updatePath},this)},projectLatlngs:function(){},setStyle:function(t){return o.setOptions(this,t),this._container&&this._updateStyle(),this},redraw:function(){return this._map&&(this.projectLatlngs(),this._updatePath()),this}}),o.Map.include({_updatePathViewport:function(){var t=o.Path.CLIP_PADDING,e=this.getSize(),i=o.DomUtil.getPosition(this._mapPane),n=i.multiplyBy(-1)._subtract(e.multiplyBy(t)._round()),s=n.add(e.multiplyBy(1+2*t)._round());this._pathViewport=new o.Bounds(n,s)}}),o.Path.SVG_NS="http://www.w3.org/2000/svg",o.Browser.svg=!(!e.createElementNS||!e.createElementNS(o.Path.SVG_NS,"svg").createSVGRect),o.Path=o.Path.extend({statics:{SVG:o.Browser.svg},bringToFront:function(){var t=this._map._pathRoot,e=this._container;return e&&t.lastChild!==e&&t.appendChild(e),this},bringToBack:function(){var t=this._map._pathRoot,e=this._container,i=t.firstChild;return e&&i!==e&&t.insertBefore(e,i),this},getPathString:function(){},_createElement:function(t){return e.createElementNS(o.Path.SVG_NS,t)},_initElements:function(){this._map._initPathRoot(),this._initPath(),this._initStyle()},_initPath:function(){this._container=this._createElement("g"),this._path=this._createElement("path"),this.options.className&&o.DomUtil.addClass(this._path,this.options.className),this._container.appendChild(this._path)},_initStyle:function(){this.options.stroke&&(this._path.setAttribute("stroke-linejoin","round"),this._path.setAttribute("stroke-linecap","round")),this.options.fill&&this._path.setAttribute("fill-rule","evenodd"),this.options.pointerEvents&&this._path.setAttribute("pointer-events",this.options.pointerEvents),this.options.clickable||this.options.pointerEvents||this._path.setAttribute("pointer-events","none"),this._updateStyle()},_updateStyle:function(){this.options.stroke?(this._path.setAttribute("stroke",this.options.color),this._path.setAttribute("stroke-opacity",this.options.opacity),this._path.setAttribute("stroke-width",this.options.weight),this.options.dashArray?this._path.setAttribute("stroke-dasharray",this.options.dashArray):this._path.removeAttribute("stroke-dasharray"),this.options.lineCap&&this._path.setAttribute("stroke-linecap",this.options.lineCap),this.options.lineJoin&&this._path.setAttribute("stroke-linejoin",this.options.lineJoin)):this._path.setAttribute("stroke","none"),this.options.fill?(this._path.setAttribute("fill",this.options.fillColor||this.options.color),this._path.setAttribute("fill-opacity",this.options.fillOpacity)):this._path.setAttribute("fill","none")},_updatePath:function(){var t=this.getPathString();t||(t="M0 0"),this._path.setAttribute("d",t)},_initEvents:function(){if(this.options.clickable){(o.Browser.svg||!o.Browser.vml)&&o.DomUtil.addClass(this._path,"leaflet-clickable"),o.DomEvent.on(this._container,"click",this._onMouseClick,this);for(var t=["dblclick","mousedown","mouseover","mouseout","mousemove","contextmenu"],e=0;e<t.length;e++)o.DomEvent.on(this._container,t[e],this._fireMouseEvent,this)}},_onMouseClick:function(t){this._map.dragging&&this._map.dragging.moved()||this._fireMouseEvent(t)},_fireMouseEvent:function(t){if(this.hasEventListeners(t.type)){var e=this._map,i=e.mouseEventToContainerPoint(t),n=e.containerPointToLayerPoint(i),s=e.layerPointToLatLng(n);this.fire(t.type,{latlng:s,layerPoint:n,containerPoint:i,originalEvent:t}),"contextmenu"===t.type&&o.DomEvent.preventDefault(t),"mousemove"!==t.type&&o.DomEvent.stopPropagation(t)}}}),o.Map.include({_initPathRoot:function(){this._pathRoot||(this._pathRoot=o.Path.prototype._createElement("svg"),this._panes.overlayPane.appendChild(this._pathRoot),this.options.zoomAnimation&&o.Browser.any3d?(o.DomUtil.addClass(this._pathRoot,"leaflet-zoom-animated"),this.on({zoomanim:this._animatePathZoom,zoomend:this._endPathZoom})):o.DomUtil.addClass(this._pathRoot,"leaflet-zoom-hide"),this.on("moveend",this._updateSvgViewport),this._updateSvgViewport()) | ||
8 | +},_animatePathZoom:function(t){var e=this.getZoomScale(t.zoom),i=this._getCenterOffset(t.center)._multiplyBy(-e)._add(this._pathViewport.min);this._pathRoot.style[o.DomUtil.TRANSFORM]=o.DomUtil.getTranslateString(i)+" scale("+e+") ",this._pathZooming=!0},_endPathZoom:function(){this._pathZooming=!1},_updateSvgViewport:function(){if(!this._pathZooming){this._updatePathViewport();var t=this._pathViewport,e=t.min,i=t.max,n=i.x-e.x,s=i.y-e.y,a=this._pathRoot,r=this._panes.overlayPane;o.Browser.mobileWebkit&&r.removeChild(a),o.DomUtil.setPosition(a,e),a.setAttribute("width",n),a.setAttribute("height",s),a.setAttribute("viewBox",[e.x,e.y,n,s].join(" ")),o.Browser.mobileWebkit&&r.appendChild(a)}}}),o.Path.include({bindPopup:function(t,e){return t instanceof o.Popup?this._popup=t:((!this._popup||e)&&(this._popup=new o.Popup(e,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on("click",this._openPopup,this).on("remove",this.closePopup,this),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this._popup=null,this.off("click",this._openPopup).off("remove",this.closePopup),this._popupHandlersAdded=!1),this},openPopup:function(t){return this._popup&&(t=t||this._latlng||this._latlngs[Math.floor(this._latlngs.length/2)],this._openPopup({latlng:t})),this},closePopup:function(){return this._popup&&this._popup._close(),this},_openPopup:function(t){this._popup.setLatLng(t.latlng),this._map.openPopup(this._popup)}}),o.Browser.vml=!o.Browser.svg&&function(){try{var t=e.createElement("div");t.innerHTML='<v:shape adj="1"/>';var i=t.firstChild;return i.style.behavior="url(#default#VML)",i&&"object"==typeof i.adj}catch(n){return!1}}(),o.Path=o.Browser.svg||!o.Browser.vml?o.Path:o.Path.extend({statics:{VML:!0,CLIP_PADDING:.02},_createElement:function(){try{return e.namespaces.add("lvml","urn:schemas-microsoft-com:vml"),function(t){return e.createElement("<lvml:"+t+' class="lvml">')}}catch(t){return function(t){return e.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),_initPath:function(){var t=this._container=this._createElement("shape");o.DomUtil.addClass(t,"leaflet-vml-shape"+(this.options.className?" "+this.options.className:"")),this.options.clickable&&o.DomUtil.addClass(t,"leaflet-clickable"),t.coordsize="1 1",this._path=this._createElement("path"),t.appendChild(this._path),this._map._pathRoot.appendChild(t)},_initStyle:function(){this._updateStyle()},_updateStyle:function(){var t=this._stroke,e=this._fill,i=this.options,n=this._container;n.stroked=i.stroke,n.filled=i.fill,i.stroke?(t||(t=this._stroke=this._createElement("stroke"),t.endcap="round",n.appendChild(t)),t.weight=i.weight+"px",t.color=i.color,t.opacity=i.opacity,t.dashStyle=i.dashArray?o.Util.isArray(i.dashArray)?i.dashArray.join(" "):i.dashArray.replace(/( *, *)/g," "):"",i.lineCap&&(t.endcap=i.lineCap.replace("butt","flat")),i.lineJoin&&(t.joinstyle=i.lineJoin)):t&&(n.removeChild(t),this._stroke=null),i.fill?(e||(e=this._fill=this._createElement("fill"),n.appendChild(e)),e.color=i.fillColor||i.color,e.opacity=i.fillOpacity):e&&(n.removeChild(e),this._fill=null)},_updatePath:function(){var t=this._container.style;t.display="none",this._path.v=this.getPathString()+" ",t.display=""}}),o.Map.include(o.Browser.svg||!o.Browser.vml?{}:{_initPathRoot:function(){if(!this._pathRoot){var t=this._pathRoot=e.createElement("div");t.className="leaflet-vml-container",this._panes.overlayPane.appendChild(t),this.on("moveend",this._updatePathViewport),this._updatePathViewport()}}}),o.Browser.canvas=function(){return!!e.createElement("canvas").getContext}(),o.Path=o.Path.SVG&&!t.L_PREFER_CANVAS||!o.Browser.canvas?o.Path:o.Path.extend({statics:{CANVAS:!0,SVG:!1},redraw:function(){return this._map&&(this.projectLatlngs(),this._requestUpdate()),this},setStyle:function(t){return o.setOptions(this,t),this._map&&(this._updateStyle(),this._requestUpdate()),this},onRemove:function(t){t.off("viewreset",this.projectLatlngs,this).off("moveend",this._updatePath,this),this.options.clickable&&(this._map.off("click",this._onClick,this),this._map.off("mousemove",this._onMouseMove,this)),this._requestUpdate(),this.fire("remove"),this._map=null},_requestUpdate:function(){this._map&&!o.Path._updateRequest&&(o.Path._updateRequest=o.Util.requestAnimFrame(this._fireMapMoveEnd,this._map))},_fireMapMoveEnd:function(){o.Path._updateRequest=null,this.fire("moveend")},_initElements:function(){this._map._initPathRoot(),this._ctx=this._map._canvasCtx},_updateStyle:function(){var t=this.options;t.stroke&&(this._ctx.lineWidth=t.weight,this._ctx.strokeStyle=t.color),t.fill&&(this._ctx.fillStyle=t.fillColor||t.color)},_drawPath:function(){var t,e,i,n,s,a;for(this._ctx.beginPath(),t=0,i=this._parts.length;i>t;t++){for(e=0,n=this._parts[t].length;n>e;e++)s=this._parts[t][e],a=(0===e?"move":"line")+"To",this._ctx[a](s.x,s.y);this instanceof o.Polygon&&this._ctx.closePath()}},_checkIfEmpty:function(){return!this._parts.length},_updatePath:function(){if(!this._checkIfEmpty()){var t=this._ctx,e=this.options;this._drawPath(),t.save(),this._updateStyle(),e.fill&&(t.globalAlpha=e.fillOpacity,t.fill()),e.stroke&&(t.globalAlpha=e.opacity,t.stroke()),t.restore()}},_initEvents:function(){this.options.clickable&&(this._map.on("mousemove",this._onMouseMove,this),this._map.on("click",this._onClick,this))},_onClick:function(t){this._containsPoint(t.layerPoint)&&this.fire("click",t)},_onMouseMove:function(t){this._map&&!this._map._animatingZoom&&(this._containsPoint(t.layerPoint)?(this._ctx.canvas.style.cursor="pointer",this._mouseInside=!0,this.fire("mouseover",t)):this._mouseInside&&(this._ctx.canvas.style.cursor="",this._mouseInside=!1,this.fire("mouseout",t)))}}),o.Map.include(o.Path.SVG&&!t.L_PREFER_CANVAS||!o.Browser.canvas?{}:{_initPathRoot:function(){var t,i=this._pathRoot;i||(i=this._pathRoot=e.createElement("canvas"),i.style.position="absolute",t=this._canvasCtx=i.getContext("2d"),t.lineCap="round",t.lineJoin="round",this._panes.overlayPane.appendChild(i),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){this._updatePathViewport();var t=this._pathViewport,e=t.min,i=t.max.subtract(e),n=this._pathRoot;o.DomUtil.setPosition(n,e),n.width=i.x,n.height=i.y,n.getContext("2d").translate(-e.x,-e.y)}}}),o.LineUtil={simplify:function(t,e){if(!e||!t.length)return t.slice();var i=e*e;return t=this._reducePoints(t,i),t=this._simplifyDP(t,i)},pointToSegmentDistance:function(t,e,i){return Math.sqrt(this._sqClosestPointOnSegment(t,e,i,!0))},closestPointOnSegment:function(t,e,i){return this._sqClosestPointOnSegment(t,e,i)},_simplifyDP:function(t,e){var n=t.length,o=typeof Uint8Array!=i+""?Uint8Array:Array,s=new o(n);s[0]=s[n-1]=1,this._simplifyDPStep(t,s,e,0,n-1);var a,r=[];for(a=0;n>a;a++)s[a]&&r.push(t[a]);return r},_simplifyDPStep:function(t,e,i,n,o){var s,a,r,h=0;for(a=n+1;o-1>=a;a++)r=this._sqClosestPointOnSegment(t[a],t[n],t[o],!0),r>h&&(s=a,h=r);h>i&&(e[s]=1,this._simplifyDPStep(t,e,i,n,s),this._simplifyDPStep(t,e,i,s,o))},_reducePoints:function(t,e){for(var i=[t[0]],n=1,o=0,s=t.length;s>n;n++)this._sqDist(t[n],t[o])>e&&(i.push(t[n]),o=n);return s-1>o&&i.push(t[s-1]),i},clipSegment:function(t,e,i,n){var o,s,a,r=n?this._lastCode:this._getBitCode(t,i),h=this._getBitCode(e,i);for(this._lastCode=h;;){if(!(r|h))return[t,e];if(r&h)return!1;o=r||h,s=this._getEdgeIntersection(t,e,o,i),a=this._getBitCode(s,i),o===r?(t=s,r=a):(e=s,h=a)}},_getEdgeIntersection:function(t,e,i,n){var s=e.x-t.x,a=e.y-t.y,r=n.min,h=n.max;return 8&i?new o.Point(t.x+s*(h.y-t.y)/a,h.y):4&i?new o.Point(t.x+s*(r.y-t.y)/a,r.y):2&i?new o.Point(h.x,t.y+a*(h.x-t.x)/s):1&i?new o.Point(r.x,t.y+a*(r.x-t.x)/s):void 0},_getBitCode:function(t,e){var i=0;return t.x<e.min.x?i|=1:t.x>e.max.x&&(i|=2),t.y<e.min.y?i|=4:t.y>e.max.y&&(i|=8),i},_sqDist:function(t,e){var i=e.x-t.x,n=e.y-t.y;return i*i+n*n},_sqClosestPointOnSegment:function(t,e,i,n){var s,a=e.x,r=e.y,h=i.x-a,l=i.y-r,u=h*h+l*l;return u>0&&(s=((t.x-a)*h+(t.y-r)*l)/u,s>1?(a=i.x,r=i.y):s>0&&(a+=h*s,r+=l*s)),h=t.x-a,l=t.y-r,n?h*h+l*l:new o.Point(a,r)}},o.Polyline=o.Path.extend({initialize:function(t,e){o.Path.prototype.initialize.call(this,e),this._latlngs=this._convertLatLngs(t)},options:{smoothFactor:1,noClip:!1},projectLatlngs:function(){this._originalPoints=[];for(var t=0,e=this._latlngs.length;e>t;t++)this._originalPoints[t]=this._map.latLngToLayerPoint(this._latlngs[t])},getPathString:function(){for(var t=0,e=this._parts.length,i="";e>t;t++)i+=this._getPathPartStr(this._parts[t]);return i},getLatLngs:function(){return this._latlngs},setLatLngs:function(t){return this._latlngs=this._convertLatLngs(t),this.redraw()},addLatLng:function(t){return this._latlngs.push(o.latLng(t)),this.redraw()},spliceLatLngs:function(){var t=[].splice.apply(this._latlngs,arguments);return this._convertLatLngs(this._latlngs,!0),this.redraw(),t},closestLayerPoint:function(t){for(var e,i,n=1/0,s=this._parts,a=null,r=0,h=s.length;h>r;r++)for(var l=s[r],u=1,c=l.length;c>u;u++){e=l[u-1],i=l[u];var d=o.LineUtil._sqClosestPointOnSegment(t,e,i,!0);n>d&&(n=d,a=o.LineUtil._sqClosestPointOnSegment(t,e,i))}return a&&(a.distance=Math.sqrt(n)),a},getBounds:function(){return new o.LatLngBounds(this.getLatLngs())},_convertLatLngs:function(t,e){var i,n,s=e?t:[];for(i=0,n=t.length;n>i;i++){if(o.Util.isArray(t[i])&&"number"!=typeof t[i][0])return;s[i]=o.latLng(t[i])}return s},_initEvents:function(){o.Path.prototype._initEvents.call(this)},_getPathPartStr:function(t){for(var e,i=o.Path.VML,n=0,s=t.length,a="";s>n;n++)e=t[n],i&&e._round(),a+=(n?"L":"M")+e.x+" "+e.y;return a},_clipPoints:function(){var t,e,i,n=this._originalPoints,s=n.length;if(this.options.noClip)return void(this._parts=[n]);this._parts=[];var a=this._parts,r=this._map._pathViewport,h=o.LineUtil;for(t=0,e=0;s-1>t;t++)i=h.clipSegment(n[t],n[t+1],r,t),i&&(a[e]=a[e]||[],a[e].push(i[0]),(i[1]!==n[t+1]||t===s-2)&&(a[e].push(i[1]),e++))},_simplifyPoints:function(){for(var t=this._parts,e=o.LineUtil,i=0,n=t.length;n>i;i++)t[i]=e.simplify(t[i],this.options.smoothFactor)},_updatePath:function(){this._map&&(this._clipPoints(),this._simplifyPoints(),o.Path.prototype._updatePath.call(this))}}),o.polyline=function(t,e){return new o.Polyline(t,e)},o.PolyUtil={},o.PolyUtil.clipPolygon=function(t,e){var i,n,s,a,r,h,l,u,c,d=[1,4,2,8],p=o.LineUtil;for(n=0,l=t.length;l>n;n++)t[n]._code=p._getBitCode(t[n],e);for(a=0;4>a;a++){for(u=d[a],i=[],n=0,l=t.length,s=l-1;l>n;s=n++)r=t[n],h=t[s],r._code&u?h._code&u||(c=p._getEdgeIntersection(h,r,u,e),c._code=p._getBitCode(c,e),i.push(c)):(h._code&u&&(c=p._getEdgeIntersection(h,r,u,e),c._code=p._getBitCode(c,e),i.push(c)),i.push(r));t=i}return t},o.Polygon=o.Polyline.extend({options:{fill:!0},initialize:function(t,e){o.Polyline.prototype.initialize.call(this,t,e),this._initWithHoles(t)},_initWithHoles:function(t){var e,i,n;if(t&&o.Util.isArray(t[0])&&"number"!=typeof t[0][0])for(this._latlngs=this._convertLatLngs(t[0]),this._holes=t.slice(1),e=0,i=this._holes.length;i>e;e++)n=this._holes[e]=this._convertLatLngs(this._holes[e]),n[0].equals(n[n.length-1])&&n.pop();t=this._latlngs,t.length>=2&&t[0].equals(t[t.length-1])&&t.pop()},projectLatlngs:function(){if(o.Polyline.prototype.projectLatlngs.call(this),this._holePoints=[],this._holes){var t,e,i,n;for(t=0,i=this._holes.length;i>t;t++)for(this._holePoints[t]=[],e=0,n=this._holes[t].length;n>e;e++)this._holePoints[t][e]=this._map.latLngToLayerPoint(this._holes[t][e])}},setLatLngs:function(t){return t&&o.Util.isArray(t[0])&&"number"!=typeof t[0][0]?(this._initWithHoles(t),this.redraw()):o.Polyline.prototype.setLatLngs.call(this,t)},_clipPoints:function(){var t=this._originalPoints,e=[];if(this._parts=[t].concat(this._holePoints),!this.options.noClip){for(var i=0,n=this._parts.length;n>i;i++){var s=o.PolyUtil.clipPolygon(this._parts[i],this._map._pathViewport);s.length&&e.push(s)}this._parts=e}},_getPathPartStr:function(t){var e=o.Polyline.prototype._getPathPartStr.call(this,t);return e+(o.Browser.svg?"z":"x")}}),o.polygon=function(t,e){return new o.Polygon(t,e)},function(){function t(t){return o.FeatureGroup.extend({initialize:function(t,e){this._layers={},this._options=e,this.setLatLngs(t)},setLatLngs:function(e){var i=0,n=e.length;for(this.eachLayer(function(t){n>i?t.setLatLngs(e[i++]):this.removeLayer(t)},this);n>i;)this.addLayer(new t(e[i++],this._options));return this},getLatLngs:function(){var t=[];return this.eachLayer(function(e){t.push(e.getLatLngs())}),t}})}o.MultiPolyline=t(o.Polyline),o.MultiPolygon=t(o.Polygon),o.multiPolyline=function(t,e){return new o.MultiPolyline(t,e)},o.multiPolygon=function(t,e){return new o.MultiPolygon(t,e)}}(),o.Rectangle=o.Polygon.extend({initialize:function(t,e){o.Polygon.prototype.initialize.call(this,this._boundsToLatLngs(t),e)},setBounds:function(t){this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return t=o.latLngBounds(t),[t.getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}}),o.rectangle=function(t,e){return new o.Rectangle(t,e)},o.Circle=o.Path.extend({initialize:function(t,e,i){o.Path.prototype.initialize.call(this,i),this._latlng=o.latLng(t),this._mRadius=e},options:{fill:!0},setLatLng:function(t){return this._latlng=o.latLng(t),this.redraw()},setRadius:function(t){return this._mRadius=t,this.redraw()},projectLatlngs:function(){var t=this._getLngRadius(),e=this._latlng,i=this._map.latLngToLayerPoint([e.lat,e.lng-t]);this._point=this._map.latLngToLayerPoint(e),this._radius=Math.max(this._point.x-i.x,1)},getBounds:function(){var t=this._getLngRadius(),e=this._mRadius/40075017*360,i=this._latlng;return new o.LatLngBounds([i.lat-e,i.lng-t],[i.lat+e,i.lng+t])},getLatLng:function(){return this._latlng},getPathString:function(){var t=this._point,e=this._radius;return this._checkIfEmpty()?"":o.Browser.svg?"M"+t.x+","+(t.y-e)+"A"+e+","+e+",0,1,1,"+(t.x-.1)+","+(t.y-e)+" z":(t._round(),e=Math.round(e),"AL "+t.x+","+t.y+" "+e+","+e+" 0,23592600")},getRadius:function(){return this._mRadius},_getLatRadius:function(){return this._mRadius/40075017*360},_getLngRadius:function(){return this._getLatRadius()/Math.cos(o.LatLng.DEG_TO_RAD*this._latlng.lat)},_checkIfEmpty:function(){if(!this._map)return!1;var t=this._map._pathViewport,e=this._radius,i=this._point;return i.x-e>t.max.x||i.y-e>t.max.y||i.x+e<t.min.x||i.y+e<t.min.y}}),o.circle=function(t,e,i){return new o.Circle(t,e,i)},o.CircleMarker=o.Circle.extend({options:{radius:10,weight:2},initialize:function(t,e){o.Circle.prototype.initialize.call(this,t,null,e),this._radius=this.options.radius},projectLatlngs:function(){this._point=this._map.latLngToLayerPoint(this._latlng)},_updateStyle:function(){o.Circle.prototype._updateStyle.call(this),this.setRadius(this.options.radius)},setLatLng:function(t){return o.Circle.prototype.setLatLng.call(this,t),this._popup&&this._popup._isOpen&&this._popup.setLatLng(t),this},setRadius:function(t){return this.options.radius=this._radius=t,this.redraw()},getRadius:function(){return this._radius}}),o.circleMarker=function(t,e){return new o.CircleMarker(t,e)},o.Polyline.include(o.Path.CANVAS?{_containsPoint:function(t,e){var i,n,s,a,r,h,l,u=this.options.weight/2;for(o.Browser.touch&&(u+=10),i=0,a=this._parts.length;a>i;i++)for(l=this._parts[i],n=0,r=l.length,s=r-1;r>n;s=n++)if((e||0!==n)&&(h=o.LineUtil.pointToSegmentDistance(t,l[s],l[n]),u>=h))return!0;return!1}}:{}),o.Polygon.include(o.Path.CANVAS?{_containsPoint:function(t){var e,i,n,s,a,r,h,l,u=!1;if(o.Polyline.prototype._containsPoint.call(this,t,!0))return!0;for(s=0,h=this._parts.length;h>s;s++)for(e=this._parts[s],a=0,l=e.length,r=l-1;l>a;r=a++)i=e[a],n=e[r],i.y>t.y!=n.y>t.y&&t.x<(n.x-i.x)*(t.y-i.y)/(n.y-i.y)+i.x&&(u=!u);return u}}:{}),o.Circle.include(o.Path.CANVAS?{_drawPath:function(){var t=this._point;this._ctx.beginPath(),this._ctx.arc(t.x,t.y,this._radius,0,2*Math.PI,!1)},_containsPoint:function(t){var e=this._point,i=this.options.stroke?this.options.weight/2:0;return t.distanceTo(e)<=this._radius+i}}:{}),o.CircleMarker.include(o.Path.CANVAS?{_updateStyle:function(){o.Path.prototype._updateStyle.call(this)}}:{}),o.GeoJSON=o.FeatureGroup.extend({initialize:function(t,e){o.setOptions(this,e),this._layers={},t&&this.addData(t)},addData:function(t){var e,i,n,s=o.Util.isArray(t)?t:t.features;if(s){for(e=0,i=s.length;i>e;e++)n=s[e],(n.geometries||n.geometry||n.features||n.coordinates)&&this.addData(s[e]);return this}var a=this.options;if(!a.filter||a.filter(t)){var r=o.GeoJSON.geometryToLayer(t,a.pointToLayer,a.coordsToLatLng,a);return r.feature=o.GeoJSON.asFeature(t),r.defaultOptions=r.options,this.resetStyle(r),a.onEachFeature&&a.onEachFeature(t,r),this.addLayer(r)}},resetStyle:function(t){var e=this.options.style;e&&(o.Util.extend(t.options,t.defaultOptions),this._setLayerStyle(t,e))},setStyle:function(t){this.eachLayer(function(e){this._setLayerStyle(e,t)},this)},_setLayerStyle:function(t,e){"function"==typeof e&&(e=e(t.feature)),t.setStyle&&t.setStyle(e)}}),o.extend(o.GeoJSON,{geometryToLayer:function(t,e,i,n){var s,a,r,h,l="Feature"===t.type?t.geometry:t,u=l.coordinates,c=[];switch(i=i||this.coordsToLatLng,l.type){case"Point":return s=i(u),e?e(t,s):new o.Marker(s);case"MultiPoint":for(r=0,h=u.length;h>r;r++)s=i(u[r]),c.push(e?e(t,s):new o.Marker(s));return new o.FeatureGroup(c);case"LineString":return a=this.coordsToLatLngs(u,0,i),new o.Polyline(a,n);case"Polygon":if(2===u.length&&!u[1].length)throw new Error("Invalid GeoJSON object.");return a=this.coordsToLatLngs(u,1,i),new o.Polygon(a,n);case"MultiLineString":return a=this.coordsToLatLngs(u,1,i),new o.MultiPolyline(a,n);case"MultiPolygon":return a=this.coordsToLatLngs(u,2,i),new o.MultiPolygon(a,n);case"GeometryCollection":for(r=0,h=l.geometries.length;h>r;r++)c.push(this.geometryToLayer({geometry:l.geometries[r],type:"Feature",properties:t.properties},e,i,n));return new o.FeatureGroup(c);default:throw new Error("Invalid GeoJSON object.")}},coordsToLatLng:function(t){return new o.LatLng(t[1],t[0],t[2])},coordsToLatLngs:function(t,e,i){var n,o,s,a=[];for(o=0,s=t.length;s>o;o++)n=e?this.coordsToLatLngs(t[o],e-1,i):(i||this.coordsToLatLng)(t[o]),a.push(n);return a},latLngToCoords:function(t){var e=[t.lng,t.lat];return t.alt!==i&&e.push(t.alt),e},latLngsToCoords:function(t){for(var e=[],i=0,n=t.length;n>i;i++)e.push(o.GeoJSON.latLngToCoords(t[i]));return e},getFeature:function(t,e){return t.feature?o.extend({},t.feature,{geometry:e}):o.GeoJSON.asFeature(e)},asFeature:function(t){return"Feature"===t.type?t:{type:"Feature",properties:{},geometry:t}}});var a={toGeoJSON:function(){return o.GeoJSON.getFeature(this,{type:"Point",coordinates:o.GeoJSON.latLngToCoords(this.getLatLng())})}};o.Marker.include(a),o.Circle.include(a),o.CircleMarker.include(a),o.Polyline.include({toGeoJSON:function(){return o.GeoJSON.getFeature(this,{type:"LineString",coordinates:o.GeoJSON.latLngsToCoords(this.getLatLngs())})}}),o.Polygon.include({toGeoJSON:function(){var t,e,i,n=[o.GeoJSON.latLngsToCoords(this.getLatLngs())];if(n[0].push(n[0][0]),this._holes)for(t=0,e=this._holes.length;e>t;t++)i=o.GeoJSON.latLngsToCoords(this._holes[t]),i.push(i[0]),n.push(i);return o.GeoJSON.getFeature(this,{type:"Polygon",coordinates:n})}}),function(){function t(t){return function(){var e=[];return this.eachLayer(function(t){e.push(t.toGeoJSON().geometry.coordinates)}),o.GeoJSON.getFeature(this,{type:t,coordinates:e})}}o.MultiPolyline.include({toGeoJSON:t("MultiLineString")}),o.MultiPolygon.include({toGeoJSON:t("MultiPolygon")}),o.LayerGroup.include({toGeoJSON:function(){var e,i=this.feature&&this.feature.geometry,n=[];if(i&&"MultiPoint"===i.type)return t("MultiPoint").call(this);var s=i&&"GeometryCollection"===i.type;return this.eachLayer(function(t){t.toGeoJSON&&(e=t.toGeoJSON(),n.push(s?e.geometry:o.GeoJSON.asFeature(e)))}),s?o.GeoJSON.getFeature(this,{geometries:n,type:"GeometryCollection"}):{type:"FeatureCollection",features:n}}})}(),o.geoJson=function(t,e){return new o.GeoJSON(t,e)},o.DomEvent={addListener:function(t,e,i,n){var s,a,r,h=o.stamp(i),l="_leaflet_"+e+h;return t[l]?this:(s=function(e){return i.call(n||t,e||o.DomEvent._getEvent())},o.Browser.pointer&&0===e.indexOf("touch")?this.addPointerListener(t,e,s,h):(o.Browser.touch&&"dblclick"===e&&this.addDoubleTapListener&&this.addDoubleTapListener(t,s,h),"addEventListener"in t?"mousewheel"===e?(t.addEventListener("DOMMouseScroll",s,!1),t.addEventListener(e,s,!1)):"mouseenter"===e||"mouseleave"===e?(a=s,r="mouseenter"===e?"mouseover":"mouseout",s=function(e){return o.DomEvent._checkMouse(t,e)?a(e):void 0},t.addEventListener(r,s,!1)):"click"===e&&o.Browser.android?(a=s,s=function(t){return o.DomEvent._filterClick(t,a)},t.addEventListener(e,s,!1)):t.addEventListener(e,s,!1):"attachEvent"in t&&t.attachEvent("on"+e,s),t[l]=s,this))},removeListener:function(t,e,i){var n=o.stamp(i),s="_leaflet_"+e+n,a=t[s];return a?(o.Browser.pointer&&0===e.indexOf("touch")?this.removePointerListener(t,e,n):o.Browser.touch&&"dblclick"===e&&this.removeDoubleTapListener?this.removeDoubleTapListener(t,n):"removeEventListener"in t?"mousewheel"===e?(t.removeEventListener("DOMMouseScroll",a,!1),t.removeEventListener(e,a,!1)):"mouseenter"===e||"mouseleave"===e?t.removeEventListener("mouseenter"===e?"mouseover":"mouseout",a,!1):t.removeEventListener(e,a,!1):"detachEvent"in t&&t.detachEvent("on"+e,a),t[s]=null,this):this},stopPropagation:function(t){return t.stopPropagation?t.stopPropagation():t.cancelBubble=!0,o.DomEvent._skipped(t),this},disableScrollPropagation:function(t){var e=o.DomEvent.stopPropagation;return o.DomEvent.on(t,"mousewheel",e).on(t,"MozMousePixelScroll",e)},disableClickPropagation:function(t){for(var e=o.DomEvent.stopPropagation,i=o.Draggable.START.length-1;i>=0;i--)o.DomEvent.on(t,o.Draggable.START[i],e);return o.DomEvent.on(t,"click",o.DomEvent._fakeStop).on(t,"dblclick",e)},preventDefault:function(t){return t.preventDefault?t.preventDefault():t.returnValue=!1,this},stop:function(t){return o.DomEvent.preventDefault(t).stopPropagation(t)},getMousePosition:function(t,e){if(!e)return new o.Point(t.clientX,t.clientY);var i=e.getBoundingClientRect();return new o.Point(t.clientX-i.left-e.clientLeft,t.clientY-i.top-e.clientTop)},getWheelDelta:function(t){var e=0;return t.wheelDelta&&(e=t.wheelDelta/120),t.detail&&(e=-t.detail/3),e},_skipEvents:{},_fakeStop:function(t){o.DomEvent._skipEvents[t.type]=!0},_skipped:function(t){var e=this._skipEvents[t.type];return this._skipEvents[t.type]=!1,e},_checkMouse:function(t,e){var i=e.relatedTarget;if(!i)return!0;try{for(;i&&i!==t;)i=i.parentNode}catch(n){return!1}return i!==t},_getEvent:function(){var e=t.event;if(!e)for(var i=arguments.callee.caller;i&&(e=i.arguments[0],!e||t.Event!==e.constructor);)i=i.caller;return e},_filterClick:function(t,e){var i=t.timeStamp||t.originalEvent.timeStamp,n=o.DomEvent._lastClick&&i-o.DomEvent._lastClick;return n&&n>100&&500>n||t.target._simulatedClick&&!t._simulated?void o.DomEvent.stop(t):(o.DomEvent._lastClick=i,e(t))}},o.DomEvent.on=o.DomEvent.addListener,o.DomEvent.off=o.DomEvent.removeListener,o.Draggable=o.Class.extend({includes:o.Mixin.Events,statics:{START:o.Browser.touch?["touchstart","mousedown"]:["mousedown"],END:{mousedown:"mouseup",touchstart:"touchend",pointerdown:"touchend",MSPointerDown:"touchend"},MOVE:{mousedown:"mousemove",touchstart:"touchmove",pointerdown:"touchmove",MSPointerDown:"touchmove"}},initialize:function(t,e){this._element=t,this._dragStartTarget=e||t},enable:function(){if(!this._enabled){for(var t=o.Draggable.START.length-1;t>=0;t--)o.DomEvent.on(this._dragStartTarget,o.Draggable.START[t],this._onDown,this);this._enabled=!0}},disable:function(){if(this._enabled){for(var t=o.Draggable.START.length-1;t>=0;t--)o.DomEvent.off(this._dragStartTarget,o.Draggable.START[t],this._onDown,this);this._enabled=!1,this._moved=!1}},_onDown:function(t){if(this._moved=!1,!(t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||(o.DomEvent.stopPropagation(t),o.Draggable._disabled||(o.DomUtil.disableImageDrag(),o.DomUtil.disableTextSelection(),this._moving)))){var i=t.touches?t.touches[0]:t;this._startPoint=new o.Point(i.clientX,i.clientY),this._startPos=this._newPos=o.DomUtil.getPosition(this._element),o.DomEvent.on(e,o.Draggable.MOVE[t.type],this._onMove,this).on(e,o.Draggable.END[t.type],this._onUp,this)}},_onMove:function(t){if(t.touches&&t.touches.length>1)return void(this._moved=!0);var i=t.touches&&1===t.touches.length?t.touches[0]:t,n=new o.Point(i.clientX,i.clientY),s=n.subtract(this._startPoint);(s.x||s.y)&&(o.Browser.touch&&Math.abs(s.x)+Math.abs(s.y)<3||(o.DomEvent.preventDefault(t),this._moved||(this.fire("dragstart"),this._moved=!0,this._startPos=o.DomUtil.getPosition(this._element).subtract(s),o.DomUtil.addClass(e.body,"leaflet-dragging"),this._lastTarget=t.target||t.srcElement,o.DomUtil.addClass(this._lastTarget,"leaflet-drag-target")),this._newPos=this._startPos.add(s),this._moving=!0,o.Util.cancelAnimFrame(this._animRequest),this._animRequest=o.Util.requestAnimFrame(this._updatePosition,this,!0,this._dragStartTarget)))},_updatePosition:function(){this.fire("predrag"),o.DomUtil.setPosition(this._element,this._newPos),this.fire("drag")},_onUp:function(){o.DomUtil.removeClass(e.body,"leaflet-dragging"),this._lastTarget&&(o.DomUtil.removeClass(this._lastTarget,"leaflet-drag-target"),this._lastTarget=null);for(var t in o.Draggable.MOVE)o.DomEvent.off(e,o.Draggable.MOVE[t],this._onMove).off(e,o.Draggable.END[t],this._onUp);o.DomUtil.enableImageDrag(),o.DomUtil.enableTextSelection(),this._moved&&this._moving&&(o.Util.cancelAnimFrame(this._animRequest),this.fire("dragend",{distance:this._newPos.distanceTo(this._startPos)})),this._moving=!1}}),o.Handler=o.Class.extend({initialize:function(t){this._map=t},enable:function(){this._enabled||(this._enabled=!0,this.addHooks())},disable:function(){this._enabled&&(this._enabled=!1,this.removeHooks())},enabled:function(){return!!this._enabled}}),o.Map.mergeOptions({dragging:!0,inertia:!o.Browser.android23,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,inertiaThreshold:o.Browser.touch?32:18,easeLinearity:.25,worldCopyJump:!1}),o.Map.Drag=o.Handler.extend({addHooks:function(){if(!this._draggable){var t=this._map;this._draggable=new o.Draggable(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDrag,this),t.on("viewreset",this._onViewReset,this),t.whenReady(this._onViewReset,this))}this._draggable.enable()},removeHooks:function(){this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},_onDragStart:function(){var t=this._map;t._panAnim&&t._panAnim.stop(),t.fire("movestart").fire("dragstart"),t.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(){if(this._map.options.inertia){var t=this._lastTime=+new Date,e=this._lastPos=this._draggable._newPos;this._positions.push(e),this._times.push(t),t-this._times[0]>200&&(this._positions.shift(),this._times.shift())}this._map.fire("move").fire("drag")},_onViewReset:function(){var t=this._map.getSize()._divideBy(2),e=this._map.latLngToLayerPoint([0,0]);this._initialWorldOffset=e.subtract(t).x,this._worldWidth=this._map.project([0,180]).x},_onPreDrag:function(){var t=this._worldWidth,e=Math.round(t/2),i=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-e+i)%t+e-i,s=(n+e+i)%t-e-i,a=Math.abs(o+i)<Math.abs(s+i)?o:s;this._draggable._newPos.x=a},_onDragEnd:function(t){var e=this._map,i=e.options,n=+new Date-this._lastTime,s=!i.inertia||n>i.inertiaThreshold||!this._positions[0];if(e.fire("dragend",t),s)e.fire("moveend");else{var a=this._lastPos.subtract(this._positions[0]),r=(this._lastTime+n-this._times[0])/1e3,h=i.easeLinearity,l=a.multiplyBy(h/r),u=l.distanceTo([0,0]),c=Math.min(i.inertiaMaxSpeed,u),d=l.multiplyBy(c/u),p=c/(i.inertiaDeceleration*h),_=d.multiplyBy(-p/2).round();_.x&&_.y?(_=e._limitOffset(_,e.options.maxBounds),o.Util.requestAnimFrame(function(){e.panBy(_,{duration:p,easeLinearity:h,noMoveStart:!0})})):e.fire("moveend")}}}),o.Map.addInitHook("addHandler","dragging",o.Map.Drag),o.Map.mergeOptions({doubleClickZoom:!0}),o.Map.DoubleClickZoom=o.Handler.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var e=this._map,i=e.getZoom()+(t.originalEvent.shiftKey?-1:1);"center"===e.options.doubleClickZoom?e.setZoom(i):e.setZoomAround(t.containerPoint,i)}}),o.Map.addInitHook("addHandler","doubleClickZoom",o.Map.DoubleClickZoom),o.Map.mergeOptions({scrollWheelZoom:!0}),o.Map.ScrollWheelZoom=o.Handler.extend({addHooks:function(){o.DomEvent.on(this._map._container,"mousewheel",this._onWheelScroll,this),o.DomEvent.on(this._map._container,"MozMousePixelScroll",o.DomEvent.preventDefault),this._delta=0},removeHooks:function(){o.DomEvent.off(this._map._container,"mousewheel",this._onWheelScroll),o.DomEvent.off(this._map._container,"MozMousePixelScroll",o.DomEvent.preventDefault)},_onWheelScroll:function(t){var e=o.DomEvent.getWheelDelta(t);this._delta+=e,this._lastMousePos=this._map.mouseEventToContainerPoint(t),this._startTime||(this._startTime=+new Date);var i=Math.max(40-(+new Date-this._startTime),0);clearTimeout(this._timer),this._timer=setTimeout(o.bind(this._performZoom,this),i),o.DomEvent.preventDefault(t),o.DomEvent.stopPropagation(t)},_performZoom:function(){var t=this._map,e=this._delta,i=t.getZoom();e=e>0?Math.ceil(e):Math.floor(e),e=Math.max(Math.min(e,4),-4),e=t._limitZoom(i+e)-i,this._delta=0,this._startTime=null,e&&("center"===t.options.scrollWheelZoom?t.setZoom(i+e):t.setZoomAround(this._lastMousePos,i+e))}}),o.Map.addInitHook("addHandler","scrollWheelZoom",o.Map.ScrollWheelZoom),o.extend(o.DomEvent,{_touchstart:o.Browser.msPointer?"MSPointerDown":o.Browser.pointer?"pointerdown":"touchstart",_touchend:o.Browser.msPointer?"MSPointerUp":o.Browser.pointer?"pointerup":"touchend",addDoubleTapListener:function(t,i,n){function s(t){var e;if(o.Browser.pointer?(_.push(t.pointerId),e=_.length):e=t.touches.length,!(e>1)){var i=Date.now(),n=i-(r||i);h=t.touches?t.touches[0]:t,l=n>0&&u>=n,r=i}}function a(t){if(o.Browser.pointer){var e=_.indexOf(t.pointerId);if(-1===e)return;_.splice(e,1)}if(l){if(o.Browser.pointer){var n,s={};for(var a in h)n=h[a],s[a]="function"==typeof n?n.bind(h):n;h=s}h.type="dblclick",i(h),r=null}}var r,h,l=!1,u=250,c="_leaflet_",d=this._touchstart,p=this._touchend,_=[];t[c+d+n]=s,t[c+p+n]=a;var m=o.Browser.pointer?e.documentElement:t;return t.addEventListener(d,s,!1),m.addEventListener(p,a,!1),o.Browser.pointer&&m.addEventListener(o.DomEvent.POINTER_CANCEL,a,!1),this},removeDoubleTapListener:function(t,i){var n="_leaflet_";return t.removeEventListener(this._touchstart,t[n+this._touchstart+i],!1),(o.Browser.pointer?e.documentElement:t).removeEventListener(this._touchend,t[n+this._touchend+i],!1),o.Browser.pointer&&e.documentElement.removeEventListener(o.DomEvent.POINTER_CANCEL,t[n+this._touchend+i],!1),this}}),o.extend(o.DomEvent,{POINTER_DOWN:o.Browser.msPointer?"MSPointerDown":"pointerdown",POINTER_MOVE:o.Browser.msPointer?"MSPointerMove":"pointermove",POINTER_UP:o.Browser.msPointer?"MSPointerUp":"pointerup",POINTER_CANCEL:o.Browser.msPointer?"MSPointerCancel":"pointercancel",_pointers:[],_pointerDocumentListener:!1,addPointerListener:function(t,e,i,n){switch(e){case"touchstart":return this.addPointerListenerStart(t,e,i,n);case"touchend":return this.addPointerListenerEnd(t,e,i,n);case"touchmove":return this.addPointerListenerMove(t,e,i,n);default:throw"Unknown touch event type"}},addPointerListenerStart:function(t,i,n,s){var a="_leaflet_",r=this._pointers,h=function(t){o.DomEvent.preventDefault(t);for(var e=!1,i=0;i<r.length;i++)if(r[i].pointerId===t.pointerId){e=!0; | ||
9 | +break}e||r.push(t),t.touches=r.slice(),t.changedTouches=[t],n(t)};if(t[a+"touchstart"+s]=h,t.addEventListener(this.POINTER_DOWN,h,!1),!this._pointerDocumentListener){var l=function(t){for(var e=0;e<r.length;e++)if(r[e].pointerId===t.pointerId){r.splice(e,1);break}};e.documentElement.addEventListener(this.POINTER_UP,l,!1),e.documentElement.addEventListener(this.POINTER_CANCEL,l,!1),this._pointerDocumentListener=!0}return this},addPointerListenerMove:function(t,e,i,n){function o(t){if(t.pointerType!==t.MSPOINTER_TYPE_MOUSE&&"mouse"!==t.pointerType||0!==t.buttons){for(var e=0;e<a.length;e++)if(a[e].pointerId===t.pointerId){a[e]=t;break}t.touches=a.slice(),t.changedTouches=[t],i(t)}}var s="_leaflet_",a=this._pointers;return t[s+"touchmove"+n]=o,t.addEventListener(this.POINTER_MOVE,o,!1),this},addPointerListenerEnd:function(t,e,i,n){var o="_leaflet_",s=this._pointers,a=function(t){for(var e=0;e<s.length;e++)if(s[e].pointerId===t.pointerId){s.splice(e,1);break}t.touches=s.slice(),t.changedTouches=[t],i(t)};return t[o+"touchend"+n]=a,t.addEventListener(this.POINTER_UP,a,!1),t.addEventListener(this.POINTER_CANCEL,a,!1),this},removePointerListener:function(t,e,i){var n="_leaflet_",o=t[n+e+i];switch(e){case"touchstart":t.removeEventListener(this.POINTER_DOWN,o,!1);break;case"touchmove":t.removeEventListener(this.POINTER_MOVE,o,!1);break;case"touchend":t.removeEventListener(this.POINTER_UP,o,!1),t.removeEventListener(this.POINTER_CANCEL,o,!1)}return this}}),o.Map.mergeOptions({touchZoom:o.Browser.touch&&!o.Browser.android23,bounceAtZoomLimits:!0}),o.Map.TouchZoom=o.Handler.extend({addHooks:function(){o.DomEvent.on(this._map._container,"touchstart",this._onTouchStart,this)},removeHooks:function(){o.DomEvent.off(this._map._container,"touchstart",this._onTouchStart,this)},_onTouchStart:function(t){var i=this._map;if(t.touches&&2===t.touches.length&&!i._animatingZoom&&!this._zooming){var n=i.mouseEventToLayerPoint(t.touches[0]),s=i.mouseEventToLayerPoint(t.touches[1]),a=i._getCenterLayerPoint();this._startCenter=n.add(s)._divideBy(2),this._startDist=n.distanceTo(s),this._moved=!1,this._zooming=!0,this._centerOffset=a.subtract(this._startCenter),i._panAnim&&i._panAnim.stop(),o.DomEvent.on(e,"touchmove",this._onTouchMove,this).on(e,"touchend",this._onTouchEnd,this),o.DomEvent.preventDefault(t)}},_onTouchMove:function(t){var e=this._map;if(t.touches&&2===t.touches.length&&this._zooming){var i=e.mouseEventToLayerPoint(t.touches[0]),n=e.mouseEventToLayerPoint(t.touches[1]);this._scale=i.distanceTo(n)/this._startDist,this._delta=i._add(n)._divideBy(2)._subtract(this._startCenter),1!==this._scale&&(e.options.bounceAtZoomLimits||!(e.getZoom()===e.getMinZoom()&&this._scale<1||e.getZoom()===e.getMaxZoom()&&this._scale>1))&&(this._moved||(o.DomUtil.addClass(e._mapPane,"leaflet-touching"),e.fire("movestart").fire("zoomstart"),this._moved=!0),o.Util.cancelAnimFrame(this._animRequest),this._animRequest=o.Util.requestAnimFrame(this._updateOnMove,this,!0,this._map._container),o.DomEvent.preventDefault(t))}},_updateOnMove:function(){var t=this._map,e=this._getScaleOrigin(),i=t.layerPointToLatLng(e),n=t.getScaleZoom(this._scale);t._animateZoom(i,n,this._startCenter,this._scale,this._delta,!1,!0)},_onTouchEnd:function(){if(!this._moved||!this._zooming)return void(this._zooming=!1);var t=this._map;this._zooming=!1,o.DomUtil.removeClass(t._mapPane,"leaflet-touching"),o.Util.cancelAnimFrame(this._animRequest),o.DomEvent.off(e,"touchmove",this._onTouchMove).off(e,"touchend",this._onTouchEnd);var i=this._getScaleOrigin(),n=t.layerPointToLatLng(i),s=t.getZoom(),a=t.getScaleZoom(this._scale)-s,r=a>0?Math.ceil(a):Math.floor(a),h=t._limitZoom(s+r),l=t.getZoomScale(h)/this._scale;t._animateZoom(n,h,i,l)},_getScaleOrigin:function(){var t=this._centerOffset.subtract(this._delta).divideBy(this._scale);return this._startCenter.add(t)}}),o.Map.addInitHook("addHandler","touchZoom",o.Map.TouchZoom),o.Map.mergeOptions({tap:!0,tapTolerance:15}),o.Map.Tap=o.Handler.extend({addHooks:function(){o.DomEvent.on(this._map._container,"touchstart",this._onDown,this)},removeHooks:function(){o.DomEvent.off(this._map._container,"touchstart",this._onDown,this)},_onDown:function(t){if(t.touches){if(o.DomEvent.preventDefault(t),this._fireClick=!0,t.touches.length>1)return this._fireClick=!1,void clearTimeout(this._holdTimeout);var i=t.touches[0],n=i.target;this._startPos=this._newPos=new o.Point(i.clientX,i.clientY),n.tagName&&"a"===n.tagName.toLowerCase()&&o.DomUtil.addClass(n,"leaflet-active"),this._holdTimeout=setTimeout(o.bind(function(){this._isTapValid()&&(this._fireClick=!1,this._onUp(),this._simulateEvent("contextmenu",i))},this),1e3),o.DomEvent.on(e,"touchmove",this._onMove,this).on(e,"touchend",this._onUp,this)}},_onUp:function(t){if(clearTimeout(this._holdTimeout),o.DomEvent.off(e,"touchmove",this._onMove,this).off(e,"touchend",this._onUp,this),this._fireClick&&t&&t.changedTouches){var i=t.changedTouches[0],n=i.target;n&&n.tagName&&"a"===n.tagName.toLowerCase()&&o.DomUtil.removeClass(n,"leaflet-active"),this._isTapValid()&&this._simulateEvent("click",i)}},_isTapValid:function(){return this._newPos.distanceTo(this._startPos)<=this._map.options.tapTolerance},_onMove:function(t){var e=t.touches[0];this._newPos=new o.Point(e.clientX,e.clientY)},_simulateEvent:function(i,n){var o=e.createEvent("MouseEvents");o._simulated=!0,n.target._simulatedClick=!0,o.initMouseEvent(i,!0,!0,t,1,n.screenX,n.screenY,n.clientX,n.clientY,!1,!1,!1,!1,0,null),n.target.dispatchEvent(o)}}),o.Browser.touch&&!o.Browser.pointer&&o.Map.addInitHook("addHandler","tap",o.Map.Tap),o.Map.mergeOptions({boxZoom:!0}),o.Map.BoxZoom=o.Handler.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._moved=!1},addHooks:function(){o.DomEvent.on(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){o.DomEvent.off(this._container,"mousedown",this._onMouseDown),this._moved=!1},moved:function(){return this._moved},_onMouseDown:function(t){return this._moved=!1,!t.shiftKey||1!==t.which&&1!==t.button?!1:(o.DomUtil.disableTextSelection(),o.DomUtil.disableImageDrag(),this._startLayerPoint=this._map.mouseEventToLayerPoint(t),void o.DomEvent.on(e,"mousemove",this._onMouseMove,this).on(e,"mouseup",this._onMouseUp,this).on(e,"keydown",this._onKeyDown,this))},_onMouseMove:function(t){this._moved||(this._box=o.DomUtil.create("div","leaflet-zoom-box",this._pane),o.DomUtil.setPosition(this._box,this._startLayerPoint),this._container.style.cursor="crosshair",this._map.fire("boxzoomstart"));var e=this._startLayerPoint,i=this._box,n=this._map.mouseEventToLayerPoint(t),s=n.subtract(e),a=new o.Point(Math.min(n.x,e.x),Math.min(n.y,e.y));o.DomUtil.setPosition(i,a),this._moved=!0,i.style.width=Math.max(0,Math.abs(s.x)-4)+"px",i.style.height=Math.max(0,Math.abs(s.y)-4)+"px"},_finish:function(){this._moved&&(this._pane.removeChild(this._box),this._container.style.cursor=""),o.DomUtil.enableTextSelection(),o.DomUtil.enableImageDrag(),o.DomEvent.off(e,"mousemove",this._onMouseMove).off(e,"mouseup",this._onMouseUp).off(e,"keydown",this._onKeyDown)},_onMouseUp:function(t){this._finish();var e=this._map,i=e.mouseEventToLayerPoint(t);if(!this._startLayerPoint.equals(i)){var n=new o.LatLngBounds(e.layerPointToLatLng(this._startLayerPoint),e.layerPointToLatLng(i));e.fitBounds(n),e.fire("boxzoomend",{boxZoomBounds:n})}},_onKeyDown:function(t){27===t.keyCode&&this._finish()}}),o.Map.addInitHook("addHandler","boxZoom",o.Map.BoxZoom),o.Map.mergeOptions({keyboard:!0,keyboardPanOffset:80,keyboardZoomOffset:1}),o.Map.Keyboard=o.Handler.extend({keyCodes:{left:[37],right:[39],down:[40],up:[38],zoomIn:[187,107,61,171],zoomOut:[189,109,173]},initialize:function(t){this._map=t,this._setPanOffset(t.options.keyboardPanOffset),this._setZoomOffset(t.options.keyboardZoomOffset)},addHooks:function(){var t=this._map._container;-1===t.tabIndex&&(t.tabIndex="0"),o.DomEvent.on(t,"focus",this._onFocus,this).on(t,"blur",this._onBlur,this).on(t,"mousedown",this._onMouseDown,this),this._map.on("focus",this._addHooks,this).on("blur",this._removeHooks,this)},removeHooks:function(){this._removeHooks();var t=this._map._container;o.DomEvent.off(t,"focus",this._onFocus,this).off(t,"blur",this._onBlur,this).off(t,"mousedown",this._onMouseDown,this),this._map.off("focus",this._addHooks,this).off("blur",this._removeHooks,this)},_onMouseDown:function(){if(!this._focused){var i=e.body,n=e.documentElement,o=i.scrollTop||n.scrollTop,s=i.scrollLeft||n.scrollLeft;this._map._container.focus(),t.scrollTo(s,o)}},_onFocus:function(){this._focused=!0,this._map.fire("focus")},_onBlur:function(){this._focused=!1,this._map.fire("blur")},_setPanOffset:function(t){var e,i,n=this._panKeys={},o=this.keyCodes;for(e=0,i=o.left.length;i>e;e++)n[o.left[e]]=[-1*t,0];for(e=0,i=o.right.length;i>e;e++)n[o.right[e]]=[t,0];for(e=0,i=o.down.length;i>e;e++)n[o.down[e]]=[0,t];for(e=0,i=o.up.length;i>e;e++)n[o.up[e]]=[0,-1*t]},_setZoomOffset:function(t){var e,i,n=this._zoomKeys={},o=this.keyCodes;for(e=0,i=o.zoomIn.length;i>e;e++)n[o.zoomIn[e]]=t;for(e=0,i=o.zoomOut.length;i>e;e++)n[o.zoomOut[e]]=-t},_addHooks:function(){o.DomEvent.on(e,"keydown",this._onKeyDown,this)},_removeHooks:function(){o.DomEvent.off(e,"keydown",this._onKeyDown,this)},_onKeyDown:function(t){var e=t.keyCode,i=this._map;if(e in this._panKeys){if(i._panAnim&&i._panAnim._inProgress)return;i.panBy(this._panKeys[e]),i.options.maxBounds&&i.panInsideBounds(i.options.maxBounds)}else{if(!(e in this._zoomKeys))return;i.setZoom(i.getZoom()+this._zoomKeys[e])}o.DomEvent.stop(t)}}),o.Map.addInitHook("addHandler","keyboard",o.Map.Keyboard),o.Handler.MarkerDrag=o.Handler.extend({initialize:function(t){this._marker=t},addHooks:function(){var t=this._marker._icon;this._draggable||(this._draggable=new o.Draggable(t,t)),this._draggable.on("dragstart",this._onDragStart,this).on("drag",this._onDrag,this).on("dragend",this._onDragEnd,this),this._draggable.enable(),o.DomUtil.addClass(this._marker._icon,"leaflet-marker-draggable")},removeHooks:function(){this._draggable.off("dragstart",this._onDragStart,this).off("drag",this._onDrag,this).off("dragend",this._onDragEnd,this),this._draggable.disable(),o.DomUtil.removeClass(this._marker._icon,"leaflet-marker-draggable")},moved:function(){return this._draggable&&this._draggable._moved},_onDragStart:function(){this._marker.closePopup().fire("movestart").fire("dragstart")},_onDrag:function(){var t=this._marker,e=t._shadow,i=o.DomUtil.getPosition(t._icon),n=t._map.layerPointToLatLng(i);e&&o.DomUtil.setPosition(e,i),t._latlng=n,t.fire("move",{latlng:n}).fire("drag")},_onDragEnd:function(t){this._marker.fire("moveend").fire("dragend",t)}}),o.Control=o.Class.extend({options:{position:"topright"},initialize:function(t){o.setOptions(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var e=this._map;return e&&e.removeControl(this),this.options.position=t,e&&e.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this._map=t;var e=this._container=this.onAdd(t),i=this.getPosition(),n=t._controlCorners[i];return o.DomUtil.addClass(e,"leaflet-control"),-1!==i.indexOf("bottom")?n.insertBefore(e,n.firstChild):n.appendChild(e),this},removeFrom:function(t){var e=this.getPosition(),i=t._controlCorners[e];return i.removeChild(this._container),this._map=null,this.onRemove&&this.onRemove(t),this},_refocusOnMap:function(){this._map&&this._map.getContainer().focus()}}),o.control=function(t){return new o.Control(t)},o.Map.include({addControl:function(t){return t.addTo(this),this},removeControl:function(t){return t.removeFrom(this),this},_initControlPos:function(){function t(t,s){var a=i+t+" "+i+s;e[t+s]=o.DomUtil.create("div",a,n)}var e=this._controlCorners={},i="leaflet-",n=this._controlContainer=o.DomUtil.create("div",i+"control-container",this._container);t("top","left"),t("top","right"),t("bottom","left"),t("bottom","right")},_clearControlPos:function(){this._container.removeChild(this._controlContainer)}}),o.Control.Zoom=o.Control.extend({options:{position:"topleft",zoomInText:"+",zoomInTitle:"Zoom in",zoomOutText:"-",zoomOutTitle:"Zoom out"},onAdd:function(t){var e="leaflet-control-zoom",i=o.DomUtil.create("div",e+" leaflet-bar");return this._map=t,this._zoomInButton=this._createButton(this.options.zoomInText,this.options.zoomInTitle,e+"-in",i,this._zoomIn,this),this._zoomOutButton=this._createButton(this.options.zoomOutText,this.options.zoomOutTitle,e+"-out",i,this._zoomOut,this),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),i},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},_zoomIn:function(t){this._map.zoomIn(t.shiftKey?3:1)},_zoomOut:function(t){this._map.zoomOut(t.shiftKey?3:1)},_createButton:function(t,e,i,n,s,a){var r=o.DomUtil.create("a",i,n);r.innerHTML=t,r.href="#",r.title=e;var h=o.DomEvent.stopPropagation;return o.DomEvent.on(r,"click",h).on(r,"mousedown",h).on(r,"dblclick",h).on(r,"click",o.DomEvent.preventDefault).on(r,"click",s,a).on(r,"click",this._refocusOnMap,a),r},_updateDisabled:function(){var t=this._map,e="leaflet-disabled";o.DomUtil.removeClass(this._zoomInButton,e),o.DomUtil.removeClass(this._zoomOutButton,e),t._zoom===t.getMinZoom()&&o.DomUtil.addClass(this._zoomOutButton,e),t._zoom===t.getMaxZoom()&&o.DomUtil.addClass(this._zoomInButton,e)}}),o.Map.mergeOptions({zoomControl:!0}),o.Map.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new o.Control.Zoom,this.addControl(this.zoomControl))}),o.control.zoom=function(t){return new o.Control.Zoom(t)},o.Control.Attribution=o.Control.extend({options:{position:"bottomright",prefix:'<a href="http://leafletjs.com" title="A JS library for interactive maps">Leaflet</a>'},initialize:function(t){o.setOptions(this,t),this._attributions={}},onAdd:function(t){this._container=o.DomUtil.create("div","leaflet-control-attribution"),o.DomEvent.disableClickPropagation(this._container);for(var e in t._layers)t._layers[e].getAttribution&&this.addAttribution(t._layers[e].getAttribution());return t.on("layeradd",this._onLayerAdd,this).on("layerremove",this._onLayerRemove,this),this._update(),this._container},onRemove:function(t){t.off("layeradd",this._onLayerAdd).off("layerremove",this._onLayerRemove)},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t?(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update(),this):void 0},removeAttribution:function(t){return t?(this._attributions[t]&&(this._attributions[t]--,this._update()),this):void 0},_update:function(){if(this._map){var t=[];for(var e in this._attributions)this._attributions[e]&&t.push(e);var i=[];this.options.prefix&&i.push(this.options.prefix),t.length&&i.push(t.join(", ")),this._container.innerHTML=i.join(" | ")}},_onLayerAdd:function(t){t.layer.getAttribution&&this.addAttribution(t.layer.getAttribution())},_onLayerRemove:function(t){t.layer.getAttribution&&this.removeAttribution(t.layer.getAttribution())}}),o.Map.mergeOptions({attributionControl:!0}),o.Map.addInitHook(function(){this.options.attributionControl&&(this.attributionControl=(new o.Control.Attribution).addTo(this))}),o.control.attribution=function(t){return new o.Control.Attribution(t)},o.Control.Scale=o.Control.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0,updateWhenIdle:!1},onAdd:function(t){this._map=t;var e="leaflet-control-scale",i=o.DomUtil.create("div",e),n=this.options;return this._addScales(n,e,i),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),i},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,e,i){t.metric&&(this._mScale=o.DomUtil.create("div",e+"-line",i)),t.imperial&&(this._iScale=o.DomUtil.create("div",e+"-line",i))},_update:function(){var t=this._map.getBounds(),e=t.getCenter().lat,i=6378137*Math.PI*Math.cos(e*Math.PI/180),n=i*(t.getNorthEast().lng-t.getSouthWest().lng)/180,o=this._map.getSize(),s=this.options,a=0;o.x>0&&(a=n*(s.maxWidth/o.x)),this._updateScales(s,a)},_updateScales:function(t,e){t.metric&&e&&this._updateMetric(e),t.imperial&&e&&this._updateImperial(e)},_updateMetric:function(t){var e=this._getRoundNum(t);this._mScale.style.width=this._getScaleWidth(e/t)+"px",this._mScale.innerHTML=1e3>e?e+" m":e/1e3+" km"},_updateImperial:function(t){var e,i,n,o=3.2808399*t,s=this._iScale;o>5280?(e=o/5280,i=this._getRoundNum(e),s.style.width=this._getScaleWidth(i/e)+"px",s.innerHTML=i+" mi"):(n=this._getRoundNum(o),s.style.width=this._getScaleWidth(n/o)+"px",s.innerHTML=n+" ft")},_getScaleWidth:function(t){return Math.round(this.options.maxWidth*t)-10},_getRoundNum:function(t){var e=Math.pow(10,(Math.floor(t)+"").length-1),i=t/e;return i=i>=10?10:i>=5?5:i>=3?3:i>=2?2:1,e*i}}),o.control.scale=function(t){return new o.Control.Scale(t)},o.Control.Layers=o.Control.extend({options:{collapsed:!0,position:"topright",autoZIndex:!0},initialize:function(t,e,i){o.setOptions(this,i),this._layers={},this._lastZIndex=0,this._handlingClick=!1;for(var n in t)this._addLayer(t[n],n);for(n in e)this._addLayer(e[n],n,!0)},onAdd:function(t){return this._initLayout(),this._update(),t.on("layeradd",this._onLayerChange,this).on("layerremove",this._onLayerChange,this),this._container},onRemove:function(t){t.off("layeradd",this._onLayerChange,this).off("layerremove",this._onLayerChange,this)},addBaseLayer:function(t,e){return this._addLayer(t,e),this._update(),this},addOverlay:function(t,e){return this._addLayer(t,e,!0),this._update(),this},removeLayer:function(t){var e=o.stamp(t);return delete this._layers[e],this._update(),this},_initLayout:function(){var t="leaflet-control-layers",e=this._container=o.DomUtil.create("div",t);e.setAttribute("aria-haspopup",!0),o.Browser.touch?o.DomEvent.on(e,"click",o.DomEvent.stopPropagation):o.DomEvent.disableClickPropagation(e).disableScrollPropagation(e);var i=this._form=o.DomUtil.create("form",t+"-list");if(this.options.collapsed){o.Browser.android||o.DomEvent.on(e,"mouseover",this._expand,this).on(e,"mouseout",this._collapse,this);var n=this._layersLink=o.DomUtil.create("a",t+"-toggle",e);n.href="#",n.title="Layers",o.Browser.touch?o.DomEvent.on(n,"click",o.DomEvent.stop).on(n,"click",this._expand,this):o.DomEvent.on(n,"focus",this._expand,this),o.DomEvent.on(i,"click",function(){setTimeout(o.bind(this._onInputClick,this),0)},this),this._map.on("click",this._collapse,this)}else this._expand();this._baseLayersList=o.DomUtil.create("div",t+"-base",i),this._separator=o.DomUtil.create("div",t+"-separator",i),this._overlaysList=o.DomUtil.create("div",t+"-overlays",i),e.appendChild(i)},_addLayer:function(t,e,i){var n=o.stamp(t);this._layers[n]={layer:t,name:e,overlay:i},this.options.autoZIndex&&t.setZIndex&&(this._lastZIndex++,t.setZIndex(this._lastZIndex))},_update:function(){if(this._container){this._baseLayersList.innerHTML="",this._overlaysList.innerHTML="";var t,e,i=!1,n=!1;for(t in this._layers)e=this._layers[t],this._addItem(e),n=n||e.overlay,i=i||!e.overlay;this._separator.style.display=n&&i?"":"none"}},_onLayerChange:function(t){var e=this._layers[o.stamp(t.layer)];if(e){this._handlingClick||this._update();var i=e.overlay?"layeradd"===t.type?"overlayadd":"overlayremove":"layeradd"===t.type?"baselayerchange":null;i&&this._map.fire(i,e)}},_createRadioElement:function(t,i){var n='<input type="radio" class="leaflet-control-layers-selector" name="'+t+'"';i&&(n+=' checked="checked"'),n+="/>";var o=e.createElement("div");return o.innerHTML=n,o.firstChild},_addItem:function(t){var i,n=e.createElement("label"),s=this._map.hasLayer(t.layer);t.overlay?(i=e.createElement("input"),i.type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=s):i=this._createRadioElement("leaflet-base-layers",s),i.layerId=o.stamp(t.layer),o.DomEvent.on(i,"click",this._onInputClick,this);var a=e.createElement("span");a.innerHTML=" "+t.name,n.appendChild(i),n.appendChild(a);var r=t.overlay?this._overlaysList:this._baseLayersList;return r.appendChild(n),n},_onInputClick:function(){var t,e,i,n=this._form.getElementsByTagName("input"),o=n.length;for(this._handlingClick=!0,t=0;o>t;t++)e=n[t],i=this._layers[e.layerId],e.checked&&!this._map.hasLayer(i.layer)?this._map.addLayer(i.layer):!e.checked&&this._map.hasLayer(i.layer)&&this._map.removeLayer(i.layer);this._handlingClick=!1,this._refocusOnMap()},_expand:function(){o.DomUtil.addClass(this._container,"leaflet-control-layers-expanded")},_collapse:function(){this._container.className=this._container.className.replace(" leaflet-control-layers-expanded","")}}),o.control.layers=function(t,e,i){return new o.Control.Layers(t,e,i)},o.PosAnimation=o.Class.extend({includes:o.Mixin.Events,run:function(t,e,i,n){this.stop(),this._el=t,this._inProgress=!0,this._newPos=e,this.fire("start"),t.style[o.DomUtil.TRANSITION]="all "+(i||.25)+"s cubic-bezier(0,0,"+(n||.5)+",1)",o.DomEvent.on(t,o.DomUtil.TRANSITION_END,this._onTransitionEnd,this),o.DomUtil.setPosition(t,e),o.Util.falseFn(t.offsetWidth),this._stepTimer=setInterval(o.bind(this._onStep,this),50)},stop:function(){this._inProgress&&(o.DomUtil.setPosition(this._el,this._getPos()),this._onTransitionEnd(),o.Util.falseFn(this._el.offsetWidth))},_onStep:function(){var t=this._getPos();return t?(this._el._leaflet_pos=t,void this.fire("step")):void this._onTransitionEnd()},_transformRe:/([-+]?(?:\d*\.)?\d+)\D*, ([-+]?(?:\d*\.)?\d+)\D*\)/,_getPos:function(){var e,i,n,s=this._el,a=t.getComputedStyle(s);if(o.Browser.any3d){if(n=a[o.DomUtil.TRANSFORM].match(this._transformRe),!n)return;e=parseFloat(n[1]),i=parseFloat(n[2])}else e=parseFloat(a.left),i=parseFloat(a.top);return new o.Point(e,i,!0)},_onTransitionEnd:function(){o.DomEvent.off(this._el,o.DomUtil.TRANSITION_END,this._onTransitionEnd,this),this._inProgress&&(this._inProgress=!1,this._el.style[o.DomUtil.TRANSITION]="",this._el._leaflet_pos=this._newPos,clearInterval(this._stepTimer),this.fire("step").fire("end"))}}),o.Map.include({setView:function(t,e,n){if(e=e===i?this._zoom:this._limitZoom(e),t=this._limitCenter(o.latLng(t),e,this.options.maxBounds),n=n||{},this._panAnim&&this._panAnim.stop(),this._loaded&&!n.reset&&n!==!0){n.animate!==i&&(n.zoom=o.extend({animate:n.animate},n.zoom),n.pan=o.extend({animate:n.animate},n.pan));var s=this._zoom!==e?this._tryAnimatedZoom&&this._tryAnimatedZoom(t,e,n.zoom):this._tryAnimatedPan(t,n.pan);if(s)return clearTimeout(this._sizeTimer),this}return this._resetView(t,e),this},panBy:function(t,e){if(t=o.point(t).round(),e=e||{},!t.x&&!t.y)return this;if(this._panAnim||(this._panAnim=new o.PosAnimation,this._panAnim.on({step:this._onPanTransitionStep,end:this._onPanTransitionEnd},this)),e.noMoveStart||this.fire("movestart"),e.animate!==!1){o.DomUtil.addClass(this._mapPane,"leaflet-pan-anim");var i=this._getMapPanePos().subtract(t);this._panAnim.run(this._mapPane,i,e.duration||.25,e.easeLinearity)}else this._rawPanBy(t),this.fire("move").fire("moveend");return this},_onPanTransitionStep:function(){this.fire("move")},_onPanTransitionEnd:function(){o.DomUtil.removeClass(this._mapPane,"leaflet-pan-anim"),this.fire("moveend")},_tryAnimatedPan:function(t,e){var i=this._getCenterOffset(t)._floor();return(e&&e.animate)===!0||this.getSize().contains(i)?(this.panBy(i,e),!0):!1}}),o.PosAnimation=o.DomUtil.TRANSITION?o.PosAnimation:o.PosAnimation.extend({run:function(t,e,i,n){this.stop(),this._el=t,this._inProgress=!0,this._duration=i||.25,this._easeOutPower=1/Math.max(n||.5,.2),this._startPos=o.DomUtil.getPosition(t),this._offset=e.subtract(this._startPos),this._startTime=+new Date,this.fire("start"),this._animate()},stop:function(){this._inProgress&&(this._step(),this._complete())},_animate:function(){this._animId=o.Util.requestAnimFrame(this._animate,this),this._step()},_step:function(){var t=+new Date-this._startTime,e=1e3*this._duration;e>t?this._runFrame(this._easeOut(t/e)):(this._runFrame(1),this._complete())},_runFrame:function(t){var e=this._startPos.add(this._offset.multiplyBy(t));o.DomUtil.setPosition(this._el,e),this.fire("step")},_complete:function(){o.Util.cancelAnimFrame(this._animId),this._inProgress=!1,this.fire("end")},_easeOut:function(t){return 1-Math.pow(1-t,this._easeOutPower)}}),o.Map.mergeOptions({zoomAnimation:!0,zoomAnimationThreshold:4}),o.DomUtil.TRANSITION&&o.Map.addInitHook(function(){this._zoomAnimated=this.options.zoomAnimation&&o.DomUtil.TRANSITION&&o.Browser.any3d&&!o.Browser.android23&&!o.Browser.mobileOpera,this._zoomAnimated&&o.DomEvent.on(this._mapPane,o.DomUtil.TRANSITION_END,this._catchTransitionEnd,this)}),o.Map.include(o.DomUtil.TRANSITION?{_catchTransitionEnd:function(t){this._animatingZoom&&t.propertyName.indexOf("transform")>=0&&this._onZoomTransitionEnd()},_nothingToAnimate:function(){return!this._container.getElementsByClassName("leaflet-zoom-animated").length},_tryAnimatedZoom:function(t,e,i){if(this._animatingZoom)return!0;if(i=i||{},!this._zoomAnimated||i.animate===!1||this._nothingToAnimate()||Math.abs(e-this._zoom)>this.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(e),o=this._getCenterOffset(t)._divideBy(1-1/n),s=this._getCenterLayerPoint()._add(o);return i.animate===!0||this.getSize().contains(o)?(this.fire("movestart").fire("zoomstart"),this._animateZoom(t,e,s,n,null,!0),!0):!1},_animateZoom:function(t,e,i,n,s,a,r){r||(this._animatingZoom=!0),o.DomUtil.addClass(this._mapPane,"leaflet-zoom-anim"),this._animateToCenter=t,this._animateToZoom=e,o.Draggable&&(o.Draggable._disabled=!0),o.Util.requestAnimFrame(function(){this.fire("zoomanim",{center:t,zoom:e,origin:i,scale:n,delta:s,backwards:a})},this)},_onZoomTransitionEnd:function(){this._animatingZoom=!1,o.DomUtil.removeClass(this._mapPane,"leaflet-zoom-anim"),this._resetView(this._animateToCenter,this._animateToZoom,!0,!0),o.Draggable&&(o.Draggable._disabled=!1)}}:{}),o.TileLayer.include({_animateZoom:function(t){this._animating||(this._animating=!0,this._prepareBgBuffer());var e=this._bgBuffer,i=o.DomUtil.TRANSFORM,n=t.delta?o.DomUtil.getTranslateString(t.delta):e.style[i],s=o.DomUtil.getScaleString(t.scale,t.origin);e.style[i]=t.backwards?s+" "+n:n+" "+s},_endZoomAnim:function(){var t=this._tileContainer,e=this._bgBuffer;t.style.visibility="",t.parentNode.appendChild(t),o.Util.falseFn(e.offsetWidth),this._animating=!1},_clearBgBuffer:function(){var t=this._map;!t||t._animatingZoom||t.touchZoom._zooming||(this._bgBuffer.innerHTML="",this._bgBuffer.style[o.DomUtil.TRANSFORM]="")},_prepareBgBuffer:function(){var t=this._tileContainer,e=this._bgBuffer,i=this._getLoadedTilesPercentage(e),n=this._getLoadedTilesPercentage(t);return e&&i>.5&&.5>n?(t.style.visibility="hidden",void this._stopLoadingImages(t)):(e.style.visibility="hidden",e.style[o.DomUtil.TRANSFORM]="",this._tileContainer=e,e=this._bgBuffer=t,this._stopLoadingImages(e),void clearTimeout(this._clearBgBufferTimer))},_getLoadedTilesPercentage:function(t){var e,i,n=t.getElementsByTagName("img"),o=0;for(e=0,i=n.length;i>e;e++)n[e].complete&&o++;return o/i},_stopLoadingImages:function(t){var e,i,n,s=Array.prototype.slice.call(t.getElementsByTagName("img"));for(e=0,i=s.length;i>e;e++)n=s[e],n.complete||(n.onload=o.Util.falseFn,n.onerror=o.Util.falseFn,n.src=o.Util.emptyImageUrl,n.parentNode.removeChild(n))}}),o.Map.include({_defaultLocateOptions:{watch:!1,setView:!1,maxZoom:1/0,timeout:1e4,maximumAge:0,enableHighAccuracy:!1},locate:function(t){if(t=this._locateOptions=o.extend(this._defaultLocateOptions,t),!navigator.geolocation)return this._handleGeolocationError({code:0,message:"Geolocation not supported."}),this;var e=o.bind(this._handleGeolocationResponse,this),i=o.bind(this._handleGeolocationError,this);return t.watch?this._locationWatchId=navigator.geolocation.watchPosition(e,i,t):navigator.geolocation.getCurrentPosition(e,i,t),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var e=t.code,i=t.message||(1===e?"permission denied":2===e?"position unavailable":"timeout");this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire("locationerror",{code:e,message:"Geolocation error: "+i+"."})},_handleGeolocationResponse:function(t){var e=t.coords.latitude,i=t.coords.longitude,n=new o.LatLng(e,i),s=180*t.coords.accuracy/40075017,a=s/Math.cos(o.LatLng.DEG_TO_RAD*e),r=o.latLngBounds([e-s,i-a],[e+s,i+a]),h=this._locateOptions;if(h.setView){var l=Math.min(this.getBoundsZoom(r),h.maxZoom);this.setView(n,l)}var u={latlng:n,bounds:r,timestamp:t.timestamp};for(var c in t.coords)"number"==typeof t.coords[c]&&(u[c]=t.coords[c]);this.fire("locationfound",u)}})}(window,document); | ||
0 | \ No newline at end of file | 10 | \ No newline at end of file |
locales/controllet_ln.js
@@ -77,6 +77,7 @@ ln["scatterchart_en"] = "Scatter"; | @@ -77,6 +77,7 @@ ln["scatterchart_en"] = "Scatter"; | ||
77 | ln["bubblechart_en"] = "Bubble"; | 77 | ln["bubblechart_en"] = "Bubble"; |
78 | ln["treemap_en"] = "Tree Map"; | 78 | ln["treemap_en"] = "Tree Map"; |
79 | ln["leafletjs_en"] = "Map"; | 79 | ln["leafletjs_en"] = "Map"; |
80 | +ln["leafletjs-geojson_en"] = "Map Geojson"; | ||
80 | 81 | ||
81 | //inputs | 82 | //inputs |
82 | ln["expertGroupBy_en"] = "EXPERT : GROUP BY"; | 83 | ln["expertGroupBy_en"] = "EXPERT : GROUP BY"; |
@@ -107,6 +108,7 @@ ln["SliceSizes_en"] = "SIZE [num]"; | @@ -107,6 +108,7 @@ ln["SliceSizes_en"] = "SIZE [num]"; | ||
107 | ln["Latitude_en"] = "LATITUDE"; | 108 | ln["Latitude_en"] = "LATITUDE"; |
108 | ln["Longitude_en"] = "LONGITUDE"; | 109 | ln["Longitude_en"] = "LONGITUDE"; |
109 | ln["BalloonContent_en"] = "BALLOON CONTENT";// [opt] | 110 | ln["BalloonContent_en"] = "BALLOON CONTENT";// [opt] |
111 | +ln["GEOJSON_en"] = "GEOJSON"; | ||
110 | ln["BubbleContent_en"] = "BUBBLE CONTENT"; | 112 | ln["BubbleContent_en"] = "BUBBLE CONTENT"; |
111 | ln["BubbleSize_en"] = "BUBBLE SIZE [num]"; | 113 | ln["BubbleSize_en"] = "BUBBLE SIZE [num]"; |
112 | ln["Categories_en"] = "CATEGORY [opt]"; | 114 | ln["Categories_en"] = "CATEGORY [opt]"; |
@@ -201,6 +203,7 @@ ln["scatterchart_it"] = "Grafico a dispersione"; | @@ -201,6 +203,7 @@ ln["scatterchart_it"] = "Grafico a dispersione"; | ||
201 | ln["bubblechart_it"] = "Grafico a bolle"; | 203 | ln["bubblechart_it"] = "Grafico a bolle"; |
202 | ln["treemap_it"] = "Grafico ad albero"; | 204 | ln["treemap_it"] = "Grafico ad albero"; |
203 | ln["leafletjs_it"] = "Mappa"; | 205 | ln["leafletjs_it"] = "Mappa"; |
206 | +ln["leafletjs-geojson_it"] = "Mappa geojson"; | ||
204 | 207 | ||
205 | //inputs | 208 | //inputs |
206 | ln["expertGroupBy_it"] = "ESPERTO : RAGGRUPPA"; | 209 | ln["expertGroupBy_it"] = "ESPERTO : RAGGRUPPA"; |
@@ -231,6 +234,7 @@ ln["SliceSizes_it"] = "DIMENSIONE [num]"; | @@ -231,6 +234,7 @@ ln["SliceSizes_it"] = "DIMENSIONE [num]"; | ||
231 | ln["Latitude_it"] = "LATITUDINE"; | 234 | ln["Latitude_it"] = "LATITUDINE"; |
232 | ln["Longitude_it"] = "LONGITUDINE"; | 235 | ln["Longitude_it"] = "LONGITUDINE"; |
233 | ln["BalloonContent_it"] = "CONTENUTO"; | 236 | ln["BalloonContent_it"] = "CONTENUTO"; |
237 | +ln["GEOJSON_it"] = "GEOJSON"; | ||
234 | ln["BubbleContent_it"] = "CONTENUTO BOLLA"; | 238 | ln["BubbleContent_it"] = "CONTENUTO BOLLA"; |
235 | ln["BubbleSize_it"] = "DIMENSIONE BOLLA [num]"; | 239 | ln["BubbleSize_it"] = "DIMENSIONE BOLLA [num]"; |
236 | ln["Categories_it"] = "CATEGORIA [opt]"; | 240 | ln["Categories_it"] = "CATEGORIA [opt]"; |
@@ -325,6 +329,7 @@ ln["scatterchart_fr"] = "Scatter"; | @@ -325,6 +329,7 @@ ln["scatterchart_fr"] = "Scatter"; | ||
325 | ln["bubblechart_fr"] = "Bubble"; | 329 | ln["bubblechart_fr"] = "Bubble"; |
326 | ln["treemap_fr"] = "Tree Map"; | 330 | ln["treemap_fr"] = "Tree Map"; |
327 | ln["leafletjs_fr"] = "Map"; | 331 | ln["leafletjs_fr"] = "Map"; |
332 | +ln["leafletjs-geojson_fr"] = "Map Geojson"; | ||
328 | 333 | ||
329 | //inputs | 334 | //inputs |
330 | ln["expertGroupBy_fr"] = "EXPERT : GROUP BY"; | 335 | ln["expertGroupBy_fr"] = "EXPERT : GROUP BY"; |
@@ -355,6 +360,7 @@ ln["SliceSizes_fr"] = "SIZE [num]"; | @@ -355,6 +360,7 @@ ln["SliceSizes_fr"] = "SIZE [num]"; | ||
355 | ln["Latitude_fr"] = "LATITUDE"; | 360 | ln["Latitude_fr"] = "LATITUDE"; |
356 | ln["Longitude_fr"] = "LONGITUDE"; | 361 | ln["Longitude_fr"] = "LONGITUDE"; |
357 | ln["BalloonContent_fr"] = "BALLOON CONTENT";// [opt] | 362 | ln["BalloonContent_fr"] = "BALLOON CONTENT";// [opt] |
363 | +ln["GEOJSON_fr"] = "GEOJSON"; | ||
358 | ln["BubbleContent_fr"] = "BUBBLE CONTENT"; | 364 | ln["BubbleContent_fr"] = "BUBBLE CONTENT"; |
359 | ln["BubbleSize_fr"] = "BUBBLE SIZE [num]"; | 365 | ln["BubbleSize_fr"] = "BUBBLE SIZE [num]"; |
360 | ln["Categories_fr"] = "CATEGORY [opt]"; | 366 | ln["Categories_fr"] = "CATEGORY [opt]"; |
@@ -449,6 +455,7 @@ ln["scatterchart_nl"] = "Scatter"; | @@ -449,6 +455,7 @@ ln["scatterchart_nl"] = "Scatter"; | ||
449 | ln["bubblechart_nl"] = "Bubble"; | 455 | ln["bubblechart_nl"] = "Bubble"; |
450 | ln["treemap_nl"] = "Tree Map"; | 456 | ln["treemap_nl"] = "Tree Map"; |
451 | ln["leafletjs_nl"] = "Map"; | 457 | ln["leafletjs_nl"] = "Map"; |
458 | +ln["leafletjs-geojson_nl"] = "Map Geojson"; | ||
452 | 459 | ||
453 | //inputs | 460 | //inputs |
454 | ln["expertGroupBy_nl"] = "EXPERT : GROUP BY"; | 461 | ln["expertGroupBy_nl"] = "EXPERT : GROUP BY"; |
@@ -479,6 +486,7 @@ ln["SliceSizes_nl"] = "SIZE [num]"; | @@ -479,6 +486,7 @@ ln["SliceSizes_nl"] = "SIZE [num]"; | ||
479 | ln["Latitude_nl"] = "LATITUDE"; | 486 | ln["Latitude_nl"] = "LATITUDE"; |
480 | ln["Longitude_nl"] = "LONGITUDE"; | 487 | ln["Longitude_nl"] = "LONGITUDE"; |
481 | ln["BalloonContent_nl"] = "BALLOON CONTENT";// [opt] | 488 | ln["BalloonContent_nl"] = "BALLOON CONTENT";// [opt] |
489 | +ln["GEOJSON_nl"] = "GEOJSON"; | ||
482 | ln["BubbleContent_nl"] = "BUBBLE CONTENT"; | 490 | ln["BubbleContent_nl"] = "BUBBLE CONTENT"; |
483 | ln["BubbleSize_nl"] = "BUBBLE SIZE [num]"; | 491 | ln["BubbleSize_nl"] = "BUBBLE SIZE [num]"; |
484 | ln["Categories_nl"] = "CATEGORY [opt]"; | 492 | ln["Categories_nl"] = "CATEGORY [opt]"; |