Commit 899e9758d62c235671549131f0e803e5385ccc07

Authored by Renato De Donato
1 parent fa7d515e

geojson <3

controllets/data-table-controllet/data-table-controllet.html
... ... @@ -335,13 +335,14 @@
335 335  
336 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 343 reset : function(){
342 344 this.setData([]);
343 345 $(this.$.tbody).animate({ scrollTop: 0}, 0);
344   -// this.filter = "";
345 346 },
346 347  
347 348 _onPrevClick : function(){
... ... @@ -478,7 +479,7 @@
478 479 var w = $(this.$.data_table_container).width();
479 480 $(this.$.tbody).width(w).height(h);
480 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 276  
277 277 setInputs : function(inputs) {
278 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 284 var name = inputs.name;
281 285 var description = inputs.description;
282 286 var selection = inputs.selection;
... ...
datalets/base-ajax-json-alasql-datalet/base-ajax-json-alasql-datalet.html
... ... @@ -34,7 +34,7 @@
34 34 <script type="text/javascript" src="../../alasql-utility/alasql.min.js"></script>
35 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 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&amp;limit=10000"
  17 + fields='["result,records,Lat","result,records,Lng", "result,records,Link"]'></leafletjs-datalet>
  18 +
  19 +
  20 +</body>
  21 +</html>
0 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 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
Changes suppressed. Click to show
  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 = '&#215;';
  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 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 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="&#215;",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 10 \ No newline at end of file
... ...
locales/controllet_ln.js
... ... @@ -77,6 +77,7 @@ ln[&quot;scatterchart_en&quot;] = &quot;Scatter&quot;;
77 77 ln["bubblechart_en"] = "Bubble";
78 78 ln["treemap_en"] = "Tree Map";
79 79 ln["leafletjs_en"] = "Map";
  80 +ln["leafletjs-geojson_en"] = "Map Geojson";
80 81  
81 82 //inputs
82 83 ln["expertGroupBy_en"] = "EXPERT : GROUP BY";
... ... @@ -107,6 +108,7 @@ ln[&quot;SliceSizes_en&quot;] = &quot;SIZE [num]&quot;;
107 108 ln["Latitude_en"] = "LATITUDE";
108 109 ln["Longitude_en"] = "LONGITUDE";
109 110 ln["BalloonContent_en"] = "BALLOON CONTENT";// [opt]
  111 +ln["GEOJSON_en"] = "GEOJSON";
110 112 ln["BubbleContent_en"] = "BUBBLE CONTENT";
111 113 ln["BubbleSize_en"] = "BUBBLE SIZE [num]";
112 114 ln["Categories_en"] = "CATEGORY [opt]";
... ... @@ -201,6 +203,7 @@ ln[&quot;scatterchart_it&quot;] = &quot;Grafico a dispersione&quot;;
201 203 ln["bubblechart_it"] = "Grafico a bolle";
202 204 ln["treemap_it"] = "Grafico ad albero";
203 205 ln["leafletjs_it"] = "Mappa";
  206 +ln["leafletjs-geojson_it"] = "Mappa geojson";
204 207  
205 208 //inputs
206 209 ln["expertGroupBy_it"] = "ESPERTO : RAGGRUPPA";
... ... @@ -231,6 +234,7 @@ ln[&quot;SliceSizes_it&quot;] = &quot;DIMENSIONE [num]&quot;;
231 234 ln["Latitude_it"] = "LATITUDINE";
232 235 ln["Longitude_it"] = "LONGITUDINE";
233 236 ln["BalloonContent_it"] = "CONTENUTO";
  237 +ln["GEOJSON_it"] = "GEOJSON";
234 238 ln["BubbleContent_it"] = "CONTENUTO BOLLA";
235 239 ln["BubbleSize_it"] = "DIMENSIONE BOLLA [num]";
236 240 ln["Categories_it"] = "CATEGORIA [opt]";
... ... @@ -325,6 +329,7 @@ ln[&quot;scatterchart_fr&quot;] = &quot;Scatter&quot;;
325 329 ln["bubblechart_fr"] = "Bubble";
326 330 ln["treemap_fr"] = "Tree Map";
327 331 ln["leafletjs_fr"] = "Map";
  332 +ln["leafletjs-geojson_fr"] = "Map Geojson";
328 333  
329 334 //inputs
330 335 ln["expertGroupBy_fr"] = "EXPERT : GROUP BY";
... ... @@ -355,6 +360,7 @@ ln[&quot;SliceSizes_fr&quot;] = &quot;SIZE [num]&quot;;
355 360 ln["Latitude_fr"] = "LATITUDE";
356 361 ln["Longitude_fr"] = "LONGITUDE";
357 362 ln["BalloonContent_fr"] = "BALLOON CONTENT";// [opt]
  363 +ln["GEOJSON_fr"] = "GEOJSON";
358 364 ln["BubbleContent_fr"] = "BUBBLE CONTENT";
359 365 ln["BubbleSize_fr"] = "BUBBLE SIZE [num]";
360 366 ln["Categories_fr"] = "CATEGORY [opt]";
... ... @@ -449,6 +455,7 @@ ln[&quot;scatterchart_nl&quot;] = &quot;Scatter&quot;;
449 455 ln["bubblechart_nl"] = "Bubble";
450 456 ln["treemap_nl"] = "Tree Map";
451 457 ln["leafletjs_nl"] = "Map";
  458 +ln["leafletjs-geojson_nl"] = "Map Geojson";
452 459  
453 460 //inputs
454 461 ln["expertGroupBy_nl"] = "EXPERT : GROUP BY";
... ... @@ -479,6 +486,7 @@ ln[&quot;SliceSizes_nl&quot;] = &quot;SIZE [num]&quot;;
479 486 ln["Latitude_nl"] = "LATITUDE";
480 487 ln["Longitude_nl"] = "LONGITUDE";
481 488 ln["BalloonContent_nl"] = "BALLOON CONTENT";// [opt]
  489 +ln["GEOJSON_nl"] = "GEOJSON";
482 490 ln["BubbleContent_nl"] = "BUBBLE CONTENT";
483 491 ln["BubbleSize_nl"] = "BUBBLE SIZE [num]";
484 492 ln["Categories_nl"] = "CATEGORY [opt]";
... ...