leaflet-js 0.6.beta4 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. checksums.yaml +6 -14
  2. data/CHANGELOG.rdoc +3 -0
  3. data/leaflet-js.gemspec +2 -2
  4. data/lib/leaflet.draw/CHANGELOG.md +45 -0
  5. data/lib/leaflet.draw/README.md +70 -23
  6. data/lib/leaflet.draw/build/deps.js +1 -0
  7. data/lib/leaflet.draw/dist/images/spritesheet-2x.png +0 -0
  8. data/lib/leaflet.draw/dist/images/spritesheet.png +0 -0
  9. data/lib/leaflet.draw/dist/leaflet.draw-src.js +489 -136
  10. data/lib/leaflet.draw/dist/leaflet.draw.css +34 -2
  11. data/lib/leaflet.draw/dist/leaflet.draw.ie.css +5 -0
  12. data/lib/leaflet.draw/dist/leaflet.draw.js +2 -2
  13. data/lib/leaflet.draw/examples/basic.html +14 -7
  14. data/lib/leaflet.draw/examples/libs/images/layers-2x.png +0 -0
  15. data/lib/leaflet.draw/examples/libs/images/layers.png +0 -0
  16. data/lib/leaflet.draw/examples/libs/images/marker-icon-2x.png +0 -0
  17. data/lib/leaflet.draw/examples/libs/leaflet-src.js +1129 -608
  18. data/lib/leaflet.draw/examples/libs/leaflet.css +85 -66
  19. data/lib/leaflet.draw/package.json +2 -2
  20. data/lib/leaflet.draw/spec/suites/DrawControlSpec.js +1 -1
  21. data/lib/leaflet.draw/spec/suites/GeometryUtilSpec.js +25 -0
  22. data/lib/leaflet.draw/spec/suites/LatLngUtilSpec.js +9 -0
  23. data/lib/leaflet.draw/src/Control.Draw.js +1 -0
  24. data/lib/leaflet.draw/src/Leaflet.draw.js +89 -1
  25. data/lib/leaflet.draw/src/Toolbar.js +2 -6
  26. data/lib/leaflet.draw/src/Tooltip.js +20 -7
  27. data/lib/leaflet.draw/src/draw/DrawToolbar.js +26 -22
  28. data/lib/leaflet.draw/src/draw/handler/Draw.Circle.js +11 -6
  29. data/lib/leaflet.draw/src/draw/handler/Draw.Feature.js +6 -2
  30. data/lib/leaflet.draw/src/draw/handler/Draw.Marker.js +7 -2
  31. data/lib/leaflet.draw/src/draw/handler/Draw.Polygon.js +29 -7
  32. data/lib/leaflet.draw/src/draw/handler/Draw.Polyline.js +44 -21
  33. data/lib/leaflet.draw/src/draw/handler/Draw.Rectangle.js +3 -3
  34. data/lib/leaflet.draw/src/draw/handler/Draw.SimpleShape.js +14 -1
  35. data/lib/leaflet.draw/src/edit/EditToolbar.js +86 -16
  36. data/lib/leaflet.draw/src/edit/handler/Edit.Poly.js +10 -7
  37. data/lib/leaflet.draw/src/edit/handler/Edit.SimpleShape.js +1 -2
  38. data/lib/leaflet.draw/src/edit/handler/EditToolbar.Delete.js +15 -3
  39. data/lib/leaflet.draw/src/edit/handler/EditToolbar.Edit.js +56 -38
  40. data/lib/leaflet.draw/src/ext/GeometryUtil.js +68 -0
  41. data/lib/leaflet.draw/src/images/spritesheet.svg +41 -0
  42. data/lib/leaflet.label/CHANGELOG.md +32 -0
  43. data/lib/leaflet.label/README.md +21 -4
  44. data/lib/leaflet.label/build/build.js +2 -2
  45. data/lib/leaflet.label/build/deps.js +2 -0
  46. data/lib/leaflet.label/build/hintrc.js +4 -0
  47. data/lib/leaflet.label/dist/leaflet.label-src.js +266 -83
  48. data/lib/leaflet.label/dist/leaflet.label.css +23 -4
  49. data/lib/leaflet.label/dist/leaflet.label.js +1 -1
  50. data/lib/leaflet.label/example/label.html +6 -3
  51. data/lib/leaflet.label/libs/leaflet/images/layers-2x.png +0 -0
  52. data/lib/leaflet.label/libs/leaflet/images/layers.png +0 -0
  53. data/lib/leaflet.label/libs/leaflet/images/marker-icon-2x.png +0 -0
  54. data/lib/leaflet.label/libs/leaflet/leaflet-src.js +1129 -608
  55. data/lib/leaflet.label/libs/leaflet/leaflet.css +85 -66
  56. data/lib/leaflet.label/libs/leaflet/leaflet.js +6 -5
  57. data/lib/leaflet.label/package.json +19 -0
  58. data/lib/leaflet.label/src/BaseMarkerMethods.js +129 -0
  59. data/lib/leaflet.label/src/CircleMarker.Label.js +7 -0
  60. data/lib/leaflet.label/src/Label.js +161 -37
  61. data/lib/leaflet.label/src/Leaflet.label.js +1 -1
  62. data/lib/leaflet.label/src/Map.Label.js +0 -2
  63. data/lib/leaflet.label/src/Marker.Label.js +15 -120
  64. data/lib/leaflet.label/src/Path.Label.js +11 -11
  65. data/lib/leaflet/CHANGELOG.md +299 -31
  66. data/lib/leaflet/CONTRIBUTING.md +3 -3
  67. data/lib/leaflet/FAQ.md +138 -0
  68. data/lib/leaflet/Jakefile.js +24 -4
  69. data/lib/leaflet/PLUGIN-GUIDE.md +127 -0
  70. data/lib/leaflet/README.md +10 -6
  71. data/lib/leaflet/build/build.html +3 -19
  72. data/lib/leaflet/build/build.js +21 -51
  73. data/lib/leaflet/build/deps.js +10 -7
  74. data/lib/leaflet/build/hintrc.js +6 -4
  75. data/lib/leaflet/debug/hacks/jitter.html +0 -1
  76. data/lib/leaflet/debug/map/canvas.html +11 -12
  77. data/lib/leaflet/debug/map/controls.html +3 -4
  78. data/lib/leaflet/debug/map/geolocation.html +0 -1
  79. data/lib/leaflet/debug/map/iframe.html +11 -0
  80. data/lib/leaflet/debug/map/image-overlay.html +0 -1
  81. data/lib/leaflet/debug/map/map-mobile.html +0 -1
  82. data/lib/leaflet/debug/map/map.html +1 -2
  83. data/lib/leaflet/debug/map/max-bounds.html +2 -1
  84. data/lib/leaflet/debug/map/opacity.html +223 -0
  85. data/lib/leaflet/debug/map/scroll.html +6 -1
  86. data/lib/leaflet/debug/map/simple-proj.html +0 -1
  87. data/lib/leaflet/debug/map/wms-marble.html +4 -5
  88. data/lib/leaflet/debug/map/wms.html +0 -1
  89. data/lib/leaflet/debug/map/zoomlevels.html +0 -1
  90. data/lib/leaflet/debug/tests/add_remove_layers.html +5 -6
  91. data/lib/leaflet/debug/tests/bringtoback.html +0 -1
  92. data/lib/leaflet/debug/tests/canvasloop.html +47 -0
  93. data/lib/leaflet/debug/tests/click_on_canvas.html +0 -1
  94. data/lib/leaflet/debug/tests/dragging_and_copyworldjump.html +61 -0
  95. data/lib/leaflet/debug/tests/opacity.html +0 -1
  96. data/lib/leaflet/debug/tests/popupcontextmenuclicks.html +59 -0
  97. data/lib/leaflet/debug/tests/remove_while_dragging.html +4 -5
  98. data/lib/leaflet/debug/tests/removetilewhilepan.html +0 -1
  99. data/lib/leaflet/debug/tests/reuse_popups.html +0 -1
  100. data/lib/leaflet/debug/tests/rtl.html +42 -0
  101. data/lib/leaflet/debug/tests/rtl2.html +27 -0
  102. data/lib/leaflet/debug/tests/set_icon_reuse_dom.html +43 -0
  103. data/lib/leaflet/debug/tests/svg_clicks.html +3 -4
  104. data/lib/leaflet/debug/vector/bounds-extend.html +0 -1
  105. data/lib/leaflet/debug/vector/feature-group-bounds.html +0 -1
  106. data/lib/leaflet/debug/vector/geojson.html +0 -1
  107. data/lib/leaflet/debug/vector/rectangle.html +0 -1
  108. data/lib/leaflet/debug/vector/touchzoomemu.html +2 -3
  109. data/lib/leaflet/debug/vector/vector-bounds.html +0 -1
  110. data/lib/leaflet/debug/vector/vector-canvas.html +0 -1
  111. data/lib/leaflet/debug/vector/vector-mobile.html +0 -1
  112. data/lib/leaflet/debug/vector/vector-simple.html +0 -1
  113. data/lib/leaflet/debug/vector/vector.html +0 -1
  114. data/lib/leaflet/dist/images/layers-2x.png +0 -0
  115. data/lib/leaflet/dist/images/layers.png +0 -0
  116. data/lib/leaflet/dist/leaflet.css +85 -66
  117. data/lib/leaflet/package.json +25 -20
  118. data/lib/leaflet/spec/after.js +1 -1
  119. data/lib/leaflet/spec/index.html +21 -13
  120. data/lib/leaflet/spec/karma.conf.js +51 -50
  121. data/lib/leaflet/spec/spec.hintrc.js +25 -0
  122. data/lib/leaflet/spec/suites/LeafletSpec.js +2 -2
  123. data/lib/leaflet/spec/suites/SpecHelper.js +37 -21
  124. data/lib/leaflet/spec/suites/control/Control.LayersSpec.js +1 -1
  125. data/lib/leaflet/spec/suites/core/ClassSpec.js +12 -12
  126. data/lib/leaflet/spec/suites/core/EventsSpec.js +74 -18
  127. data/lib/leaflet/spec/suites/core/UtilSpec.js +69 -25
  128. data/lib/leaflet/spec/suites/dom/DomEventSpec.js +16 -16
  129. data/lib/leaflet/spec/suites/dom/DomUtilSpec.js +9 -16
  130. data/lib/leaflet/spec/suites/dom/PosAnimationSpec.js +27 -0
  131. data/lib/leaflet/spec/suites/geo/CRSSpec.js +47 -0
  132. data/lib/leaflet/spec/suites/geo/LatLngBoundsSpec.js +22 -14
  133. data/lib/leaflet/spec/suites/geo/LatLngSpec.js +22 -8
  134. data/lib/leaflet/spec/suites/geo/ProjectionSpec.js +21 -20
  135. data/lib/leaflet/spec/suites/geometry/BoundsSpec.js +15 -15
  136. data/lib/leaflet/spec/suites/geometry/PointSpec.js +12 -12
  137. data/lib/leaflet/spec/suites/geometry/TransformationSpec.js +4 -4
  138. data/lib/leaflet/spec/suites/layer/FeatureGroupSpec.js +59 -9
  139. data/lib/leaflet/spec/suites/layer/GeoJSONSpec.js +213 -17
  140. data/lib/leaflet/spec/suites/layer/LayerGroupSpec.js +6 -6
  141. data/lib/leaflet/spec/suites/layer/PopupSpec.js +65 -5
  142. data/lib/leaflet/spec/suites/layer/TileLayerSpec.js +16 -15
  143. data/lib/leaflet/spec/suites/layer/marker/MarkerSpec.js +94 -0
  144. data/lib/leaflet/spec/suites/layer/vector/CircleMarkerSpec.js +7 -7
  145. data/lib/leaflet/spec/suites/layer/vector/PolygonSpec.js +38 -2
  146. data/lib/leaflet/spec/suites/layer/vector/PolylineGeometrySpec.js +4 -4
  147. data/lib/leaflet/spec/suites/layer/vector/PolylineSpec.js +2 -2
  148. data/lib/leaflet/spec/suites/map/MapSpec.js +318 -26
  149. data/lib/leaflet/spec/suites/map/handler/Map.DragSpec.js +38 -0
  150. data/lib/leaflet/src/Leaflet.js +2 -2
  151. data/lib/leaflet/src/control/Control.Attribution.js +6 -0
  152. data/lib/leaflet/src/control/Control.Layers.js +33 -24
  153. data/lib/leaflet/src/control/Control.Zoom.js +12 -4
  154. data/lib/leaflet/src/control/Control.js +10 -0
  155. data/lib/leaflet/src/copyright.js +2 -1
  156. data/lib/leaflet/src/core/Browser.js +11 -10
  157. data/lib/leaflet/src/core/Events.js +15 -11
  158. data/lib/leaflet/src/core/Util.js +19 -14
  159. data/lib/leaflet/src/dom/DomEvent.DoubleTap.js +13 -12
  160. data/lib/leaflet/src/dom/DomEvent.Pointer.js +155 -0
  161. data/lib/leaflet/src/dom/DomEvent.js +57 -19
  162. data/lib/leaflet/src/dom/DomUtil.js +89 -34
  163. data/lib/leaflet/src/dom/Draggable.js +26 -89
  164. data/lib/leaflet/src/dom/PosAnimation.js +13 -2
  165. data/lib/leaflet/src/geo/LatLng.js +16 -5
  166. data/lib/leaflet/src/geo/LatLngBounds.js +5 -2
  167. data/lib/leaflet/src/geo/crs/CRS.EPSG3395.js +2 -2
  168. data/lib/leaflet/src/geo/crs/CRS.js +5 -0
  169. data/lib/leaflet/src/geo/projection/Projection.Mercator.js +3 -3
  170. data/lib/leaflet/src/geometry/LineUtil.js +2 -2
  171. data/lib/leaflet/src/images/layers.svg +8 -0
  172. data/lib/leaflet/src/images/marker.svg +61 -1
  173. data/lib/leaflet/src/layer/FeatureGroup.js +24 -7
  174. data/lib/leaflet/src/layer/GeoJSON.js +97 -56
  175. data/lib/leaflet/src/layer/ImageOverlay.js +9 -0
  176. data/lib/leaflet/src/layer/LayerGroup.js +8 -3
  177. data/lib/leaflet/src/layer/Popup.js +56 -34
  178. data/lib/leaflet/src/layer/marker/DivIcon.js +4 -2
  179. data/lib/leaflet/src/layer/marker/Icon.Default.js +1 -1
  180. data/lib/leaflet/src/layer/marker/Icon.js +15 -18
  181. data/lib/leaflet/src/layer/marker/Marker.Drag.js +7 -5
  182. data/lib/leaflet/src/layer/marker/Marker.Popup.js +22 -5
  183. data/lib/leaflet/src/layer/marker/Marker.js +75 -32
  184. data/lib/leaflet/src/layer/tile/TileLayer.Anim.js +14 -26
  185. data/lib/leaflet/src/layer/tile/TileLayer.Canvas.js +7 -6
  186. data/lib/leaflet/src/layer/tile/TileLayer.WMS.js +14 -10
  187. data/lib/leaflet/src/layer/tile/TileLayer.js +53 -32
  188. data/lib/leaflet/src/layer/vector/CircleMarker.js +11 -0
  189. data/lib/leaflet/src/layer/vector/MultiPoly.js +10 -0
  190. data/lib/leaflet/src/layer/vector/Path.SVG.js +14 -3
  191. data/lib/leaflet/src/layer/vector/Path.VML.js +12 -2
  192. data/lib/leaflet/src/layer/vector/Path.js +7 -3
  193. data/lib/leaflet/src/layer/vector/Polygon.js +14 -3
  194. data/lib/leaflet/src/layer/vector/canvas/CircleMarker.Canvas.js +9 -0
  195. data/lib/leaflet/src/layer/vector/canvas/Path.Canvas.js +1 -0
  196. data/lib/leaflet/src/map/Map.js +192 -125
  197. data/lib/leaflet/src/map/anim/Map.PanAnimation.js +29 -19
  198. data/lib/leaflet/src/map/anim/Map.ZoomAnimation.js +21 -9
  199. data/lib/leaflet/src/map/ext/Map.Geolocation.js +11 -4
  200. data/lib/leaflet/src/map/handler/Map.BoxZoom.js +26 -12
  201. data/lib/leaflet/src/map/handler/Map.DoubleClickZoom.js +10 -3
  202. data/lib/leaflet/src/map/handler/Map.Drag.js +12 -6
  203. data/lib/leaflet/src/map/handler/Map.Keyboard.js +5 -2
  204. data/lib/leaflet/src/map/handler/Map.ScrollWheelZoom.js +7 -1
  205. data/lib/leaflet/src/map/handler/Map.Tap.js +107 -0
  206. data/lib/leaflet/src/map/handler/Map.TouchZoom.js +9 -3
  207. data/vendor/assets/images/layers-2x.png +0 -0
  208. data/vendor/assets/images/layers.png +0 -0
  209. data/vendor/assets/images/spritesheet-2x.png +0 -0
  210. data/vendor/assets/images/spritesheet.png +0 -0
  211. data/vendor/assets/javascripts/leaflet.draw.js +2 -4
  212. data/vendor/assets/javascripts/leaflet.js +3 -1
  213. data/vendor/assets/javascripts/leaflet.label.js +2 -0
  214. data/vendor/assets/stylesheets/leaflet.css.erb +337 -318
  215. data/vendor/assets/stylesheets/leaflet.draw.css.erb +35 -3
  216. data/vendor/assets/stylesheets/leaflet.draw.ie.css +5 -0
  217. data/vendor/assets/stylesheets/leaflet.label.css +23 -4
  218. metadata +40 -14
  219. data/lib/leaflet.draw/examples/libs/leaflet.ie.css +0 -51
  220. data/lib/leaflet.label/libs/leaflet/leaflet.ie.css +0 -51
  221. data/lib/leaflet/dist/leaflet-src.js +0 -8579
  222. data/lib/leaflet/dist/leaflet.ie.css +0 -51
  223. data/lib/leaflet/dist/leaflet.js +0 -8
  224. data/lib/leaflet/spec/happen.js +0 -93
  225. data/lib/leaflet/src/dom/DomEvent.MsTouch.js +0 -146
  226. data/vendor/assets/stylesheets/leaflet.ie.css +0 -51
@@ -27,6 +27,11 @@
27
27
  background-repeat: no-repeat;
28
28
  }
29
29
 
30
+ .leaflet-retina .leaflet-draw-toolbar a {
31
+ background-image: url('images/spritesheet-2x.png');
32
+ background-size: 270px 30px;
33
+ }
34
+
30
35
  .leaflet-draw a {
31
36
  display: block;
32
37
  text-align: center;
@@ -47,8 +52,13 @@
47
52
  top: 0;
48
53
  }
49
54
 
55
+ .leaflet-right .leaflet-draw-actions {
56
+ right:26px;
57
+ left:auto;
58
+ }
59
+
50
60
  .leaflet-draw-actions li {
51
- float: left;
61
+ display: inline-block;
52
62
  }
53
63
 
54
64
  .leaflet-draw-actions li:first-child a {
@@ -60,6 +70,16 @@
60
70
  border-radius: 0 4px 4px 0;
61
71
  }
62
72
 
73
+ .leaflet-right .leaflet-draw-actions li:last-child a {
74
+ -webkit-border-radius: 0;
75
+ border-radius: 0;
76
+ }
77
+
78
+ .leaflet-right .leaflet-draw-actions li:first-child a {
79
+ -webkit-border-radius: 4px 0 0 4px;
80
+ border-radius: 4px 0 0 4px;
81
+ }
82
+
63
83
  .leaflet-draw-actions a {
64
84
  background-color: #919187;
65
85
  border-left: 1px solid #AAA;
@@ -67,16 +87,19 @@
67
87
  font: 11px/19px "Helvetica Neue", Arial, Helvetica, sans-serif;
68
88
  line-height: 28px;
69
89
  text-decoration: none;
70
- width: 50px;
90
+ padding-left: 10px;
91
+ padding-right: 10px;
71
92
  height: 28px;
72
93
  }
73
94
 
74
95
  .leaflet-draw-actions-bottom {
75
96
  margin-top: 0;
97
+ white-space: nowrap;
76
98
  }
77
99
 
78
100
  .leaflet-draw-actions-top {
79
101
  margin-top: 1px;
102
+ white-space: nowrap;
80
103
  }
81
104
 
82
105
  .leaflet-draw-actions-top a,
@@ -130,6 +153,14 @@
130
153
  background-position: -182px -2px;
131
154
  }
132
155
 
156
+ .leaflet-draw-toolbar .leaflet-draw-edit-edit.leaflet-disabled {
157
+ background-position: -212px -2px;
158
+ }
159
+
160
+ .leaflet-draw-toolbar .leaflet-draw-edit-remove.leaflet-disabled {
161
+ background-position: -242px -2px;
162
+ }
163
+
133
164
  /* ================================================================== */
134
165
  /* Drawing styles
135
166
  /* ================================================================== */
@@ -151,6 +182,7 @@
151
182
  margin-top: -21px;
152
183
  padding: 4px 8px;
153
184
  position: absolute;
185
+ visibility: hidden;
154
186
  white-space: nowrap;
155
187
  z-index: 6;
156
188
  }
@@ -17,6 +17,11 @@
17
17
  margin-top: 3px;
18
18
  }
19
19
 
20
+ .leaflet-draw-actions li {
21
+ display: inline;
22
+ zoom: 1;
23
+ }
24
+
20
25
  .leaflet-edit-marker-selected {
21
26
  border: 4px dashed #fe93c2;
22
27
  }
@@ -6,5 +6,5 @@
6
6
  http://leafletjs.com
7
7
  https://github.com/jacobtoye
8
8
  */
9
- (function(t,e){L.drawVersion="0.2.0-dev",L.Draw={},L.Draw.Feature=L.Handler.extend({includes:L.Mixin.Events,initialize:function(t,e){this._map=t,this._container=t._container,this._overlayPane=t._panes.overlayPane,this._popupPane=t._panes.popupPane,e&&e.shapeOptions&&(e.shapeOptions=L.Util.extend({},this.options.shapeOptions,e.shapeOptions)),L.Util.extend(this.options,e)},enable:function(){this._enabled||(L.Handler.prototype.enable.call(this),this.fire("enabled",{handler:this.type}),this._map.fire("draw:drawstart",{layerType:this.type}))},disable:function(){this._enabled&&(L.Handler.prototype.disable.call(this),this.fire("disabled",{handler:this.type}),this._map.fire("draw:drawstop",{layerType:this.type}))},addHooks:function(){this._map&&(L.DomUtil.disableTextSelection(),this._tooltip=new L.Tooltip(this._map),L.DomEvent.addListener(this._container,"keyup",this._cancelDrawing,this))},removeHooks:function(){this._map&&(L.DomUtil.enableTextSelection(),this._tooltip.dispose(),this._tooltip=null,L.DomEvent.removeListener(this._container,"keyup",this._cancelDrawing))},setOptions:function(t){L.setOptions(this,t)},_fireCreatedEvent:function(t){this._map.fire("draw:created",{layer:t,layerType:this.type})},_cancelDrawing:function(t){27===t.keyCode&&this.disable()}}),L.Draw.Polyline=L.Draw.Feature.extend({statics:{TYPE:"polyline"},Poly:L.Polyline,options:{allowIntersection:!0,drawError:{color:"#b00b00",message:"<strong>Error:</strong> shape edges cannot cross!",timeout:2500},icon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon"}),guidelineDistance:20,shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!1,clickable:!0},zIndexOffset:2e3},initialize:function(t,e){e&&e.drawError&&(e.drawError=L.Util.extend({},this.options.drawError,e.drawError)),this.type=L.Draw.Polyline.TYPE,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._markers=[],this._markerGroup=new L.LayerGroup,this._map.addLayer(this._markerGroup),this._poly=new L.Polyline([],this.options.shapeOptions),this._tooltip.updateContent(this._getTooltipText()),this._mouseMarker||(this._mouseMarker=L.marker(this._map.getCenter(),{icon:L.divIcon({className:"leaflet-mouse-marker",iconAnchor:[20,20],iconSize:[40,40]}),opacity:0,zIndexOffset:this.options.zIndexOffset})),this._mouseMarker.on("click",this._onClick,this).addTo(this._map),this._map.on("mousemove",this._onMouseMove,this).on("zoomend",this._onZoomEnd,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._clearHideErrorTimeout(),this._cleanUpShape(),this._map.removeLayer(this._markerGroup),delete this._markerGroup,delete this._markers,this._map.removeLayer(this._poly),delete this._poly,this._mouseMarker.off("click",this._onClick,this),this._map.removeLayer(this._mouseMarker),delete this._mouseMarker,this._clearGuides(),this._map.off("mousemove",this._onMouseMove,this).off("zoomend",this._onZoomEnd,this)},_finishShape:function(){var t=this._poly.newLatLngIntersects(this._poly.getLatLngs()[0],!0);return!this.options.allowIntersection&&t||!this._shapeIsValid()?(this._showErrorTooltip(),undefined):(this._fireCreatedEvent(),this.disable(),undefined)},_shapeIsValid:function(){return!0},_onZoomEnd:function(){this._updateGuide()},_onMouseMove:function(t){var e=t.layerPoint,i=t.latlng;this._currentLatLng=i,this._tooltip.updatePosition(i),this._updateGuide(e),this._mouseMarker.setLatLng(i),L.DomEvent.preventDefault(t.originalEvent)},_onClick:function(t){var e=t.target.getLatLng(),i=this._markers.length;return i>0&&!this.options.allowIntersection&&this._poly.newLatLngIntersects(e)?(this._showErrorTooltip(),undefined):(this._errorShown&&this._hideErrorTooltip(),this._markers.push(this._createMarker(e)),this._poly.addLatLng(e),2===this._poly.getLatLngs().length&&this._map.addLayer(this._poly),this._updateFinishHandler(),this._vertexAdded(e),this._clearGuides(),undefined)},_updateFinishHandler:function(){var t=this._markers.length;t>1&&this._markers[t-1].on("click",this._finishShape,this),t>2&&this._markers[t-2].off("click",this._finishShape,this)},_createMarker:function(t){var e=new L.Marker(t,{icon:this.options.icon,zIndexOffset:2*this.options.zIndexOffset});return this._markerGroup.addLayer(e),e},_updateGuide:function(t){t=t||this._map.latLngToLayerPoint(this._currentLatLng);var e=this._markers.length;e>0&&(this._errorShown||this._tooltip.updateContent(this._getTooltipText()),this._clearGuides(),this._drawGuide(this._map.latLngToLayerPoint(this._markers[e-1].getLatLng()),t))},_drawGuide:function(t,e){var i,o,s,a,n=Math.floor(Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2)));for(this._guidesContainer||(this._guidesContainer=L.DomUtil.create("div","leaflet-draw-guides",this._overlayPane)),i=this.options.guidelineDistance;n>i;i+=this.options.guidelineDistance)o=i/n,s={x:Math.floor(t.x*(1-o)+o*e.x),y:Math.floor(t.y*(1-o)+o*e.y)},a=L.DomUtil.create("div","leaflet-draw-guide-dash",this._guidesContainer),a.style.backgroundColor=this._errorShown?this.options.drawError.color:this.options.shapeOptions.color,L.DomUtil.setPosition(a,s)},_updateGuideColor:function(t){if(this._guidesContainer)for(var e=0,i=this._guidesContainer.childNodes.length;i>e;e++)this._guidesContainer.childNodes[e].style.backgroundColor=t},_clearGuides:function(){if(this._guidesContainer)for(;this._guidesContainer.firstChild;)this._guidesContainer.removeChild(this._guidesContainer.firstChild)},_getTooltipText:function(){var t,e,i;return 0===this._markers.length?t={text:"Click to start drawing line."}:(e=this._measurementRunningTotal+this._currentLatLng.distanceTo(this._markers[this._markers.length-1].getLatLng()),i=e>1e3?(e/1e3).toFixed(2)+" km":Math.ceil(e)+" m",t=1===this._markers.length?{text:"Click to continue drawing line.",subtext:i}:{text:"Click last point to finish line.",subtext:i}),t},_showErrorTooltip:function(){this._errorShown=!0,this._tooltip.showAsError().updateContent({text:this.options.drawError.message}),this._updateGuideColor(this.options.drawError.color),this._poly.setStyle({color:this.options.drawError.color}),this._clearHideErrorTimeout(),this._hideErrorTimeout=setTimeout(L.Util.bind(this._hideErrorTooltip,this),this.options.drawError.timeout)},_hideErrorTooltip:function(){this._errorShown=!1,this._clearHideErrorTimeout(),this._tooltip.removeError().updateContent(this._getTooltipText()),this._updateGuideColor(this.options.shapeOptions.color),this._poly.setStyle({color:this.options.shapeOptions.color})},_clearHideErrorTimeout:function(){this._hideErrorTimeout&&(clearTimeout(this._hideErrorTimeout),this._hideErrorTimeout=null)},_vertexAdded:function(t){1===this._markers.length?this._measurementRunningTotal=0:this._measurementRunningTotal+=t.distanceTo(this._markers[this._markers.length-2].getLatLng())},_cleanUpShape:function(){this._markers.length>0&&this._markers[this._markers.length-1].off("click",this._finishShape,this)},_fireCreatedEvent:function(){var t=new this.Poly(this._poly.getLatLngs(),this.options.shapeOptions);L.Draw.Feature.prototype._fireCreatedEvent.call(this,t)}}),L.Draw.Polygon=L.Draw.Polyline.extend({statics:{TYPE:"polygon"},Poly:L.Polygon,options:{shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0}},initialize:function(t,e){L.Draw.Polyline.prototype.initialize.call(this,t,e),this.type=L.Draw.Polygon.TYPE},_updateFinishHandler:function(){var t=this._markers.length;1===t&&this._markers[0].on("click",this._finishShape,this),t>2&&(this._markers[t-1].on("dblclick",this._finishShape,this),t>3&&this._markers[t-2].off("dblclick",this._finishShape,this))},_getTooltipText:function(){var t;return t=0===this._markers.length?"Click to start drawing shape.":3>this._markers.length?"Click to continue drawing shape.":"Double click to close this shape.",{text:t}},_shapeIsValid:function(){return this._markers.length>=3},_vertexAdded:function(){},_cleanUpShape:function(){var t=this._markers.length;t>0&&(this._markers[0].off("click",this._finishShape,this),t>2&&this._markers[t-1].off("dblclick",this._finishShape,this))}}),L.SimpleShape={},L.Draw.SimpleShape=L.Draw.Feature.extend({addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._map.dragging.disable(),this._container.style.cursor="crosshair",this._tooltip.updateContent({text:this._initialLabelText}),this._map.on("mousedown",this._onMouseDown,this).on("mousemove",this._onMouseMove,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._map&&(this._map.dragging.enable(),this._container.style.cursor="",this._map.off("mousedown",this._onMouseDown,this).off("mousemove",this._onMouseMove,this),L.DomEvent.off(e,"mouseup",this._onMouseUp),this._shape&&(this._map.removeLayer(this._shape),delete this._shape)),this._isDrawing=!1},_onMouseDown:function(t){this._isDrawing=!0,this._startLatLng=t.latlng,L.DomEvent.on(e,"mouseup",this._onMouseUp,this).preventDefault(t.originalEvent)},_onMouseMove:function(t){var e=t.latlng;this._tooltip.updatePosition(e),this._isDrawing&&(this._tooltip.updateContent({text:"Release mouse to finish drawing."}),this._drawShape(e))},_onMouseUp:function(){this._shape&&this._fireCreatedEvent(),this.disable()}}),L.Draw.Rectangle=L.Draw.SimpleShape.extend({statics:{TYPE:"rectangle"},options:{shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0}},initialize:function(t,e){this.type=L.Draw.Rectangle.TYPE,L.Draw.SimpleShape.prototype.initialize.call(this,t,e)},_initialLabelText:"Click and drag to draw rectangle.",_drawShape:function(t){this._shape?this._shape.setBounds(new L.LatLngBounds(this._startLatLng,t)):(this._shape=new L.Rectangle(new L.LatLngBounds(this._startLatLng,t),this.options.shapeOptions),this._map.addLayer(this._shape))},_fireCreatedEvent:function(){var t=new L.Rectangle(this._shape.getBounds(),this.options.shapeOptions);L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this,t)}}),L.Draw.Circle=L.Draw.SimpleShape.extend({statics:{TYPE:"circle"},options:{shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0}},initialize:function(t,e){this.type=L.Draw.Circle.TYPE,L.Draw.SimpleShape.prototype.initialize.call(this,t,e)},_initialLabelText:"Click and drag to draw circle.",_drawShape:function(t){this._shape?this._shape.setRadius(this._startLatLng.distanceTo(t)):(this._shape=new L.Circle(this._startLatLng,this._startLatLng.distanceTo(t),this.options.shapeOptions),this._map.addLayer(this._shape))},_fireCreatedEvent:function(){var t=new L.Circle(this._startLatLng,this._shape.getRadius(),this.options.shapeOptions);L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this,t)},_onMouseMove:function(t){var e,i=t.latlng;this._tooltip.updatePosition(i),this._isDrawing&&(this._drawShape(i),e=this._shape.getRadius().toFixed(1),this._tooltip.updateContent({text:"Release mouse to finish drawing.",subtext:"Radius: "+e+" m"}))}}),L.Draw.Marker=L.Draw.Feature.extend({statics:{TYPE:"marker"},options:{icon:new L.Icon.Default,zIndexOffset:2e3},initialize:function(t,e){this.type=L.Draw.Marker.TYPE,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._tooltip.updateContent({text:"Click map to place marker."}),this._mouseMarker||(this._mouseMarker=L.marker(this._map.getCenter(),{icon:L.divIcon({className:"leaflet-mouse-marker",iconAnchor:[20,20],iconSize:[40,40]}),opacity:0,zIndexOffset:this.options.zIndexOffset})),this._mouseMarker.on("click",this._onClick,this).addTo(this._map),this._map.on("mousemove",this._onMouseMove,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._map&&(this._marker&&(this._marker.off("click",this._onClick,this),this._map.off("click",this._onClick,this).removeLayer(this._marker),delete this._marker),this._mouseMarker.off("click",this._onClick,this),this._map.removeLayer(this._mouseMarker),delete this._mouseMarker,this._map.off("mousemove",this._onMouseMove,this))},_onMouseMove:function(t){var e=t.latlng;this._tooltip.updatePosition(e),this._mouseMarker.setLatLng(e),this._marker?this._marker.setLatLng(e):(this._marker=new L.Marker(e,{icon:this.options.icon,zIndexOffset:this.options.zIndexOffset}),this._marker.on("click",this._onClick,this),this._map.on("click",this._onClick,this).addLayer(this._marker))},_onClick:function(){this._fireCreatedEvent(),this.disable()},_fireCreatedEvent:function(){var t=new L.Marker(this._marker.getLatLng(),{icon:this.options.icon});L.Draw.Feature.prototype._fireCreatedEvent.call(this,t)}}),L.Edit=L.Edit||{},L.Edit.Poly=L.Handler.extend({options:{icon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon"})},initialize:function(t,e){this._poly=t,L.setOptions(this,e)},addHooks:function(){this._poly._map&&(this._markerGroup||this._initMarkers(),this._poly._map.addLayer(this._markerGroup))},removeHooks:function(){this._poly._map&&(this._poly._map.removeLayer(this._markerGroup),delete this._markerGroup,delete this._markers)},updateMarkers:function(){this._markerGroup.clearLayers(),this._initMarkers()},_initMarkers:function(){this._markerGroup||(this._markerGroup=new L.LayerGroup),this._markers=[];var t,e,i,o,s=this._poly._latlngs;for(t=0,i=s.length;i>t;t++)o=this._createMarker(s[t],t),o.on("click",this._onMarkerClick,this),this._markers.push(o);var a,n;for(t=0,e=i-1;i>t;e=t++)(0!==t||L.Polygon&&this._poly instanceof L.Polygon)&&(a=this._markers[e],n=this._markers[t],this._createMiddleMarker(a,n),this._updatePrevNext(a,n))},_createMarker:function(t,e){var i=new L.Marker(t,{draggable:!0,icon:this.options.icon});return i._origLatLng=t,i._index=e,i.on("drag",this._onMarkerDrag,this),i.on("dragend",this._fireEdit,this),this._markerGroup.addLayer(i),i},_removeMarker:function(t){var e=t._index;this._markerGroup.removeLayer(t),this._markers.splice(e,1),this._poly.spliceLatLngs(e,1),this._updateIndexes(e,-1),t.off("drag",this._onMarkerDrag,this).off("dragend",this._fireEdit,this).off("click",this._onMarkerClick,this)},_fireEdit:function(){this._poly.edited=!0,this._poly.fire("edit")},_onMarkerDrag:function(t){var e=t.target;L.extend(e._origLatLng,e._latlng),e._middleLeft&&e._middleLeft.setLatLng(this._getMiddleLatLng(e._prev,e)),e._middleRight&&e._middleRight.setLatLng(this._getMiddleLatLng(e,e._next)),this._poly.redraw()},_onMarkerClick:function(t){if(!(3>this._poly._latlngs.length)){var e=t.target;this._removeMarker(e),this._updatePrevNext(e._prev,e._next),e._middleLeft&&this._markerGroup.removeLayer(e._middleLeft),e._middleRight&&this._markerGroup.removeLayer(e._middleRight),e._prev&&e._next?this._createMiddleMarker(e._prev,e._next):e._prev?e._next||(e._prev._middleRight=null):e._next._middleLeft=null,this._fireEdit()}},_updateIndexes:function(t,e){this._markerGroup.eachLayer(function(i){i._index>t&&(i._index+=e)})},_createMiddleMarker:function(t,e){var i,o,s,a=this._getMiddleLatLng(t,e),n=this._createMarker(a);n.setOpacity(.6),t._middleRight=e._middleLeft=n,o=function(){var o=e._index;n._index=o,n.off("click",i,this).on("click",this._onMarkerClick,this),a.lat=n.getLatLng().lat,a.lng=n.getLatLng().lng,this._poly.spliceLatLngs(o,0,a),this._markers.splice(o,0,n),n.setOpacity(1),this._updateIndexes(o,1),e._index++,this._updatePrevNext(t,n),this._updatePrevNext(n,e)},s=function(){n.off("dragstart",o,this),n.off("dragend",s,this),this._createMiddleMarker(t,n),this._createMiddleMarker(n,e)},i=function(){o.call(this),s.call(this),this._fireEdit()},n.on("click",i,this).on("dragstart",o,this).on("dragend",s,this),this._markerGroup.addLayer(n)},_updatePrevNext:function(t,e){t&&(t._next=e),e&&(e._prev=t)},_getMiddleLatLng:function(t,e){var i=this._poly._map,o=i.latLngToLayerPoint(t.getLatLng()),s=i.latLngToLayerPoint(e.getLatLng());return i.layerPointToLatLng(o._add(s)._divideBy(2))}}),L.Polyline.addInitHook(function(){this.editing||(L.Edit.Poly&&(this.editing=new L.Edit.Poly(this),this.options.editable&&this.editing.enable()),this.on("add",function(){this.editing&&this.editing.enabled()&&this.editing.addHooks()}),this.on("remove",function(){this.editing&&this.editing.enabled()&&this.editing.removeHooks()}))}),L.Edit=L.Edit||{},L.Edit.SimpleShape=L.Handler.extend({options:{moveIcon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon leaflet-edit-move"}),resizeIcon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon leaflet-edit-resize"})},initialize:function(t,e){this._shape=t,L.Util.setOptions(this,e)},addHooks:function(){this._shape._map&&(this._map=this._shape._map,this._markerGroup||this._initMarkers(),this._map.addLayer(this._markerGroup))},removeHooks:function(){if(this._shape._map){this._unbindMarker(this._moveMarker);for(var t=0,e=this._resizeMarkers.length;e>t;t++)this._unbindMarker(this._resizeMarkers[t]);this._resizeMarkers=null,this._map.removeLayer(this._markerGroup),delete this._markerGroup}this._map=null},updateMarkers:function(){this._markerGroup.clearLayers(),this._initMarkers()},_initMarkers:function(){this._markerGroup||(this._markerGroup=new L.LayerGroup),this._createMoveMarker(),this._createResizeMarker()},_createMoveMarker:function(){},_createResizeMarker:function(){},_createMarker:function(t,e){var i=new L.Marker(t,{draggable:!0,icon:e,zIndexOffset:10});return this._bindMarker(i),this._markerGroup.addLayer(i),i},_bindMarker:function(t){t.on("dragstart",this._onMarkerDragStart,this).on("drag",this._onMarkerDrag,this).on("dragend",this._onMarkerDragEnd,this)},_unbindMarker:function(t){t.off("dragstart",this._onMarkerDragStart,this).off("drag",this._onMarkerDrag,this).off("dragend",this._onMarkerDragEnd,this)},_onMarkerDragStart:function(t){var e=t.target;e.setOpacity(0)},_fireEdit:function(){this._shape.edited=!0,this._shape.fire("edit")},_onMarkerDrag:function(t){var e=t.target,i=e.getLatLng();e===this._moveMarker?this._move(i):this._resize(i),this._shape.redraw()},_onMarkerDragEnd:function(t){var e=t.target;e.setOpacity(1),this._shape.fire("edit"),this._fireEdit()},_move:function(){},_resize:function(){}}),L.Edit=L.Edit||{},L.Edit.Rectangle=L.Edit.SimpleShape.extend({_createMoveMarker:function(){var t=this._shape.getBounds(),e=t.getCenter();this._moveMarker=this._createMarker(e,this.options.moveIcon)},_createResizeMarker:function(){var t=this._getCorners();this._resizeMarkers=[];for(var e=0,i=t.length;i>e;e++)this._resizeMarkers.push(this._createMarker(t[e],this.options.resizeIcon)),this._resizeMarkers[e]._cornerIndex=e},_onMarkerDragStart:function(t){L.Edit.SimpleShape.prototype._onMarkerDragStart.call(this,t);var e=this._getCorners(),i=t.target,o=i._cornerIndex;this._oppositeCorner=e[(o+2)%4],this._toggleCornerMarkers(0,o)},_onMarkerDragEnd:function(t){var e,i,o=t.target;o===this._moveMarker&&(e=this._shape.getBounds(),i=e.getCenter(),o.setLatLng(i)),this._toggleCornerMarkers(1),this._repositionCornerMarkers(),L.Edit.SimpleShape.prototype._onMarkerDragEnd.call(this,t)},_move:function(t){for(var e,i=this._shape.getLatLngs(),o=this._shape.getBounds(),s=o.getCenter(),a=[],n=0,r=i.length;r>n;n++)e=[i[n].lat-s.lat,i[n].lng-s.lng],a.push([t.lat+e[0],t.lng+e[1]]);this._shape.setLatLngs(a),this._repositionCornerMarkers()},_resize:function(t){var e;this._shape.setBounds(L.latLngBounds(t,this._oppositeCorner)),e=this._shape.getBounds(),this._moveMarker.setLatLng(e.getCenter())},_getCorners:function(){var t=this._shape.getBounds(),e=t.getNorthWest(),i=t.getNorthEast(),o=t.getSouthEast(),s=t.getSouthWest();return[e,i,o,s]},_toggleCornerMarkers:function(t){for(var e=0,i=this._resizeMarkers.length;i>e;e++)this._resizeMarkers[e].setOpacity(t)},_repositionCornerMarkers:function(){for(var t=this._getCorners(),e=0,i=this._resizeMarkers.length;i>e;e++)this._resizeMarkers[e].setLatLng(t[e])}}),L.Rectangle.addInitHook(function(){L.Edit.Rectangle&&(this.editing=new L.Edit.Rectangle(this),this.options.editable&&this.editing.enable())}),L.Edit=L.Edit||{},L.Edit.Circle=L.Edit.SimpleShape.extend({_createMoveMarker:function(){var t=this._shape.getLatLng();this._moveMarker=this._createMarker(t,this.options.moveIcon)},_createResizeMarker:function(){var t=this._shape.getLatLng(),e=this._getResizeMarkerPoint(t);this._resizeMarkers=[],this._resizeMarkers.push(this._createMarker(e,this.options.resizeIcon))},_getResizeMarkerPoint:function(t){var e=this._shape._radius*Math.cos(Math.PI/4),i=this._map.project(t);return this._map.unproject([i.x+e,i.y-e])},_move:function(t){var e=this._getResizeMarkerPoint(t);this._resizeMarkers[0].setLatLng(e),this._shape.setLatLng(t)},_resize:function(t){var e=this._moveMarker.getLatLng(),i=e.distanceTo(t);this._shape.setRadius(i)}}),L.Circle.addInitHook(function(){L.Edit.Circle&&(this.editing=new L.Edit.Circle(this),this.options.editable&&this.editing.enable()),this.on("add",function(){this.editing&&this.editing.enabled()&&this.editing.addHooks()}),this.on("remove",function(){this.editing&&this.editing.enabled()&&this.editing.removeHooks()})}),L.LatLngUtil={cloneLatLngs:function(t){for(var e=[],i=0,o=t.length;o>i;i++)e.push(this.cloneLatLng(t[i]));return e},cloneLatLng:function(t){return L.latLng(t.lat,t.lng)}},L.Util.extend(L.LineUtil,{segmentsIntersect:function(t,e,i,o){return this._checkCounterclockwise(t,i,o)!==this._checkCounterclockwise(e,i,o)&&this._checkCounterclockwise(t,e,i)!==this._checkCounterclockwise(t,e,o)},_checkCounterclockwise:function(t,e,i){return(i.y-t.y)*(e.x-t.x)>(e.y-t.y)*(i.x-t.x)}}),L.Polyline.include({intersects:function(){var t,e,i,o=this._originalPoints,s=o?o.length:0;if(this._tooFewPointsForIntersection())return!1;for(t=s-1;t>=3;t--)if(e=o[t-1],i=o[t],this._lineSegmentsIntersectsRange(e,i,t-2))return!0;return!1},newLatLngIntersects:function(t,e){return this._map?this.newPointIntersects(this._map.latLngToLayerPoint(t),e):!1},newPointIntersects:function(t,e){var i=this._originalPoints,o=i?i.length:0,s=i?i[o-1]:null,a=o-2;return this._tooFewPointsForIntersection(1)?!1:this._lineSegmentsIntersectsRange(s,t,a,e?1:0)},_tooFewPointsForIntersection:function(t){var e=this._originalPoints,i=e?e.length:0;return i+=t||0,!this._originalPoints||3>=i},_lineSegmentsIntersectsRange:function(t,e,i,o){var s,a,n=this._originalPoints;o=o||0;for(var r=i;r>o;r--)if(s=n[r-1],a=n[r],L.LineUtil.segmentsIntersect(t,e,s,a))return!0;return!1}}),L.Polygon.include({intersects:function(){var t,e,i,o,s,a=this._originalPoints;return this._tooFewPointsForIntersection()?!1:(t=L.Polyline.prototype.intersects.call(this))?!0:(e=a.length,i=a[0],o=a[e-1],s=e-2,this._lineSegmentsIntersectsRange(o,i,s,1))}}),L.Control.Draw=L.Control.extend({options:{position:"topleft",draw:{},edit:!1},initialize:function(t){if("0.5.1">=L.version)throw Error("Leaflet.draw 0.2.0+ requires Leaflet 0.6.0+. Download latest from https://github.com/Leaflet/Leaflet/");L.Control.prototype.initialize.call(this,t);var e,i;this._toolbars={},L.DrawToolbar&&this.options.draw&&(i=new L.DrawToolbar(this.options.draw),e=L.stamp(i),this._toolbars[e]=i,this._toolbars[e].on("enable",this._toolbarEnabled,this)),L.EditToolbar&&this.options.edit&&(i=new L.EditToolbar(this.options.edit),e=L.stamp(i),this._toolbars[e]=i,this._toolbars[e].on("enable",this._toolbarEnabled,this))},onAdd:function(t){var e,i=L.DomUtil.create("div","leaflet-draw"),o=!1,s="leaflet-draw-toolbar-top";for(var a in this._toolbars)this._toolbars.hasOwnProperty(a)&&(e=this._toolbars[a].addToolbar(t),o||(L.DomUtil.hasClass(e,s)||L.DomUtil.addClass(e.childNodes[0],s),o=!0),i.appendChild(e));return i},onRemove:function(){for(var t in this._toolbars)this._toolbars.hasOwnProperty(t)&&this._toolbars[t].removeToolbar()},setDrawingOptions:function(t){for(var e in this._toolbars)this._toolbars[e]instanceof L.DrawToolbar&&this._toolbars[e].setOptions(t)},_toolbarEnabled:function(t){var e=""+L.stamp(t.target);for(var i in this._toolbars)this._toolbars.hasOwnProperty(i)&&i!==e&&this._toolbars[i].disable()}}),L.Map.mergeOptions({drawControl:!1}),L.Map.addInitHook(function(){this.options.drawControl&&(this.drawControl=new L.Control.Draw,this.addControl(this.drawControl))}),L.Toolbar=L.Class.extend({includes:[L.Mixin.Events],initialize:function(t){L.setOptions(this,t),this._modes={},this._actionButtons=[],this._activeMode=null},enabled:function(){return null!==this._activeMode},disable:function(){this.enabled()&&this._activeMode.handler.disable()},removeToolbar:function(){for(var t in this._modes)this._modes.hasOwnProperty(t)&&(this._disposeButton(this._modes[t].button,this._modes[t].handler.enable),this._modes[t].handler.disable(),this._modes[t].handler.off("enabled",this._handlerActivated,this).off("disabled",this._handlerDeactivated,this));this._modes={};for(var e=0,i=this._actionButtons.length;i>e;e++)this._disposeButton(this._actionButtons[e].button,this._actionButtons[e].callback);this._actionButtons=[],this._actionsContainer=null},_initModeHandler:function(t,e,i,o){var s=t.type;this._modes[s]={},this._modes[s].handler=t,this._modes[s].button=this._createButton({title:this.options[s].title,className:o+"-"+s,container:e,callback:this._modes[s].handler.enable,context:this._modes[s].handler}),this._modes[s].buttonIndex=i,this._modes[s].handler.on("enabled",this._handlerActivated,this).on("disabled",this._handlerDeactivated,this)},_createButton:function(t){var e=L.DomUtil.create("a",t.className||"",t.container);return e.href="#",t.text&&(e.innerHTML=t.text),t.title&&(e.title=t.title),L.DomEvent.on(e,"click",L.DomEvent.stopPropagation).on(e,"mousedown",L.DomEvent.stopPropagation).on(e,"dblclick",L.DomEvent.stopPropagation).on(e,"click",L.DomEvent.preventDefault).on(e,"click",t.callback,t.context),e},_disposeButton:function(t,e){L.DomEvent.off(t,"click",L.DomEvent.stopPropagation).off(t,"mousedown",L.DomEvent.stopPropagation).off(t,"dblclick",L.DomEvent.stopPropagation).off(t,"click",L.DomEvent.preventDefault).off(t,"click",e)},_handlerActivated:function(t){this._activeMode&&this._activeMode.handler.enabled()&&this._activeMode.handler.disable(),this._activeMode=this._modes[t.handler],L.DomUtil.addClass(this._activeMode.button,"leaflet-draw-toolbar-button-enabled"),this._showActionsToolbar(),this.fire("enable")},_handlerDeactivated:function(){this._hideActionsToolbar(),L.DomUtil.removeClass(this._activeMode.button,"leaflet-draw-toolbar-button-enabled"),this._activeMode=null,this.fire("disable")},_createActions:function(t){for(var e,i,o=L.DomUtil.create("ul","leaflet-draw-actions"),s=50,a=t.length,n=a*s+(a-1),r=0;a>r;r++)e=L.DomUtil.create("li","",o),i=this._createButton({title:t[r].title,text:t[r].text,container:e,callback:t[r].callback,context:t[r].context}),this._actionButtons.push({button:i,callback:t[r].callback});return o.style.width=n+"px",o},_showActionsToolbar:function(){var t=this._activeMode.buttonIndex,e=this._lastButtonIndex,i=26,o=1,s=t*i+t*o-1;this._actionsContainer.style.top=s+"px",0===t&&(L.DomUtil.addClass(this._toolbarContainer,"leaflet-draw-toolbar-notop"),L.DomUtil.addClass(this._actionsContainer,"leaflet-draw-actions-top")),t===e&&(L.DomUtil.addClass(this._toolbarContainer,"leaflet-draw-toolbar-nobottom"),L.DomUtil.addClass(this._actionsContainer,"leaflet-draw-actions-bottom")),this._actionsContainer.style.display="block"},_hideActionsToolbar:function(){this._actionsContainer.style.display="none",L.DomUtil.removeClass(this._toolbarContainer,"leaflet-draw-toolbar-notop"),L.DomUtil.removeClass(this._toolbarContainer,"leaflet-draw-toolbar-nobottom"),L.DomUtil.removeClass(this._actionsContainer,"leaflet-draw-actions-top"),L.DomUtil.removeClass(this._actionsContainer,"leaflet-draw-actions-bottom")}}),L.Tooltip=L.Class.extend({initialize:function(t){this._map=t,this._popupPane=t._panes.popupPane,this._container=L.DomUtil.create("div","leaflet-draw-tooltip",this._popupPane),this._singleLineLabel=!1},dispose:function(){this._popupPane.removeChild(this._container),this._container=null},updateContent:function(t){return t.subtext=t.subtext||"",0!==t.subtext.length||this._singleLineLabel?t.subtext.length>0&&this._singleLineLabel&&(L.DomUtil.removeClass(this._container,"leaflet-draw-tooltip-single"),this._singleLineLabel=!1):(L.DomUtil.addClass(this._container,"leaflet-draw-tooltip-single"),this._singleLineLabel=!0),this._container.innerHTML=(t.subtext.length>0?'<span class="leaflet-draw-tooltip-subtext">'+t.subtext+"</span>"+"<br />":"")+"<span>"+t.text+"</span>",this},updatePosition:function(t){var e=this._map.latLngToLayerPoint(t);return L.DomUtil.setPosition(this._container,e),this},showAsError:function(){return L.DomUtil.addClass(this._container,"leaflet-error-draw-tooltip"),this},removeError:function(){return L.DomUtil.removeClass(this._container,"leaflet-error-draw-tooltip"),this}}),L.DrawToolbar=L.Toolbar.extend({options:{polyline:{title:"Draw a polyline"},polygon:{title:"Draw a polygon"},rectangle:{title:"Draw a rectangle"},circle:{title:"Draw a circle"},marker:{title:"Add a marker"}},initialize:function(t){L.Toolbar.prototype.initialize.call(this,t)},addToolbar:function(t){var e=L.DomUtil.create("div","leaflet-draw-section"),i=0,o="leaflet-draw-draw";return this._toolbarContainer=L.DomUtil.create("div","leaflet-draw-toolbar leaflet-bar"),this.options.polyline&&this._initModeHandler(new L.Draw.Polyline(t,this.options.polyline),this._toolbarContainer,i++,o),this.options.polygon&&this._initModeHandler(new L.Draw.Polygon(t,this.options.polygon),this._toolbarContainer,i++,o),this.options.rectangle&&this._initModeHandler(new L.Draw.Rectangle(t,this.options.rectangle),this._toolbarContainer,i++,o),this.options.circle&&this._initModeHandler(new L.Draw.Circle(t,this.options.circle),this._toolbarContainer,i++,o),this.options.marker&&this._initModeHandler(new L.Draw.Marker(t,this.options.marker),this._toolbarContainer,i++,o),this._lastButtonIndex=--i,this._actionsContainer=this._createActions([{title:"Cancel drawing",text:"Cancel",callback:this.disable,context:this}]),e.appendChild(this._toolbarContainer),e.appendChild(this._actionsContainer),e},setOptions:function(t){L.setOptions(this,t);for(var e in this._modes)this._modes.hasOwnProperty(e)&&t.hasOwnProperty(e)&&this._modes[e].handler.setOptions(t[e])}}),L.EditToolbar=L.Toolbar.extend({options:{edit:{title:"Edit layers",selectedPathOptions:null},remove:{title:"Delete layers"},featureGroup:null},initialize:function(t){L.Toolbar.prototype.initialize.call(this,t),this._selectedFeatureCount=0},addToolbar:function(t){var e=L.DomUtil.create("div","leaflet-draw-section"),i=0,o="leaflet-draw-edit";return this._toolbarContainer=L.DomUtil.create("div","leaflet-draw-toolbar leaflet-bar"),this._map=t,this.options.edit&&this._initModeHandler(new L.EditToolbar.Edit(t,{featureGroup:this.options.featureGroup,selectedPathOptions:this.options.edit.selectedPathOptions}),this._toolbarContainer,i++,o),this.options.remove&&this._initModeHandler(new L.EditToolbar.Delete(t,{featureGroup:this.options.featureGroup}),this._toolbarContainer,i++,o),this._lastButtonIndex=--i,this._actionsContainer=this._createActions([{title:"Save changes.",text:"Save",callback:this._save,context:this},{title:"Cancel editing, discards all changes.",text:"Cancel",callback:this.disable,context:this}]),e.appendChild(this._toolbarContainer),e.appendChild(this._actionsContainer),e},disable:function(){this.enabled()&&(this._activeMode.handler.revertLayers(),L.Toolbar.prototype.disable.call(this))},_save:function(){this._activeMode.handler.save(),this._activeMode.handler.disable()}}),L.EditToolbar.Edit=L.Handler.extend({statics:{TYPE:"edit"},includes:L.Mixin.Events,options:{selectedPathOptions:{color:"#fe57a1",opacity:.6,dashArray:"10, 10",fill:!0,fillColor:"#fe57a1",fillOpacity:.1}},initialize:function(t,e){if(L.Handler.prototype.initialize.call(this,t),e.selectedPathOptions=e.selectedPathOptions||this.options.selectedPathOptions,L.Util.setOptions(this,e),this._featureGroup=this.options.featureGroup,!(this._featureGroup instanceof L.FeatureGroup))throw Error("options.featureGroup must be a L.FeatureGroup");
10
- this._uneditedLayerProps={},this.type=L.EditToolbar.Edit.TYPE},enable:function(){this._enabled||(L.Handler.prototype.enable.call(this),this._featureGroup.on("layeradd",this._enableLayerEdit,this).on("layerremove",this._disableLayerEdit,this),this.fire("enabled",{handler:this.type}))},disable:function(){this._enabled&&(this.fire("disabled",{handler:this.type}),this._featureGroup.off("layeradd",this._enableLayerEdit,this).off("layerremove",this._disableLayerEdit,this),L.Handler.prototype.disable.call(this))},addHooks:function(){this._map&&(this._featureGroup.eachLayer(this._enableLayerEdit,this),this._tooltip=new L.Tooltip(this._map),this._tooltip.updateContent({text:"Drag handles, or marker to edit feature.",subtext:"Click cancel to undo changes."}),this._map.on("mousemove",this._onMouseMove,this))},removeHooks:function(){this._map&&(this._featureGroup.eachLayer(this._disableLayerEdit,this),this._uneditedLayerProps={},this._tooltip.dispose(),this._tooltip=null,this._map.off("mousemove",this._onMouseMove,this))},revertLayers:function(){this._featureGroup.eachLayer(function(t){this._revertLayer(t)},this)},save:function(){var t=new L.LayerGroup;this._featureGroup.eachLayer(function(e){e.edited&&(t.addLayer(e),e.edited=!1)}),this._map.fire("draw:edited",{layers:t})},_backupLayer:function(t){var e=L.Util.stamp(t);this._uneditedLayerProps[e]||(this._uneditedLayerProps[e]=t instanceof L.Polyline||t instanceof L.Polygon||t instanceof L.Rectangle?{latlngs:L.LatLngUtil.cloneLatLngs(t.getLatLngs())}:t instanceof L.Circle?{latlng:L.LatLngUtil.cloneLatLng(t.getLatLng()),radius:t.getRadius()}:{latlng:L.LatLngUtil.cloneLatLng(t.getLatLng())})},_revertLayer:function(t){var e=L.Util.stamp(t);t.edited=!1,this._uneditedLayerProps.hasOwnProperty(e)&&(t instanceof L.Polyline||t instanceof L.Polygon||t instanceof L.Rectangle?t.setLatLngs(this._uneditedLayerProps[e].latlngs):t instanceof L.Circle?(t.setLatLng(this._uneditedLayerProps[e].latlng),t.setRadius(this._uneditedLayerProps[e].radius)):t.setLatLng(this._uneditedLayerProps[e].latlng))},_toggleMarkerHighlight:function(t){var e=t._icon;e.style.display="none",L.DomUtil.hasClass(e,"leaflet-edit-marker-selected")?(L.DomUtil.removeClass(e,"leaflet-edit-marker-selected"),this._offsetMarker(e,-4)):(L.DomUtil.addClass(e,"leaflet-edit-marker-selected"),this._offsetMarker(e,4)),e.style.display=""},_offsetMarker:function(t,e){var i=parseInt(t.style.marginTop,10)-e,o=parseInt(t.style.marginLeft,10)-e;t.style.marginTop=i+"px",t.style.marginLeft=o+"px"},_enableLayerEdit:function(t){var e=t.layer||t.target||t,i=L.Util.extend({},this.options.selectedPathOptions);this._backupLayer(e),e instanceof L.Marker?this._toggleMarkerHighlight(e):(e.options.previousOptions=e.options,e instanceof L.Circle||e instanceof L.Polygon||e instanceof L.Rectangle||(i.fill=!1),e.setStyle(i)),e instanceof L.Marker?(e.dragging.enable(),e.on("dragend",this._onMarkerDragEnd)):e.editing.enable()},_disableLayerEdit:function(t){var e=t.layer||t.target||t;e.edited=!1,e instanceof L.Marker?this._toggleMarkerHighlight(e):(e.setStyle(e.options.previousOptions),delete e.options.previousOptions),e instanceof L.Marker?(e.dragging.disable(),e.off("dragend",this._onMarkerDragEnd,this)):e.editing.disable()},_onMarkerDragEnd:function(t){var e=t.target;e.edited=!0},_onMouseMove:function(t){this._tooltip.updatePosition(t.latlng)}}),L.EditToolbar.Delete=L.Handler.extend({statics:{TYPE:"remove"},includes:L.Mixin.Events,initialize:function(t,e){if(L.Handler.prototype.initialize.call(this,t),L.Util.setOptions(this,e),this._deletableLayers=this.options.featureGroup,!(this._deletableLayers instanceof L.FeatureGroup))throw Error("options.featureGroup must be a L.FeatureGroup");this.type=L.EditToolbar.Delete.TYPE},enable:function(){this._enabled||(L.Handler.prototype.enable.call(this),this._deletableLayers.on("layeradd",this._enableLayerDelete,this).on("layerremove",this._disableLayerDelete,this),this.fire("enabled",{handler:this.type}))},disable:function(){this._enabled&&(L.Handler.prototype.disable.call(this),this._deletableLayers.off("layeradd",this._enableLayerDelete,this).off("layerremove",this._disableLayerDelete,this),this.fire("disabled",{handler:this.type}))},addHooks:function(){this._map&&(this._deletableLayers.eachLayer(this._enableLayerDelete,this),this._deletedLayers=new L.layerGroup,this._tooltip=new L.Tooltip(this._map),this._tooltip.updateContent({text:"Click on a feature to remove."}),this._map.on("mousemove",this._onMouseMove,this))},removeHooks:function(){this._map&&(this._deletableLayers.eachLayer(this._disableLayerDelete,this),this._deletedLayers=null,this._tooltip.dispose(),this._tooltip=null,this._map.off("mousemove",this._onMouseMove,this))},revertLayers:function(){this._deletedLayers.eachLayer(function(t){this._deletableLayers.addLayer(t)},this)},save:function(){this._map.fire("draw:deleted",{layers:this._deletedLayers})},_enableLayerDelete:function(t){var e=t.layer||t.target||t;e.on("click",this._removeLayer,this)},_disableLayerDelete:function(t){var e=t.layer||t.target||t;e.off("click",this._removeLayer,this),this._deletedLayers.removeLayer(e)},_removeLayer:function(t){var e=t.layer||t.target||t;this._deletableLayers.removeLayer(e),this._deletedLayers.addLayer(e)},_onMouseMove:function(t){this._tooltip.updatePosition(t.latlng)}})})(this,document);
9
+ (function(t,e){L.drawVersion="0.2.3-dev",L.drawLocal={draw:{toolbar:{actions:{title:"Cancel drawing",text:"Cancel"},buttons:{polyline:"Draw a polyline",polygon:"Draw a polygon",rectangle:"Draw a rectangle",circle:"Draw a circle",marker:"Draw a marker"}},handlers:{circle:{tooltip:{start:"Click and drag to draw circle."}},marker:{tooltip:{start:"Click map to place marker."}},polygon:{tooltip:{start:"Click to start drawing shape.",cont:"Click to continue drawing shape.",end:"Click first point to close this shape."}},polyline:{error:"<strong>Error:</strong> shape edges cannot cross!",tooltip:{start:"Click to start drawing line.",cont:"Click to continue drawing line.",end:"Click last point to finish line."}},rectangle:{tooltip:{start:"Click and drag to draw rectangle."}},simpleshape:{tooltip:{end:"Release mouse to finish drawing."}}}},edit:{toolbar:{actions:{save:{title:"Save changes.",text:"Save"},cancel:{title:"Cancel editing, discards all changes.",text:"Cancel"}},buttons:{edit:"Edit layers.",editDisabled:"No layers to edit.",remove:"Delete layers.",removeDisabled:"No layers to delete."}},handlers:{edit:{tooltip:{text:"Drag handles, or marker to edit feature.",subtext:"Click cancel to undo changes."}},remove:{tooltip:{text:"Click on a feature to remove"}}}}},L.Draw={},L.Draw.Feature=L.Handler.extend({includes:L.Mixin.Events,initialize:function(t,e){this._map=t,this._container=t._container,this._overlayPane=t._panes.overlayPane,this._popupPane=t._panes.popupPane,e&&e.shapeOptions&&(e.shapeOptions=L.Util.extend({},this.options.shapeOptions,e.shapeOptions)),L.setOptions(this,e)},enable:function(){this._enabled||(L.Handler.prototype.enable.call(this),this.fire("enabled",{handler:this.type}),this._map.fire("draw:drawstart",{layerType:this.type}))},disable:function(){this._enabled&&(L.Handler.prototype.disable.call(this),this.fire("disabled",{handler:this.type}),this._map.fire("draw:drawstop",{layerType:this.type}))},addHooks:function(){var t=this._map;t&&(L.DomUtil.disableTextSelection(),t.getContainer().focus(),this._tooltip=new L.Tooltip(this._map),L.DomEvent.addListener(this._container,"keyup",this._cancelDrawing,this))},removeHooks:function(){this._map&&(L.DomUtil.enableTextSelection(),this._tooltip.dispose(),this._tooltip=null,L.DomEvent.removeListener(this._container,"keyup",this._cancelDrawing))},setOptions:function(t){L.setOptions(this,t)},_fireCreatedEvent:function(t){this._map.fire("draw:created",{layer:t,layerType:this.type})},_cancelDrawing:function(t){27===t.keyCode&&this.disable()}}),L.Draw.Polyline=L.Draw.Feature.extend({statics:{TYPE:"polyline"},Poly:L.Polyline,options:{allowIntersection:!0,repeatMode:!1,drawError:{color:"#b00b00",timeout:2500},icon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon"}),guidelineDistance:20,shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!1,clickable:!0},metric:!0,showLength:!0,zIndexOffset:2e3},initialize:function(t,e){this.options.drawError.message=L.drawLocal.draw.handlers.polyline.error,e&&e.drawError&&(e.drawError=L.Util.extend({},this.options.drawError,e.drawError)),this.type=L.Draw.Polyline.TYPE,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._markers=[],this._markerGroup=new L.LayerGroup,this._map.addLayer(this._markerGroup),this._poly=new L.Polyline([],this.options.shapeOptions),this._tooltip.updateContent(this._getTooltipText()),this._mouseMarker||(this._mouseMarker=L.marker(this._map.getCenter(),{icon:L.divIcon({className:"leaflet-mouse-marker",iconAnchor:[20,20],iconSize:[40,40]}),opacity:0,zIndexOffset:this.options.zIndexOffset})),this._mouseMarker.on("click",this._onClick,this).addTo(this._map),this._map.on("mousemove",this._onMouseMove,this).on("zoomend",this._onZoomEnd,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._clearHideErrorTimeout(),this._cleanUpShape(),this._map.removeLayer(this._markerGroup),delete this._markerGroup,delete this._markers,this._map.removeLayer(this._poly),delete this._poly,this._mouseMarker.off("click",this._onClick,this),this._map.removeLayer(this._mouseMarker),delete this._mouseMarker,this._clearGuides(),this._map.off("mousemove",this._onMouseMove,this).off("zoomend",this._onZoomEnd,this)},_finishShape:function(){var t=this._poly.newLatLngIntersects(this._poly.getLatLngs()[0],!0);return!this.options.allowIntersection&&t||!this._shapeIsValid()?(this._showErrorTooltip(),undefined):(this._fireCreatedEvent(),this.disable(),this.options.repeatMode&&this.enable(),undefined)},_shapeIsValid:function(){return!0},_onZoomEnd:function(){this._updateGuide()},_onMouseMove:function(t){var e=t.layerPoint,i=t.latlng;this._currentLatLng=i,this._updateTooltip(i),this._updateGuide(e),this._mouseMarker.setLatLng(i),L.DomEvent.preventDefault(t.originalEvent)},_onClick:function(t){var e=t.target.getLatLng(),i=this._markers.length;return i>0&&!this.options.allowIntersection&&this._poly.newLatLngIntersects(e)?(this._showErrorTooltip(),undefined):(this._errorShown&&this._hideErrorTooltip(),this._markers.push(this._createMarker(e)),this._poly.addLatLng(e),2===this._poly.getLatLngs().length&&this._map.addLayer(this._poly),this._updateFinishHandler(),this._vertexAdded(e),this._clearGuides(),this._updateTooltip(),undefined)},_updateFinishHandler:function(){var t=this._markers.length;t>1&&this._markers[t-1].on("click",this._finishShape,this),t>2&&this._markers[t-2].off("click",this._finishShape,this)},_createMarker:function(t){var e=new L.Marker(t,{icon:this.options.icon,zIndexOffset:2*this.options.zIndexOffset});return this._markerGroup.addLayer(e),e},_updateGuide:function(t){var e=this._markers.length;e>0&&(t=t||this._map.latLngToLayerPoint(this._currentLatLng),this._clearGuides(),this._drawGuide(this._map.latLngToLayerPoint(this._markers[e-1].getLatLng()),t))},_updateTooltip:function(t){var e=this._getTooltipText();t&&this._tooltip.updatePosition(t),this._errorShown||this._tooltip.updateContent(e)},_drawGuide:function(t,e){var i,o,a,s,r=Math.floor(Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2)));for(this._guidesContainer||(this._guidesContainer=L.DomUtil.create("div","leaflet-draw-guides",this._overlayPane)),i=this.options.guidelineDistance;r>i;i+=this.options.guidelineDistance)o=i/r,a={x:Math.floor(t.x*(1-o)+o*e.x),y:Math.floor(t.y*(1-o)+o*e.y)},s=L.DomUtil.create("div","leaflet-draw-guide-dash",this._guidesContainer),s.style.backgroundColor=this._errorShown?this.options.drawError.color:this.options.shapeOptions.color,L.DomUtil.setPosition(s,a)},_updateGuideColor:function(t){if(this._guidesContainer)for(var e=0,i=this._guidesContainer.childNodes.length;i>e;e++)this._guidesContainer.childNodes[e].style.backgroundColor=t},_clearGuides:function(){if(this._guidesContainer)for(;this._guidesContainer.firstChild;)this._guidesContainer.removeChild(this._guidesContainer.firstChild)},_getTooltipText:function(){var t,e,i=this.options.showLength;return 0===this._markers.length?t={text:L.drawLocal.draw.handlers.polyline.tooltip.start}:(e=i?this._getMeasurementString():"",t=1===this._markers.length?{text:L.drawLocal.draw.handlers.polyline.tooltip.cont,subtext:e}:{text:L.drawLocal.draw.handlers.polyline.tooltip.end,subtext:e}),t},_getMeasurementString:function(){var t,e=this._currentLatLng,i=this._markers[this._markers.length-1].getLatLng();return t=this._measurementRunningTotal+e.distanceTo(i),L.GeometryUtil.readableDistance(t,this.options.metric)},_showErrorTooltip:function(){this._errorShown=!0,this._tooltip.showAsError().updateContent({text:this.options.drawError.message}),this._updateGuideColor(this.options.drawError.color),this._poly.setStyle({color:this.options.drawError.color}),this._clearHideErrorTimeout(),this._hideErrorTimeout=setTimeout(L.Util.bind(this._hideErrorTooltip,this),this.options.drawError.timeout)},_hideErrorTooltip:function(){this._errorShown=!1,this._clearHideErrorTimeout(),this._tooltip.removeError().updateContent(this._getTooltipText()),this._updateGuideColor(this.options.shapeOptions.color),this._poly.setStyle({color:this.options.shapeOptions.color})},_clearHideErrorTimeout:function(){this._hideErrorTimeout&&(clearTimeout(this._hideErrorTimeout),this._hideErrorTimeout=null)},_vertexAdded:function(t){1===this._markers.length?this._measurementRunningTotal=0:this._measurementRunningTotal+=t.distanceTo(this._markers[this._markers.length-2].getLatLng())},_cleanUpShape:function(){this._markers.length>1&&this._markers[this._markers.length-1].off("click",this._finishShape,this)},_fireCreatedEvent:function(){var t=new this.Poly(this._poly.getLatLngs(),this.options.shapeOptions);L.Draw.Feature.prototype._fireCreatedEvent.call(this,t)}}),L.Draw.Polygon=L.Draw.Polyline.extend({statics:{TYPE:"polygon"},Poly:L.Polygon,options:{showArea:!1,shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0}},initialize:function(t,e){L.Draw.Polyline.prototype.initialize.call(this,t,e),this.type=L.Draw.Polygon.TYPE},_updateFinishHandler:function(){var t=this._markers.length;1===t&&this._markers[0].on("click",this._finishShape,this),t>2&&(this._markers[t-1].on("dblclick",this._finishShape,this),t>3&&this._markers[t-2].off("dblclick",this._finishShape,this))},_getTooltipText:function(){var t,e;return 0===this._markers.length?t=L.drawLocal.draw.handlers.polygon.tooltip.start:3>this._markers.length?t=L.drawLocal.draw.handlers.polygon.tooltip.cont:(t=L.drawLocal.draw.handlers.polygon.tooltip.end,e=this._getMeasurementString()),{text:t,subtext:e}},_getMeasurementString:function(){var t=this._area;return t?L.GeometryUtil.readableArea(t,this.options.metric):null},_shapeIsValid:function(){return this._markers.length>=3},_vertexAdded:function(){if(!this.options.allowIntersection&&this.options.showArea){var t=this._poly.getLatLngs();this._area=L.GeometryUtil.geodesicArea(t)}},_cleanUpShape:function(){var t=this._markers.length;t>0&&(this._markers[0].off("click",this._finishShape,this),t>2&&this._markers[t-1].off("dblclick",this._finishShape,this))}}),L.SimpleShape={},L.Draw.SimpleShape=L.Draw.Feature.extend({options:{repeatMode:!1},initialize:function(t,e){this._endLabelText=L.drawLocal.draw.handlers.simpleshape.tooltip.end,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._map.dragging.disable(),this._container.style.cursor="crosshair",this._tooltip.updateContent({text:this._initialLabelText}),this._map.on("mousedown",this._onMouseDown,this).on("mousemove",this._onMouseMove,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._map&&(this._map.dragging.enable(),this._container.style.cursor="",this._map.off("mousedown",this._onMouseDown,this).off("mousemove",this._onMouseMove,this),L.DomEvent.off(e,"mouseup",this._onMouseUp),this._shape&&(this._map.removeLayer(this._shape),delete this._shape)),this._isDrawing=!1},_onMouseDown:function(t){this._isDrawing=!0,this._startLatLng=t.latlng,L.DomEvent.on(e,"mouseup",this._onMouseUp,this).preventDefault(t.originalEvent)},_onMouseMove:function(t){var e=t.latlng;this._tooltip.updatePosition(e),this._isDrawing&&(this._tooltip.updateContent({text:this._endLabelText}),this._drawShape(e))},_onMouseUp:function(){this._shape&&this._fireCreatedEvent(),this.disable(),this.options.repeatMode&&this.enable()}}),L.Draw.Rectangle=L.Draw.SimpleShape.extend({statics:{TYPE:"rectangle"},options:{shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0}},initialize:function(t,e){this.type=L.Draw.Rectangle.TYPE,this._initialLabelText=L.drawLocal.draw.handlers.rectangle.tooltip.start,L.Draw.SimpleShape.prototype.initialize.call(this,t,e)},_drawShape:function(t){this._shape?this._shape.setBounds(new L.LatLngBounds(this._startLatLng,t)):(this._shape=new L.Rectangle(new L.LatLngBounds(this._startLatLng,t),this.options.shapeOptions),this._map.addLayer(this._shape))},_fireCreatedEvent:function(){var t=new L.Rectangle(this._shape.getBounds(),this.options.shapeOptions);L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this,t)}}),L.Draw.Circle=L.Draw.SimpleShape.extend({statics:{TYPE:"circle"},options:{shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0},showRadius:!0,metric:!0},initialize:function(t,e){this.type=L.Draw.Circle.TYPE,this._initialLabelText=L.drawLocal.draw.handlers.circle.tooltip.start,L.Draw.SimpleShape.prototype.initialize.call(this,t,e)},_drawShape:function(t){this._shape?this._shape.setRadius(this._startLatLng.distanceTo(t)):(this._shape=new L.Circle(this._startLatLng,this._startLatLng.distanceTo(t),this.options.shapeOptions),this._map.addLayer(this._shape))},_fireCreatedEvent:function(){var t=new L.Circle(this._startLatLng,this._shape.getRadius(),this.options.shapeOptions);L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this,t)},_onMouseMove:function(t){var e,i=t.latlng,o=(this.options.metric,this.options.showRadius),a=this.options.metric;this._tooltip.updatePosition(i),this._isDrawing&&(this._drawShape(i),e=this._shape.getRadius().toFixed(1),this._tooltip.updateContent({text:this._endLabelText,subtext:o?"Radius: "+L.GeometryUtil.readableDistance(e,a):""}))}}),L.Draw.Marker=L.Draw.Feature.extend({statics:{TYPE:"marker"},options:{icon:new L.Icon.Default,repeatMode:!1,zIndexOffset:2e3},initialize:function(t,e){this.type=L.Draw.Marker.TYPE,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._tooltip.updateContent({text:L.drawLocal.draw.handlers.marker.tooltip.start}),this._mouseMarker||(this._mouseMarker=L.marker(this._map.getCenter(),{icon:L.divIcon({className:"leaflet-mouse-marker",iconAnchor:[20,20],iconSize:[40,40]}),opacity:0,zIndexOffset:this.options.zIndexOffset})),this._mouseMarker.on("click",this._onClick,this).addTo(this._map),this._map.on("mousemove",this._onMouseMove,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._map&&(this._marker&&(this._marker.off("click",this._onClick,this),this._map.off("click",this._onClick,this).removeLayer(this._marker),delete this._marker),this._mouseMarker.off("click",this._onClick,this),this._map.removeLayer(this._mouseMarker),delete this._mouseMarker,this._map.off("mousemove",this._onMouseMove,this))},_onMouseMove:function(t){var e=t.latlng;this._tooltip.updatePosition(e),this._mouseMarker.setLatLng(e),this._marker?(e=this._mouseMarker.getLatLng(),this._marker.setLatLng(e)):(this._marker=new L.Marker(e,{icon:this.options.icon,zIndexOffset:this.options.zIndexOffset}),this._marker.on("click",this._onClick,this),this._map.on("click",this._onClick,this).addLayer(this._marker))},_onClick:function(){this._fireCreatedEvent(),this.disable(),this.options.repeatMode&&this.enable()},_fireCreatedEvent:function(){var t=new L.Marker(this._marker.getLatLng(),{icon:this.options.icon});L.Draw.Feature.prototype._fireCreatedEvent.call(this,t)}}),L.Edit=L.Edit||{},L.Edit.Poly=L.Handler.extend({options:{icon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon"})},initialize:function(t,e){this._poly=t,L.setOptions(this,e)},addHooks:function(){this._poly._map&&(this._markerGroup||this._initMarkers(),this._poly._map.addLayer(this._markerGroup))},removeHooks:function(){this._poly._map&&(this._poly._map.removeLayer(this._markerGroup),delete this._markerGroup,delete this._markers)},updateMarkers:function(){this._markerGroup.clearLayers(),this._initMarkers()},_initMarkers:function(){this._markerGroup||(this._markerGroup=new L.LayerGroup),this._markers=[];var t,e,i,o,a=this._poly._latlngs;for(t=0,i=a.length;i>t;t++)o=this._createMarker(a[t],t),o.on("click",this._onMarkerClick,this),this._markers.push(o);var s,r;for(t=0,e=i-1;i>t;e=t++)(0!==t||L.Polygon&&this._poly instanceof L.Polygon)&&(s=this._markers[e],r=this._markers[t],this._createMiddleMarker(s,r),this._updatePrevNext(s,r))},_createMarker:function(t,e){var i=new L.Marker(t,{draggable:!0,icon:this.options.icon});return i._origLatLng=t,i._index=e,i.on("drag",this._onMarkerDrag,this),i.on("dragend",this._fireEdit,this),this._markerGroup.addLayer(i),i},_removeMarker:function(t){var e=t._index;this._markerGroup.removeLayer(t),this._markers.splice(e,1),this._poly.spliceLatLngs(e,1),this._updateIndexes(e,-1),t.off("drag",this._onMarkerDrag,this).off("dragend",this._fireEdit,this).off("click",this._onMarkerClick,this)},_fireEdit:function(){this._poly.edited=!0,this._poly.fire("edit")},_onMarkerDrag:function(t){var e=t.target;L.extend(e._origLatLng,e._latlng),e._middleLeft&&e._middleLeft.setLatLng(this._getMiddleLatLng(e._prev,e)),e._middleRight&&e._middleRight.setLatLng(this._getMiddleLatLng(e,e._next)),this._poly.redraw()},_onMarkerClick:function(t){var e=L.Polygon&&this._poly instanceof L.Polygon?4:3,i=t.target;e>this._poly._latlngs.length||(this._removeMarker(i),this._updatePrevNext(i._prev,i._next),i._middleLeft&&this._markerGroup.removeLayer(i._middleLeft),i._middleRight&&this._markerGroup.removeLayer(i._middleRight),i._prev&&i._next?this._createMiddleMarker(i._prev,i._next):i._prev?i._next||(i._prev._middleRight=null):i._next._middleLeft=null,this._fireEdit())},_updateIndexes:function(t,e){this._markerGroup.eachLayer(function(i){i._index>t&&(i._index+=e)})},_createMiddleMarker:function(t,e){var i,o,a,s=this._getMiddleLatLng(t,e),r=this._createMarker(s);r.setOpacity(.6),t._middleRight=e._middleLeft=r,o=function(){var o=e._index;r._index=o,r.off("click",i,this).on("click",this._onMarkerClick,this),s.lat=r.getLatLng().lat,s.lng=r.getLatLng().lng,this._poly.spliceLatLngs(o,0,s),this._markers.splice(o,0,r),r.setOpacity(1),this._updateIndexes(o,1),e._index++,this._updatePrevNext(t,r),this._updatePrevNext(r,e)},a=function(){r.off("dragstart",o,this),r.off("dragend",a,this),this._createMiddleMarker(t,r),this._createMiddleMarker(r,e)},i=function(){o.call(this),a.call(this),this._fireEdit()},r.on("click",i,this).on("dragstart",o,this).on("dragend",a,this),this._markerGroup.addLayer(r)},_updatePrevNext:function(t,e){t&&(t._next=e),e&&(e._prev=t)},_getMiddleLatLng:function(t,e){var i=this._poly._map,o=i.project(t.getLatLng()),a=i.project(e.getLatLng());return i.unproject(o._add(a)._divideBy(2))}}),L.Polyline.addInitHook(function(){this.editing||(L.Edit.Poly&&(this.editing=new L.Edit.Poly(this),this.options.editable&&this.editing.enable()),this.on("add",function(){this.editing&&this.editing.enabled()&&this.editing.addHooks()}),this.on("remove",function(){this.editing&&this.editing.enabled()&&this.editing.removeHooks()}))}),L.Edit=L.Edit||{},L.Edit.SimpleShape=L.Handler.extend({options:{moveIcon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon leaflet-edit-move"}),resizeIcon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon leaflet-edit-resize"})},initialize:function(t,e){this._shape=t,L.Util.setOptions(this,e)},addHooks:function(){this._shape._map&&(this._map=this._shape._map,this._markerGroup||this._initMarkers(),this._map.addLayer(this._markerGroup))},removeHooks:function(){if(this._shape._map){this._unbindMarker(this._moveMarker);for(var t=0,e=this._resizeMarkers.length;e>t;t++)this._unbindMarker(this._resizeMarkers[t]);this._resizeMarkers=null,this._map.removeLayer(this._markerGroup),delete this._markerGroup}this._map=null},updateMarkers:function(){this._markerGroup.clearLayers(),this._initMarkers()},_initMarkers:function(){this._markerGroup||(this._markerGroup=new L.LayerGroup),this._createMoveMarker(),this._createResizeMarker()},_createMoveMarker:function(){},_createResizeMarker:function(){},_createMarker:function(t,e){var i=new L.Marker(t,{draggable:!0,icon:e,zIndexOffset:10});return this._bindMarker(i),this._markerGroup.addLayer(i),i},_bindMarker:function(t){t.on("dragstart",this._onMarkerDragStart,this).on("drag",this._onMarkerDrag,this).on("dragend",this._onMarkerDragEnd,this)},_unbindMarker:function(t){t.off("dragstart",this._onMarkerDragStart,this).off("drag",this._onMarkerDrag,this).off("dragend",this._onMarkerDragEnd,this)},_onMarkerDragStart:function(t){var e=t.target;e.setOpacity(0)},_fireEdit:function(){this._shape.edited=!0,this._shape.fire("edit")},_onMarkerDrag:function(t){var e=t.target,i=e.getLatLng();e===this._moveMarker?this._move(i):this._resize(i),this._shape.redraw()},_onMarkerDragEnd:function(t){var e=t.target;e.setOpacity(1),this._fireEdit()},_move:function(){},_resize:function(){}}),L.Edit=L.Edit||{},L.Edit.Rectangle=L.Edit.SimpleShape.extend({_createMoveMarker:function(){var t=this._shape.getBounds(),e=t.getCenter();this._moveMarker=this._createMarker(e,this.options.moveIcon)},_createResizeMarker:function(){var t=this._getCorners();this._resizeMarkers=[];for(var e=0,i=t.length;i>e;e++)this._resizeMarkers.push(this._createMarker(t[e],this.options.resizeIcon)),this._resizeMarkers[e]._cornerIndex=e},_onMarkerDragStart:function(t){L.Edit.SimpleShape.prototype._onMarkerDragStart.call(this,t);var e=this._getCorners(),i=t.target,o=i._cornerIndex;this._oppositeCorner=e[(o+2)%4],this._toggleCornerMarkers(0,o)},_onMarkerDragEnd:function(t){var e,i,o=t.target;o===this._moveMarker&&(e=this._shape.getBounds(),i=e.getCenter(),o.setLatLng(i)),this._toggleCornerMarkers(1),this._repositionCornerMarkers(),L.Edit.SimpleShape.prototype._onMarkerDragEnd.call(this,t)},_move:function(t){for(var e,i=this._shape.getLatLngs(),o=this._shape.getBounds(),a=o.getCenter(),s=[],r=0,n=i.length;n>r;r++)e=[i[r].lat-a.lat,i[r].lng-a.lng],s.push([t.lat+e[0],t.lng+e[1]]);this._shape.setLatLngs(s),this._repositionCornerMarkers()},_resize:function(t){var e;this._shape.setBounds(L.latLngBounds(t,this._oppositeCorner)),e=this._shape.getBounds(),this._moveMarker.setLatLng(e.getCenter())},_getCorners:function(){var t=this._shape.getBounds(),e=t.getNorthWest(),i=t.getNorthEast(),o=t.getSouthEast(),a=t.getSouthWest();return[e,i,o,a]},_toggleCornerMarkers:function(t){for(var e=0,i=this._resizeMarkers.length;i>e;e++)this._resizeMarkers[e].setOpacity(t)},_repositionCornerMarkers:function(){for(var t=this._getCorners(),e=0,i=this._resizeMarkers.length;i>e;e++)this._resizeMarkers[e].setLatLng(t[e])}}),L.Rectangle.addInitHook(function(){L.Edit.Rectangle&&(this.editing=new L.Edit.Rectangle(this),this.options.editable&&this.editing.enable())}),L.Edit=L.Edit||{},L.Edit.Circle=L.Edit.SimpleShape.extend({_createMoveMarker:function(){var t=this._shape.getLatLng();this._moveMarker=this._createMarker(t,this.options.moveIcon)},_createResizeMarker:function(){var t=this._shape.getLatLng(),e=this._getResizeMarkerPoint(t);this._resizeMarkers=[],this._resizeMarkers.push(this._createMarker(e,this.options.resizeIcon))},_getResizeMarkerPoint:function(t){var e=this._shape._radius*Math.cos(Math.PI/4),i=this._map.project(t);return this._map.unproject([i.x+e,i.y-e])},_move:function(t){var e=this._getResizeMarkerPoint(t);this._resizeMarkers[0].setLatLng(e),this._shape.setLatLng(t)},_resize:function(t){var e=this._moveMarker.getLatLng(),i=e.distanceTo(t);this._shape.setRadius(i)}}),L.Circle.addInitHook(function(){L.Edit.Circle&&(this.editing=new L.Edit.Circle(this),this.options.editable&&this.editing.enable()),this.on("add",function(){this.editing&&this.editing.enabled()&&this.editing.addHooks()}),this.on("remove",function(){this.editing&&this.editing.enabled()&&this.editing.removeHooks()})}),L.LatLngUtil={cloneLatLngs:function(t){for(var e=[],i=0,o=t.length;o>i;i++)e.push(this.cloneLatLng(t[i]));return e},cloneLatLng:function(t){return L.latLng(t.lat,t.lng)}},L.GeometryUtil={geodesicArea:function(t){var e,i,o=t.length,a=0,s=L.LatLng.DEG_TO_RAD;if(o>2){for(var r=0;o>r;r++)e=t[r],i=t[(r+1)%o],a+=(i.lng-e.lng)*s*(2+Math.sin(e.lat*s)+Math.sin(i.lat*s));a=6378137*6378137*a/2}return Math.abs(a)},readableArea:function(t,e){var i;return e?i=t>=1e4?(1e-4*t).toFixed(2)+" ha":t.toFixed(2)+" m&sup2;":(t*=.836127,i=t>=3097600?(t/3097600).toFixed(2)+" mi&sup2;":t>=4840?(t/4840).toFixed(2)+" acres":Math.ceil(t)+" yd&sup2;"),i},readableDistance:function(t,e){var i;return e?i=t>1e3?(t/1e3).toFixed(2)+" km":Math.ceil(t)+" m":(t*=1.09361,i=t>1760?(t/1760).toFixed(2)+" miles":Math.ceil(t)+" yd"),i}},L.Util.extend(L.LineUtil,{segmentsIntersect:function(t,e,i,o){return this._checkCounterclockwise(t,i,o)!==this._checkCounterclockwise(e,i,o)&&this._checkCounterclockwise(t,e,i)!==this._checkCounterclockwise(t,e,o)},_checkCounterclockwise:function(t,e,i){return(i.y-t.y)*(e.x-t.x)>(e.y-t.y)*(i.x-t.x)}}),L.Polyline.include({intersects:function(){var t,e,i,o=this._originalPoints,a=o?o.length:0;if(this._tooFewPointsForIntersection())return!1;for(t=a-1;t>=3;t--)if(e=o[t-1],i=o[t],this._lineSegmentsIntersectsRange(e,i,t-2))return!0;return!1},newLatLngIntersects:function(t,e){return this._map?this.newPointIntersects(this._map.latLngToLayerPoint(t),e):!1},newPointIntersects:function(t,e){var i=this._originalPoints,o=i?i.length:0,a=i?i[o-1]:null,s=o-2;return this._tooFewPointsForIntersection(1)?!1:this._lineSegmentsIntersectsRange(a,t,s,e?1:0)},_tooFewPointsForIntersection:function(t){var e=this._originalPoints,i=e?e.length:0;return i+=t||0,!this._originalPoints||3>=i},_lineSegmentsIntersectsRange:function(t,e,i,o){var a,s,r=this._originalPoints;o=o||0;for(var n=i;n>o;n--)if(a=r[n-1],s=r[n],L.LineUtil.segmentsIntersect(t,e,a,s))return!0;return!1}}),L.Polygon.include({intersects:function(){var t,e,i,o,a,s=this._originalPoints;return this._tooFewPointsForIntersection()?!1:(t=L.Polyline.prototype.intersects.call(this))?!0:(e=s.length,i=s[0],o=s[e-1],a=e-2,this._lineSegmentsIntersectsRange(o,i,a,1))}}),L.Control.Draw=L.Control.extend({options:{position:"topleft",draw:{},edit:!1},initialize:function(t){if("0.5.1">=L.version)throw Error("Leaflet.draw 0.2.0+ requires Leaflet 0.6.0+. Download latest from https://github.com/Leaflet/Leaflet/");L.Control.prototype.initialize.call(this,t);var e,i;this._toolbars={},L.DrawToolbar&&this.options.draw&&(i=new L.DrawToolbar(this.options.draw),e=L.stamp(i),this._toolbars[e]=i,this._toolbars[e].on("enable",this._toolbarEnabled,this)),L.EditToolbar&&this.options.edit&&(i=new L.EditToolbar(this.options.edit),e=L.stamp(i),this._toolbars[e]=i,this._toolbars[e].on("enable",this._toolbarEnabled,this))},onAdd:function(t){var e,i=L.DomUtil.create("div","leaflet-draw"),o=!1,a="leaflet-draw-toolbar-top";for(var s in this._toolbars)this._toolbars.hasOwnProperty(s)&&(e=this._toolbars[s].addToolbar(t),o||(L.DomUtil.hasClass(e,a)||L.DomUtil.addClass(e.childNodes[0],a),o=!0),i.appendChild(e));return i},onRemove:function(){for(var t in this._toolbars)this._toolbars.hasOwnProperty(t)&&this._toolbars[t].removeToolbar()},setDrawingOptions:function(t){for(var e in this._toolbars)this._toolbars[e]instanceof L.DrawToolbar&&this._toolbars[e].setOptions(t)},_toolbarEnabled:function(t){var e=""+L.stamp(t.target);for(var i in this._toolbars)this._toolbars.hasOwnProperty(i)&&i!==e&&this._toolbars[i].disable()}}),L.Map.mergeOptions({drawControlTooltips:!0,drawControl:!1}),L.Map.addInitHook(function(){this.options.drawControl&&(this.drawControl=new L.Control.Draw,this.addControl(this.drawControl))}),L.Toolbar=L.Class.extend({includes:[L.Mixin.Events],initialize:function(t){L.setOptions(this,t),this._modes={},this._actionButtons=[],this._activeMode=null},enabled:function(){return null!==this._activeMode},disable:function(){this.enabled()&&this._activeMode.handler.disable()},removeToolbar:function(){for(var t in this._modes)this._modes.hasOwnProperty(t)&&(this._disposeButton(this._modes[t].button,this._modes[t].handler.enable),this._modes[t].handler.disable(),this._modes[t].handler.off("enabled",this._handlerActivated,this).off("disabled",this._handlerDeactivated,this));this._modes={};for(var e=0,i=this._actionButtons.length;i>e;e++)this._disposeButton(this._actionButtons[e].button,this._actionButtons[e].callback);this._actionButtons=[],this._actionsContainer=null},_initModeHandler:function(t,e,i,o,a){var s=t.type;this._modes[s]={},this._modes[s].handler=t,this._modes[s].button=this._createButton({title:a,className:o+"-"+s,container:e,callback:this._modes[s].handler.enable,context:this._modes[s].handler}),this._modes[s].buttonIndex=i,this._modes[s].handler.on("enabled",this._handlerActivated,this).on("disabled",this._handlerDeactivated,this)},_createButton:function(t){var e=L.DomUtil.create("a",t.className||"",t.container);return e.href="#",t.text&&(e.innerHTML=t.text),t.title&&(e.title=t.title),L.DomEvent.on(e,"click",L.DomEvent.stopPropagation).on(e,"mousedown",L.DomEvent.stopPropagation).on(e,"dblclick",L.DomEvent.stopPropagation).on(e,"click",L.DomEvent.preventDefault).on(e,"click",t.callback,t.context),e},_disposeButton:function(t,e){L.DomEvent.off(t,"click",L.DomEvent.stopPropagation).off(t,"mousedown",L.DomEvent.stopPropagation).off(t,"dblclick",L.DomEvent.stopPropagation).off(t,"click",L.DomEvent.preventDefault).off(t,"click",e)},_handlerActivated:function(t){this._activeMode&&this._activeMode.handler.enabled()&&this._activeMode.handler.disable(),this._activeMode=this._modes[t.handler],L.DomUtil.addClass(this._activeMode.button,"leaflet-draw-toolbar-button-enabled"),this._showActionsToolbar(),this.fire("enable")},_handlerDeactivated:function(){this._hideActionsToolbar(),L.DomUtil.removeClass(this._activeMode.button,"leaflet-draw-toolbar-button-enabled"),this._activeMode=null,this.fire("disable")},_createActions:function(t){for(var e,i,o=L.DomUtil.create("ul","leaflet-draw-actions"),a=t.length,s=0;a>s;s++)e=L.DomUtil.create("li","",o),i=this._createButton({title:t[s].title,text:t[s].text,container:e,callback:t[s].callback,context:t[s].context}),this._actionButtons.push({button:i,callback:t[s].callback});return o},_showActionsToolbar:function(){var t=this._activeMode.buttonIndex,e=this._lastButtonIndex,i=26,o=1,a=t*i+t*o-1;this._actionsContainer.style.top=a+"px",0===t&&(L.DomUtil.addClass(this._toolbarContainer,"leaflet-draw-toolbar-notop"),L.DomUtil.addClass(this._actionsContainer,"leaflet-draw-actions-top")),t===e&&(L.DomUtil.addClass(this._toolbarContainer,"leaflet-draw-toolbar-nobottom"),L.DomUtil.addClass(this._actionsContainer,"leaflet-draw-actions-bottom")),this._actionsContainer.style.display="block"},_hideActionsToolbar:function(){this._actionsContainer.style.display="none",L.DomUtil.removeClass(this._toolbarContainer,"leaflet-draw-toolbar-notop"),L.DomUtil.removeClass(this._toolbarContainer,"leaflet-draw-toolbar-nobottom"),L.DomUtil.removeClass(this._actionsContainer,"leaflet-draw-actions-top"),L.DomUtil.removeClass(this._actionsContainer,"leaflet-draw-actions-bottom")}}),L.Tooltip=L.Class.extend({initialize:function(t){this._map=t,this._popupPane=t._panes.popupPane,this._container=t.options.drawControlTooltips?L.DomUtil.create("div","leaflet-draw-tooltip",this._popupPane):null,this._singleLineLabel=!1},dispose:function(){this._container&&(this._popupPane.removeChild(this._container),this._container=null)},updateContent:function(t){return this._container?(t.subtext=t.subtext||"",0!==t.subtext.length||this._singleLineLabel?t.subtext.length>0&&this._singleLineLabel&&(L.DomUtil.removeClass(this._container,"leaflet-draw-tooltip-single"),this._singleLineLabel=!1):(L.DomUtil.addClass(this._container,"leaflet-draw-tooltip-single"),this._singleLineLabel=!0),this._container.innerHTML=(t.subtext.length>0?'<span class="leaflet-draw-tooltip-subtext">'+t.subtext+"</span>"+"<br />":"")+"<span>"+t.text+"</span>",this):this},updatePosition:function(t){var e=this._map.latLngToLayerPoint(t),i=this._container;return this._container&&(i.style.visibility="inherit",L.DomUtil.setPosition(i,e)),this},showAsError:function(){return this._container&&L.DomUtil.addClass(this._container,"leaflet-error-draw-tooltip"),this},removeError:function(){return this._container&&L.DomUtil.removeClass(this._container,"leaflet-error-draw-tooltip"),this}}),L.DrawToolbar=L.Toolbar.extend({options:{polyline:{},polygon:{},rectangle:{},circle:{},marker:{}},initialize:function(t){for(var e in this.options)this.options.hasOwnProperty(e)&&t[e]&&(t[e]=L.extend({},this.options[e],t[e]));
10
+ L.Toolbar.prototype.initialize.call(this,t)},addToolbar:function(t){var e=L.DomUtil.create("div","leaflet-draw-section"),i=0,o="leaflet-draw-draw";return this._toolbarContainer=L.DomUtil.create("div","leaflet-draw-toolbar leaflet-bar"),this.options.polyline&&this._initModeHandler(new L.Draw.Polyline(t,this.options.polyline),this._toolbarContainer,i++,o,L.drawLocal.draw.toolbar.buttons.polyline),this.options.polygon&&this._initModeHandler(new L.Draw.Polygon(t,this.options.polygon),this._toolbarContainer,i++,o,L.drawLocal.draw.toolbar.buttons.polygon),this.options.rectangle&&this._initModeHandler(new L.Draw.Rectangle(t,this.options.rectangle),this._toolbarContainer,i++,o,L.drawLocal.draw.toolbar.buttons.rectangle),this.options.circle&&this._initModeHandler(new L.Draw.Circle(t,this.options.circle),this._toolbarContainer,i++,o,L.drawLocal.draw.toolbar.buttons.circle),this.options.marker&&this._initModeHandler(new L.Draw.Marker(t,this.options.marker),this._toolbarContainer,i++,o,L.drawLocal.draw.toolbar.buttons.marker),this._lastButtonIndex=--i,this._actionsContainer=this._createActions([{title:L.drawLocal.draw.toolbar.actions.title,text:L.drawLocal.draw.toolbar.actions.text,callback:this.disable,context:this}]),e.appendChild(this._toolbarContainer),e.appendChild(this._actionsContainer),e},setOptions:function(t){L.setOptions(this,t);for(var e in this._modes)this._modes.hasOwnProperty(e)&&t.hasOwnProperty(e)&&this._modes[e].handler.setOptions(t[e])}}),L.EditToolbar=L.Toolbar.extend({options:{edit:{selectedPathOptions:{color:"#fe57a1",opacity:.6,dashArray:"10, 10",fill:!0,fillColor:"#fe57a1",fillOpacity:.1}},remove:{},featureGroup:null},initialize:function(t){t.edit&&(t.edit.selectedPathOptions===undefined&&(t.edit.selectedPathOptions=this.options.edit.selectedPathOptions),t.edit=L.extend({},this.options.edit,t.edit)),t.remove&&(t.remove=L.extend({},this.options.remove,t.remove)),L.Toolbar.prototype.initialize.call(this,t),this._selectedFeatureCount=0},addToolbar:function(t){var e=L.DomUtil.create("div","leaflet-draw-section"),i=0,o="leaflet-draw-edit",a=this.options.featureGroup;return this._toolbarContainer=L.DomUtil.create("div","leaflet-draw-toolbar leaflet-bar"),this._map=t,this.options.edit&&this._initModeHandler(new L.EditToolbar.Edit(t,{featureGroup:a,selectedPathOptions:this.options.edit.selectedPathOptions}),this._toolbarContainer,i++,o,L.drawLocal.edit.toolbar.buttons.edit),this.options.remove&&this._initModeHandler(new L.EditToolbar.Delete(t,{featureGroup:a}),this._toolbarContainer,i++,o,L.drawLocal.edit.toolbar.buttons.remove),this._lastButtonIndex=--i,this._actionsContainer=this._createActions([{title:L.drawLocal.edit.toolbar.actions.save.title,text:L.drawLocal.edit.toolbar.actions.save.text,callback:this._save,context:this},{title:L.drawLocal.edit.toolbar.actions.cancel.title,text:L.drawLocal.edit.toolbar.actions.cancel.text,callback:this.disable,context:this}]),e.appendChild(this._toolbarContainer),e.appendChild(this._actionsContainer),this._checkDisabled(),a.on("layeradd layerremove",this._checkDisabled,this),e},removeToolbar:function(){L.Toolbar.prototype.removeToolbar.call(this),this.options.featureGroup.off("layeradd layerremove",this._checkDisabled,this)},disable:function(){this.enabled()&&(this._activeMode.handler.revertLayers(),L.Toolbar.prototype.disable.call(this))},_save:function(){this._activeMode.handler.save(),this._activeMode.handler.disable()},_checkDisabled:function(){var t,e=this.options.featureGroup,i=0!==e.getLayers().length;this.options.edit&&(t=this._modes[L.EditToolbar.Edit.TYPE].button,i?L.DomUtil.removeClass(t,"leaflet-disabled"):L.DomUtil.addClass(t,"leaflet-disabled"),t.setAttribute("title",i?L.drawLocal.edit.toolbar.buttons.edit:L.drawLocal.edit.toolbar.buttons.editDisabled)),this.options.remove&&(t=this._modes[L.EditToolbar.Delete.TYPE].button,i?L.DomUtil.removeClass(t,"leaflet-disabled"):L.DomUtil.addClass(t,"leaflet-disabled"),t.setAttribute("title",i?L.drawLocal.edit.toolbar.buttons.remove:L.drawLocal.edit.toolbar.buttons.removeDisabled))}}),L.EditToolbar.Edit=L.Handler.extend({statics:{TYPE:"edit"},includes:L.Mixin.Events,initialize:function(t,e){if(L.Handler.prototype.initialize.call(this,t),this._selectedPathOptions=e.selectedPathOptions,this._featureGroup=e.featureGroup,!(this._featureGroup instanceof L.FeatureGroup))throw Error("options.featureGroup must be a L.FeatureGroup");this._uneditedLayerProps={},this.type=L.EditToolbar.Edit.TYPE},enable:function(){!this._enabled&&this._hasAvailableLayers()&&(L.Handler.prototype.enable.call(this),this._featureGroup.on("layeradd",this._enableLayerEdit,this).on("layerremove",this._disableLayerEdit,this),this.fire("enabled",{handler:this.type}),this._map.fire("draw:editstart",{handler:this.type}))},disable:function(){this._enabled&&(this.fire("disabled",{handler:this.type}),this._map.fire("draw:editstop",{handler:this.type}),this._featureGroup.off("layeradd",this._enableLayerEdit,this).off("layerremove",this._disableLayerEdit,this),L.Handler.prototype.disable.call(this))},addHooks:function(){var t=this._map;t&&(t.getContainer().focus(),this._featureGroup.eachLayer(this._enableLayerEdit,this),this._tooltip=new L.Tooltip(this._map),this._tooltip.updateContent({text:L.drawLocal.edit.handlers.edit.tooltip.text,subtext:L.drawLocal.edit.handlers.edit.tooltip.subtext}),this._map.on("mousemove",this._onMouseMove,this))},removeHooks:function(){this._map&&(this._featureGroup.eachLayer(this._disableLayerEdit,this),this._uneditedLayerProps={},this._tooltip.dispose(),this._tooltip=null,this._map.off("mousemove",this._onMouseMove,this))},revertLayers:function(){this._featureGroup.eachLayer(function(t){this._revertLayer(t)},this)},save:function(){var t=new L.LayerGroup;this._featureGroup.eachLayer(function(e){e.edited&&(t.addLayer(e),e.edited=!1)}),this._map.fire("draw:edited",{layers:t})},_backupLayer:function(t){var e=L.Util.stamp(t);this._uneditedLayerProps[e]||(this._uneditedLayerProps[e]=t instanceof L.Polyline||t instanceof L.Polygon||t instanceof L.Rectangle?{latlngs:L.LatLngUtil.cloneLatLngs(t.getLatLngs())}:t instanceof L.Circle?{latlng:L.LatLngUtil.cloneLatLng(t.getLatLng()),radius:t.getRadius()}:{latlng:L.LatLngUtil.cloneLatLng(t.getLatLng())})},_revertLayer:function(t){var e=L.Util.stamp(t);t.edited=!1,this._uneditedLayerProps.hasOwnProperty(e)&&(t instanceof L.Polyline||t instanceof L.Polygon||t instanceof L.Rectangle?t.setLatLngs(this._uneditedLayerProps[e].latlngs):t instanceof L.Circle?(t.setLatLng(this._uneditedLayerProps[e].latlng),t.setRadius(this._uneditedLayerProps[e].radius)):t.setLatLng(this._uneditedLayerProps[e].latlng))},_toggleMarkerHighlight:function(t){if(t._icon){var e=t._icon;e.style.display="none",L.DomUtil.hasClass(e,"leaflet-edit-marker-selected")?(L.DomUtil.removeClass(e,"leaflet-edit-marker-selected"),this._offsetMarker(e,-4)):(L.DomUtil.addClass(e,"leaflet-edit-marker-selected"),this._offsetMarker(e,4)),e.style.display=""}},_offsetMarker:function(t,e){var i=parseInt(t.style.marginTop,10)-e,o=parseInt(t.style.marginLeft,10)-e;t.style.marginTop=i+"px",t.style.marginLeft=o+"px"},_enableLayerEdit:function(t){var e,i=t.layer||t.target||t,o=i instanceof L.Marker;(!o||i._icon)&&(this._backupLayer(i),this._selectedPathOptions&&(e=L.Util.extend({},this._selectedPathOptions),o?this._toggleMarkerHighlight(i):(i.options.previousOptions=i.options,i instanceof L.Circle||i instanceof L.Polygon||i instanceof L.Rectangle||(e.fill=!1),i.setStyle(e))),o?(i.dragging.enable(),i.on("dragend",this._onMarkerDragEnd)):i.editing.enable())},_disableLayerEdit:function(t){var e=t.layer||t.target||t;e.edited=!1,this._selectedPathOptions&&(e instanceof L.Marker?this._toggleMarkerHighlight(e):(e.setStyle(e.options.previousOptions),delete e.options.previousOptions)),e instanceof L.Marker?(e.dragging.disable(),e.off("dragend",this._onMarkerDragEnd,this)):e.editing.disable()},_onMarkerDragEnd:function(t){var e=t.target;e.edited=!0},_onMouseMove:function(t){this._tooltip.updatePosition(t.latlng)},_hasAvailableLayers:function(){return 0!==this._featureGroup.getLayers().length}}),L.EditToolbar.Delete=L.Handler.extend({statics:{TYPE:"remove"},includes:L.Mixin.Events,initialize:function(t,e){if(L.Handler.prototype.initialize.call(this,t),L.Util.setOptions(this,e),this._deletableLayers=this.options.featureGroup,!(this._deletableLayers instanceof L.FeatureGroup))throw Error("options.featureGroup must be a L.FeatureGroup");this.type=L.EditToolbar.Delete.TYPE},enable:function(){!this._enabled&&this._hasAvailableLayers()&&(L.Handler.prototype.enable.call(this),this._deletableLayers.on("layeradd",this._enableLayerDelete,this).on("layerremove",this._disableLayerDelete,this),this.fire("enabled",{handler:this.type}),this._map.fire("draw:editstart",{handler:this.type}))},disable:function(){this._enabled&&(L.Handler.prototype.disable.call(this),this._deletableLayers.off("layeradd",this._enableLayerDelete,this).off("layerremove",this._disableLayerDelete,this),this.fire("disabled",{handler:this.type}),this._map.fire("draw:editstop",{handler:this.type}))},addHooks:function(){var t=this._map;t&&(t.getContainer().focus(),this._deletableLayers.eachLayer(this._enableLayerDelete,this),this._deletedLayers=new L.layerGroup,this._tooltip=new L.Tooltip(this._map),this._tooltip.updateContent({text:L.drawLocal.edit.handlers.remove.tooltip.text}),this._map.on("mousemove",this._onMouseMove,this))},removeHooks:function(){this._map&&(this._deletableLayers.eachLayer(this._disableLayerDelete,this),this._deletedLayers=null,this._tooltip.dispose(),this._tooltip=null,this._map.off("mousemove",this._onMouseMove,this))},revertLayers:function(){this._deletedLayers.eachLayer(function(t){this._deletableLayers.addLayer(t)},this)},save:function(){this._map.fire("draw:deleted",{layers:this._deletedLayers})},_enableLayerDelete:function(t){var e=t.layer||t.target||t;e.on("click",this._removeLayer,this)},_disableLayerDelete:function(t){var e=t.layer||t.target||t;e.off("click",this._removeLayer,this),this._deletedLayers.removeLayer(e)},_removeLayer:function(t){var e=t.layer||t.target||t;this._deletableLayers.removeLayer(e),this._deletedLayers.addLayer(e)},_onMouseMove:function(t){this._tooltip.updatePosition(t.latlng)},_hasAvailableLayers:function(){return 0!==this._deletableLayers.getLayers().length}})})(this,document);
@@ -4,7 +4,6 @@
4
4
  <title>Leaflet.draw drawing and editing tools</title>
5
5
 
6
6
  <link rel="stylesheet" href="libs/leaflet.css" />
7
- <!--[if lte IE 8]><link rel="stylesheet" href="libs/leaflet.ie.css" /><![endif]-->
8
7
  <link rel="stylesheet" href="../dist/leaflet.draw.css" />
9
8
  <!--[if lte IE 8]><link rel="stylesheet" href="../dist/leaflet.draw.ie.css" /><![endif]-->
10
9
 
@@ -26,9 +25,10 @@
26
25
  <script src="../src/draw/handler/Draw.Marker.js"></script>
27
26
 
28
27
  <script src="../src/ext/LatLngUtil.js"></script>
28
+ <script src="../src/ext/GeometryUtil.js"></script>
29
29
  <script src="../src/ext/LineUtil.Intersect.js"></script>
30
- <script src="../src/ext/Polygon.Intersect.js"></script>
31
30
  <script src="../src/ext/Polyline.Intersect.js"></script>
31
+ <script src="../src/ext/Polygon.Intersect.js"></script>
32
32
 
33
33
  <script src="../src/Control.Draw.js"></script>
34
34
  <script src="../src/Tooltip.js"></script>
@@ -43,7 +43,6 @@
43
43
  <div id="map" style="width: 800px; height: 600px; border: 1px solid #ccc"></div>
44
44
  <button id="changeColor">Rectangle -> Blue</button>
45
45
  <script>
46
-
47
46
  var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png',
48
47
  cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18}),
49
48
  map = new L.Map('map', {layers: [cloudmade], center: new L.LatLng(-37.7772, 175.2756), zoom: 15 });
@@ -51,12 +50,18 @@
51
50
  var drawnItems = new L.FeatureGroup();
52
51
  map.addLayer(drawnItems);
53
52
 
53
+ // Set the title to show on the polygon button
54
+ L.drawLocal.draw.toolbar.buttons.polygon = 'Draw a sexy polygon!';
55
+
54
56
  var drawControl = new L.Control.Draw({
57
+ position: 'topright',
55
58
  draw: {
56
- position: 'topleft',
59
+ polyline: {
60
+ metric: true
61
+ },
57
62
  polygon: {
58
- title: 'Draw a sexy polygon!',
59
63
  allowIntersection: false,
64
+ showArea: true,
60
65
  drawError: {
61
66
  color: '#b00b00',
62
67
  timeout: 1000
@@ -69,10 +74,12 @@
69
74
  shapeOptions: {
70
75
  color: '#662d91'
71
76
  }
72
- }
77
+ },
78
+ marker: false
73
79
  },
74
80
  edit: {
75
- featureGroup: drawnItems
81
+ featureGroup: drawnItems,
82
+ remove: false
76
83
  }
77
84
  });
78
85
  map.addControl(drawControl);
@@ -1,12 +1,13 @@
1
1
  /*
2
2
  Leaflet, a JavaScript library for mobile-friendly interactive maps. http://leafletjs.com
3
- (c) 2010-2013, Vladimir Agafonkin, CloudMade
3
+ (c) 2010-2013, Vladimir Agafonkin
4
+ (c) 2010-2011, CloudMade
4
5
  */
5
6
  (function (window, document, undefined) {
6
7
  var oldL = window.L,
7
8
  L = {};
8
9
 
9
- L.version = '0.6-dev';
10
+ L.version = '0.7-dev';
10
11
 
11
12
  // define Leaflet for Node module pattern loaders, including Browserify
12
13
  if (typeof module === 'object' && typeof module.exports === 'object') {
@@ -14,7 +15,7 @@ if (typeof module === 'object' && typeof module.exports === 'object') {
14
15
 
15
16
  // define Leaflet as an AMD module
16
17
  } else if (typeof define === 'function' && define.amd) {
17
- define('leaflet', [], function () { return L; });
18
+ define(L);
18
19
  }
19
20
 
20
21
  // define Leaflet as a global L variable, saving the original L to restore later if needed
@@ -55,8 +56,9 @@ L.Util = {
55
56
  },
56
57
 
57
58
  stamp: (function () {
58
- var lastId = 0, key = '_leaflet_id';
59
- return function (/*Object*/ obj) {
59
+ var lastId = 0,
60
+ key = '_leaflet_id';
61
+ return function (obj) {
60
62
  obj[key] = obj[key] || ++lastId;
61
63
  return obj[key];
62
64
  };
@@ -125,27 +127,31 @@ L.Util = {
125
127
  return obj.options;
126
128
  },
127
129
 
128
- getParamString: function (obj, existingUrl) {
130
+ getParamString: function (obj, existingUrl, uppercase) {
129
131
  var params = [];
130
132
  for (var i in obj) {
131
- params.push(encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]));
133
+ params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));
132
134
  }
133
135
  return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
134
136
  },
135
137
 
136
- template: function (str, data) {
137
- return str.replace(/\{ *([\w_]+) *\}/g, function (str, key) {
138
- var value = data[key];
139
- if (value === undefined) {
140
- throw new Error('No value provided for variable ' + str);
141
- } else if (typeof value === 'function') {
142
- value = value(data);
143
- }
144
- return value;
138
+ compileTemplate: function (str, data) {
139
+ // based on https://gist.github.com/padolsey/6008842
140
+ str = str.replace(/"/g, '\\\"');
141
+ str = str.replace(/\{ *([\w_]+) *\}/g, function (str, key) {
142
+ return '" + o["' + key + '"]' + (typeof data[key] === 'function' ? '(o)' : '') + ' + "';
145
143
  });
144
+ // jshint evil: true
145
+ return new Function('o', 'return "' + str + '";');
146
+ },
147
+
148
+ template: function (str, data) {
149
+ var cache = L.Util._templateCache = L.Util._templateCache || {};
150
+ cache[str] = cache[str] || L.Util.compileTemplate(str, data);
151
+ return cache[str](data);
146
152
  },
147
153
 
148
- isArray: function (obj) {
154
+ isArray: Array.isArray || function (obj) {
149
155
  return (Object.prototype.toString.call(obj) === '[object Array]');
150
156
  },
151
157
 
@@ -352,8 +358,8 @@ L.Mixin.Events = {
352
358
  // store listeners of a particular context in a separate hash (if it has an id)
353
359
  // gives a major performance boost when removing thousands of map layers
354
360
 
355
- indexKey = type + '_idx',
356
- indexLenKey = indexKey + '_len',
361
+ indexKey = type + '_idx';
362
+ indexLenKey = indexKey + '_len';
357
363
 
358
364
  typeIndex = events[indexKey] = events[indexKey] || {};
359
365
 
@@ -384,6 +390,10 @@ L.Mixin.Events = {
384
390
 
385
391
  removeEventListener: function (types, fn, context) { // ([String, Function, Object]) or (Object[, Object])
386
392
 
393
+ if (!this[eventsKey]) {
394
+ return this;
395
+ }
396
+
387
397
  if (!types) {
388
398
  return this.clearAllEventListeners();
389
399
  }
@@ -392,7 +402,7 @@ L.Mixin.Events = {
392
402
 
393
403
  var events = this[eventsKey],
394
404
  contextId = context && L.stamp(context),
395
- i, len, type, listeners, j, indexKey, indexLenKey, typeIndex;
405
+ i, len, type, listeners, j, indexKey, indexLenKey, typeIndex, removed;
396
406
 
397
407
  types = L.Util.splitWords(types);
398
408
 
@@ -414,7 +424,10 @@ L.Mixin.Events = {
414
424
  if (listeners) {
415
425
  for (j = listeners.length - 1; j >= 0; j--) {
416
426
  if ((listeners[j].action === fn) && (!context || (listeners[j].context === context))) {
417
- listeners.splice(j, 1);
427
+ removed = listeners.splice(j, 1);
428
+ // set the old action to a no-op, because it is possible
429
+ // that the listener is being iterated over as part of a dispatch
430
+ removed[0].action = L.Util.falseFn;
418
431
  }
419
432
  }
420
433
 
@@ -457,7 +470,7 @@ L.Mixin.Events = {
457
470
  typeIndex = events[type + '_idx'];
458
471
 
459
472
  for (contextId in typeIndex) {
460
- listeners = typeIndex[contextId];
473
+ listeners = typeIndex[contextId].slice();
461
474
 
462
475
  if (listeners) {
463
476
  for (i = 0, len = listeners.length; i < len; i++) {
@@ -497,7 +510,7 @@ L.Mixin.Events.fire = L.Mixin.Events.fireEvent;
497
510
 
498
511
  (function () {
499
512
 
500
- var ie = !!window.ActiveXObject,
513
+ var ie = 'ActiveXObject' in window,
501
514
  ie6 = ie && !window.XMLHttpRequest,
502
515
  ie7 = ie && !document.querySelector,
503
516
  ielt9 = ie && !document.addEventListener,
@@ -509,10 +522,13 @@ L.Mixin.Events.fire = L.Mixin.Events.fireEvent;
509
522
  phantomjs = ua.indexOf('phantom') !== -1,
510
523
  android = ua.indexOf('android') !== -1,
511
524
  android23 = ua.search('android [23]') !== -1,
525
+ gecko = ua.indexOf('gecko') !== -1,
512
526
 
513
527
  mobile = typeof orientation !== undefined + '',
514
- msTouch = window.navigator && window.navigator.msPointerEnabled &&
515
- window.navigator.msMaxTouchPoints,
528
+ msPointer = window.navigator && window.navigator.msPointerEnabled &&
529
+ window.navigator.msMaxTouchPoints && !window.PointerEvent,
530
+ pointer = (window.PointerEvent && window.navigator.pointerEnabled && window.navigator.maxTouchPoints) ||
531
+ msPointer,
516
532
  retina = ('devicePixelRatio' in window && window.devicePixelRatio > 1) ||
517
533
  ('matchMedia' in window && window.matchMedia('(min-resolution:144dpi)') &&
518
534
  window.matchMedia('(min-resolution:144dpi)').matches),
@@ -532,8 +548,8 @@ L.Mixin.Events.fire = L.Mixin.Events.fireEvent;
532
548
 
533
549
  var startName = 'ontouchstart';
534
550
 
535
- // IE10+ (We simulate these into touch* events in L.DomEvent and L.DomEvent.MsTouch) or WebKit, etc.
536
- if (msTouch || (startName in doc)) {
551
+ // IE10+ (We simulate these into touch* events in L.DomEvent and L.DomEvent.Pointer) or WebKit, etc.
552
+ if (pointer || (startName in doc)) {
537
553
  return true;
538
554
  }
539
555
 
@@ -563,6 +579,7 @@ L.Mixin.Events.fire = L.Mixin.Events.fireEvent;
563
579
  ie7: ie7,
564
580
  ielt9: ielt9,
565
581
  webkit: webkit,
582
+ gecko: gecko && !webkit && !window.opera && !ie,
566
583
 
567
584
  android: android,
568
585
  android23: android23,
@@ -581,7 +598,8 @@ L.Mixin.Events.fire = L.Mixin.Events.fireEvent;
581
598
  mobileOpera: mobile && window.opera,
582
599
 
583
600
  touch: touch,
584
- msTouch: msTouch,
601
+ msPointer: msPointer,
602
+ pointer: pointer,
585
603
 
586
604
  retina: retina
587
605
  };
@@ -872,8 +890,7 @@ L.DomUtil = {
872
890
  el = element,
873
891
  docBody = document.body,
874
892
  docEl = document.documentElement,
875
- pos,
876
- ie7 = L.Browser.ie7;
893
+ pos;
877
894
 
878
895
  do {
879
896
  top += el.offsetTop || 0;
@@ -892,6 +909,22 @@ L.DomUtil = {
892
909
  left += docBody.scrollLeft || docEl.scrollLeft || 0;
893
910
  break;
894
911
  }
912
+
913
+ if (pos === 'relative' && !el.offsetLeft) {
914
+ var width = L.DomUtil.getStyle(el, 'width'),
915
+ maxWidth = L.DomUtil.getStyle(el, 'max-width'),
916
+ r = el.getBoundingClientRect();
917
+
918
+ if (width !== 'none' || maxWidth !== 'none') {
919
+ left += r.left + el.clientLeft;
920
+ }
921
+
922
+ //calculate full y offset since we're breaking out of the loop
923
+ top += r.top + (docBody.scrollTop || docEl.scrollTop || 0);
924
+
925
+ break;
926
+ }
927
+
895
928
  el = el.offsetParent;
896
929
 
897
930
  } while (el);
@@ -904,19 +937,6 @@ L.DomUtil = {
904
937
  top -= el.scrollTop || 0;
905
938
  left -= el.scrollLeft || 0;
906
939
 
907
- // webkit (and ie <= 7) handles RTL scrollLeft different to everyone else
908
- // https://code.google.com/p/closure-library/source/browse/trunk/closure/goog/style/bidi.js
909
- if (!L.DomUtil.documentIsLtr() && (L.Browser.webkit || ie7)) {
910
- left += el.scrollWidth - el.clientWidth;
911
-
912
- // ie7 shows the scrollbar by default and provides clientWidth counting it, so we
913
- // need to add it back in if it is visible; scrollbar is on the left as we are RTL
914
- if (ie7 && L.DomUtil.getStyle(el, 'overflow-y') !== 'hidden' &&
915
- L.DomUtil.getStyle(el, 'overflow') !== 'hidden') {
916
- left += 17;
917
- }
918
- }
919
-
920
940
  el = el.parentNode;
921
941
  } while (el);
922
942
 
@@ -943,23 +963,6 @@ L.DomUtil = {
943
963
  return el;
944
964
  },
945
965
 
946
- disableTextSelection: function () {
947
- if (document.selection && document.selection.empty) {
948
- document.selection.empty();
949
- }
950
- if (!this._onselectstart) {
951
- this._onselectstart = document.onselectstart || null;
952
- document.onselectstart = L.Util.falseFn;
953
- }
954
- },
955
-
956
- enableTextSelection: function () {
957
- if (document.onselectstart === L.Util.falseFn) {
958
- document.onselectstart = this._onselectstart;
959
- this._onselectstart = null;
960
- }
961
- },
962
-
963
966
  hasClass: function (el, name) {
964
967
  return (el.className.length > 0) &&
965
968
  new RegExp('(^|\\s)' + name + '(\\s|$)').test(el.className);
@@ -1080,6 +1083,38 @@ L.DomUtil.TRANSITION_END =
1080
1083
  L.DomUtil.TRANSITION === 'webkitTransition' || L.DomUtil.TRANSITION === 'OTransition' ?
1081
1084
  L.DomUtil.TRANSITION + 'End' : 'transitionend';
1082
1085
 
1086
+ (function () {
1087
+ var userSelectProperty = L.DomUtil.testProp(
1088
+ ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']);
1089
+
1090
+ L.extend(L.DomUtil, {
1091
+ disableTextSelection: function () {
1092
+ L.DomEvent.on(window, 'selectstart', L.DomEvent.preventDefault);
1093
+ if (userSelectProperty) {
1094
+ var style = document.documentElement.style;
1095
+ this._userSelect = style[userSelectProperty];
1096
+ style[userSelectProperty] = 'none';
1097
+ }
1098
+ },
1099
+
1100
+ enableTextSelection: function () {
1101
+ L.DomEvent.off(window, 'selectstart', L.DomEvent.preventDefault);
1102
+ if (userSelectProperty) {
1103
+ document.documentElement.style[userSelectProperty] = this._userSelect;
1104
+ delete this._userSelect;
1105
+ }
1106
+ },
1107
+
1108
+ disableImageDrag: function () {
1109
+ L.DomEvent.on(window, 'dragstart', L.DomEvent.preventDefault);
1110
+ },
1111
+
1112
+ enableImageDrag: function () {
1113
+ L.DomEvent.off(window, 'dragstart', L.DomEvent.preventDefault);
1114
+ }
1115
+ });
1116
+ })();
1117
+
1083
1118
 
1084
1119
  /*
1085
1120
  * L.LatLng represents a geographical point with latitude and longitude coordinates.
@@ -1158,7 +1193,11 @@ L.latLng = function (a, b) { // (LatLng) or ([Number, Number]) or (Number, Numbe
1158
1193
  return a;
1159
1194
  }
1160
1195
  if (L.Util.isArray(a)) {
1161
- return new L.LatLng(a[0], a[1]);
1196
+ if (typeof a[0] === 'number' || typeof a[0] === 'string') {
1197
+ return new L.LatLng(a[0], a[1]);
1198
+ } else {
1199
+ return null;
1200
+ }
1162
1201
  }
1163
1202
  if (a === undefined || a === null) {
1164
1203
  return a;
@@ -1166,6 +1205,9 @@ L.latLng = function (a, b) { // (LatLng) or ([Number, Number]) or (Number, Numbe
1166
1205
  if (typeof a === 'object' && 'lat' in a) {
1167
1206
  return new L.LatLng(a.lat, 'lng' in a ? a.lng : a.lon);
1168
1207
  }
1208
+ if (b === undefined) {
1209
+ return null;
1210
+ }
1169
1211
  return new L.LatLng(a, b);
1170
1212
  };
1171
1213
 
@@ -1188,8 +1230,11 @@ L.LatLngBounds = function (southWest, northEast) { // (LatLng, LatLng) or (LatLn
1188
1230
  L.LatLngBounds.prototype = {
1189
1231
  // extend the bounds to contain the given point or bounds
1190
1232
  extend: function (obj) { // (LatLng) or (LatLngBounds)
1191
- if (typeof obj[0] === 'number' || typeof obj[0] === 'string' || obj instanceof L.LatLng) {
1192
- obj = L.latLng(obj);
1233
+ if (!obj) { return this; }
1234
+
1235
+ var latLng = L.latLng(obj);
1236
+ if (latLng !== null) {
1237
+ obj = latLng;
1193
1238
  } else {
1194
1239
  obj = L.latLngBounds(obj);
1195
1240
  }
@@ -1480,9 +1525,13 @@ L.Map = L.Class.extend({
1480
1525
  initialize: function (id, options) { // (HTMLElement or String, Object)
1481
1526
  options = L.setOptions(this, options);
1482
1527
 
1528
+
1483
1529
  this._initContainer(id);
1484
1530
  this._initLayout();
1485
- this.callInitHooks();
1531
+
1532
+ // hack for https://github.com/Leaflet/Leaflet/issues/1980
1533
+ this._onResize = L.bind(this._onResize, this);
1534
+
1486
1535
  this._initEvents();
1487
1536
 
1488
1537
  if (options.maxBounds) {
@@ -1490,10 +1539,18 @@ L.Map = L.Class.extend({
1490
1539
  }
1491
1540
 
1492
1541
  if (options.center && options.zoom !== undefined) {
1493
- this.setView(L.latLng(options.center), options.zoom, true);
1542
+ this.setView(L.latLng(options.center), options.zoom, {reset: true});
1494
1543
  }
1495
1544
 
1496
- this._initLayers(options.layers);
1545
+ this._handlers = [];
1546
+
1547
+ this._layers = {};
1548
+ this._zoomBoundLayers = {};
1549
+ this._tileLayersNum = 0;
1550
+
1551
+ this.callInitHooks();
1552
+
1553
+ this._addLayers(options.layers);
1497
1554
  },
1498
1555
 
1499
1556
 
@@ -1501,23 +1558,28 @@ L.Map = L.Class.extend({
1501
1558
 
1502
1559
  // replaced by animation-powered implementation in Map.PanAnimation.js
1503
1560
  setView: function (center, zoom) {
1561
+ zoom = zoom === undefined ? this.getZoom() : zoom;
1504
1562
  this._resetView(L.latLng(center), this._limitZoom(zoom));
1505
1563
  return this;
1506
1564
  },
1507
1565
 
1508
- setZoom: function (zoom) { // (Number)
1509
- return this.setView(this.getCenter(), zoom);
1566
+ setZoom: function (zoom, options) {
1567
+ if (!this._loaded) {
1568
+ this._zoom = this._limitZoom(zoom);
1569
+ return this;
1570
+ }
1571
+ return this.setView(this.getCenter(), zoom, {zoom: options});
1510
1572
  },
1511
1573
 
1512
- zoomIn: function (delta) {
1513
- return this.setZoom(this._zoom + (delta || 1));
1574
+ zoomIn: function (delta, options) {
1575
+ return this.setZoom(this._zoom + (delta || 1), options);
1514
1576
  },
1515
1577
 
1516
- zoomOut: function (delta) {
1517
- return this.setZoom(this._zoom - (delta || 1));
1578
+ zoomOut: function (delta, options) {
1579
+ return this.setZoom(this._zoom - (delta || 1), options);
1518
1580
  },
1519
1581
 
1520
- setZoomAround: function (latlng, zoom) {
1582
+ setZoomAround: function (latlng, zoom, options) {
1521
1583
  var scale = this.getZoomScale(zoom),
1522
1584
  viewHalf = this.getSize().divideBy(2),
1523
1585
  containerPoint = latlng instanceof L.Point ? latlng : this.latLngToContainerPoint(latlng),
@@ -1525,31 +1587,35 @@ L.Map = L.Class.extend({
1525
1587
  centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale),
1526
1588
  newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset));
1527
1589
 
1528
- return this.setView(newCenter, zoom);
1590
+ return this.setView(newCenter, zoom, {zoom: options});
1529
1591
  },
1530
1592
 
1531
- fitBounds: function (bounds, paddingTopLeft, paddingBottomRight) { // (LatLngBounds || ILayer[, Point, Point])
1593
+ fitBounds: function (bounds, options) {
1532
1594
 
1595
+ options = options || {};
1533
1596
  bounds = bounds.getBounds ? bounds.getBounds() : L.latLngBounds(bounds);
1534
1597
 
1535
- paddingTopLeft = L.point(paddingTopLeft || [0, 0]);
1536
- paddingBottomRight = L.point(paddingBottomRight || paddingTopLeft);
1598
+ var paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]),
1599
+ paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]),
1600
+
1601
+ zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR)),
1602
+ paddingOffset = paddingBR.subtract(paddingTL).divideBy(2),
1537
1603
 
1538
- var zoom = this.getBoundsZoom(bounds, false, paddingTopLeft.add(paddingBottomRight)),
1539
- paddingOffset = paddingBottomRight.subtract(paddingTopLeft).divideBy(2),
1540
1604
  swPoint = this.project(bounds.getSouthWest(), zoom),
1541
1605
  nePoint = this.project(bounds.getNorthEast(), zoom),
1542
1606
  center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom);
1543
1607
 
1544
- return this.setView(center, zoom);
1608
+ zoom = options && options.maxZoom ? Math.min(options.maxZoom, zoom) : zoom;
1609
+
1610
+ return this.setView(center, zoom, options);
1545
1611
  },
1546
1612
 
1547
- fitWorld: function () {
1548
- return this.fitBounds([[-90, -180], [90, 180]]);
1613
+ fitWorld: function (options) {
1614
+ return this.fitBounds([[-90, -180], [90, 180]], options);
1549
1615
  },
1550
1616
 
1551
- panTo: function (center) { // (LatLng)
1552
- return this.setView(center, this._zoom);
1617
+ panTo: function (center, options) { // (LatLng)
1618
+ return this.setView(center, this._zoom, {pan: options});
1553
1619
  },
1554
1620
 
1555
1621
  panBy: function (offset) { // (Point)
@@ -1562,13 +1628,14 @@ L.Map = L.Class.extend({
1562
1628
  return this.fire('moveend');
1563
1629
  },
1564
1630
 
1565
- setMaxBounds: function (bounds) {
1631
+ setMaxBounds: function (bounds, options) {
1566
1632
  bounds = L.latLngBounds(bounds);
1567
1633
 
1568
1634
  this.options.maxBounds = bounds;
1569
1635
 
1570
1636
  if (!bounds) {
1571
1637
  this._boundsMinZoom = null;
1638
+ this.off('moveend', this._panInsideMaxBounds, this);
1572
1639
  return this;
1573
1640
  }
1574
1641
 
@@ -1578,7 +1645,7 @@ L.Map = L.Class.extend({
1578
1645
 
1579
1646
  if (this._loaded) {
1580
1647
  if (this._zoom < minZoom) {
1581
- this.setView(bounds.getCenter(), minZoom);
1648
+ this.setView(bounds.getCenter(), minZoom, options);
1582
1649
  } else {
1583
1650
  this.panInsideBounds(bounds);
1584
1651
  }
@@ -1638,14 +1705,13 @@ L.Map = L.Class.extend({
1638
1705
  // TODO looks ugly, refactor!!!
1639
1706
  if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) {
1640
1707
  this._tileLayersNum++;
1641
- this._tileLayersToLoad++;
1642
- layer.on('load', this._onTileLayerLoad, this);
1708
+ this._tileLayersToLoad++;
1709
+ layer.on('load', this._onTileLayerLoad, this);
1643
1710
  }
1644
1711
 
1645
- this.whenReady(function () {
1646
- layer.onAdd(this);
1647
- this.fire('layeradd', {layer: layer});
1648
- }, this);
1712
+ if (this._loaded) {
1713
+ this._layerAdd(layer);
1714
+ }
1649
1715
 
1650
1716
  return this;
1651
1717
  },
@@ -1653,11 +1719,18 @@ L.Map = L.Class.extend({
1653
1719
  removeLayer: function (layer) {
1654
1720
  var id = L.stamp(layer);
1655
1721
 
1656
- if (!this._layers[id]) { return; }
1722
+ if (!this._layers[id]) { return this; }
1657
1723
 
1658
- layer.onRemove(this);
1724
+ if (this._loaded) {
1725
+ layer.onRemove(this);
1726
+ }
1659
1727
 
1660
1728
  delete this._layers[id];
1729
+
1730
+ if (this._loaded) {
1731
+ this.fire('layerremove', {layer: layer});
1732
+ }
1733
+
1661
1734
  if (this._zoomBoundLayers[id]) {
1662
1735
  delete this._zoomBoundLayers[id];
1663
1736
  this._updateZoomLevels();
@@ -1666,11 +1739,11 @@ L.Map = L.Class.extend({
1666
1739
  // TODO looks ugly, refactor
1667
1740
  if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) {
1668
1741
  this._tileLayersNum--;
1669
- this._tileLayersToLoad--;
1670
- layer.off('load', this._onTileLayerLoad, this);
1742
+ this._tileLayersToLoad--;
1743
+ layer.off('load', this._onTileLayerLoad, this);
1671
1744
  }
1672
1745
 
1673
- return this.fire('layerremove', {layer: layer});
1746
+ return this;
1674
1747
  },
1675
1748
 
1676
1749
  hasLayer: function (layer) {
@@ -1686,10 +1759,15 @@ L.Map = L.Class.extend({
1686
1759
  return this;
1687
1760
  },
1688
1761
 
1689
- invalidateSize: function (animate) {
1690
- var oldSize = this.getSize();
1762
+ invalidateSize: function (options) {
1763
+ options = L.extend({
1764
+ animate: false,
1765
+ pan: true
1766
+ }, options === true ? {animate: true} : options);
1691
1767
 
1768
+ var oldSize = this.getSize();
1692
1769
  this._sizeChanged = true;
1770
+ this._initialCenter = null;
1693
1771
 
1694
1772
  if (this.options.maxBounds) {
1695
1773
  this.setMaxBounds(this.options.maxBounds);
@@ -1698,35 +1776,43 @@ L.Map = L.Class.extend({
1698
1776
  if (!this._loaded) { return this; }
1699
1777
 
1700
1778
  var newSize = this.getSize(),
1701
- offset = oldSize.subtract(newSize).divideBy(2).round();
1779
+ oldCenter = oldSize.divideBy(2).round(),
1780
+ newCenter = newSize.divideBy(2).round(),
1781
+ offset = oldCenter.subtract(newCenter);
1702
1782
 
1703
- if ((offset.x !== 0) || (offset.y !== 0)) {
1704
- if (animate === true) {
1705
- this.panBy(offset);
1706
- } else {
1707
- this._rawPanBy(offset);
1783
+ if (!offset.x && !offset.y) { return this; }
1708
1784
 
1709
- this.fire('move');
1785
+ if (options.animate && options.pan) {
1786
+ this.panBy(offset);
1710
1787
 
1711
- clearTimeout(this._sizeTimer);
1712
- this._sizeTimer = setTimeout(L.bind(this.fire, this, 'moveend'), 200);
1788
+ } else {
1789
+ if (options.pan) {
1790
+ this._rawPanBy(offset);
1713
1791
  }
1714
- this.fire('resize', {
1715
- oldSize: oldSize,
1716
- newSize: newSize
1717
- });
1792
+
1793
+ this.fire('move');
1794
+
1795
+ // make sure moveend is not fired too often on resize
1796
+ clearTimeout(this._sizeTimer);
1797
+ this._sizeTimer = setTimeout(L.bind(this.fire, this, 'moveend'), 200);
1718
1798
  }
1719
- return this;
1799
+
1800
+ return this.fire('resize', {
1801
+ oldSize: oldSize,
1802
+ newSize: newSize
1803
+ });
1720
1804
  },
1721
1805
 
1722
1806
  // TODO handler.addTo
1723
1807
  addHandler: function (name, HandlerClass) {
1724
- if (!HandlerClass) { return; }
1808
+ if (!HandlerClass) { return this; }
1725
1809
 
1726
- this[name] = new HandlerClass(this);
1810
+ var handler = this[name] = new HandlerClass(this);
1811
+
1812
+ this._handlers.push(handler);
1727
1813
 
1728
1814
  if (this.options[name]) {
1729
- this[name].enable();
1815
+ handler.enable();
1730
1816
  }
1731
1817
 
1732
1818
  return this;
@@ -1736,8 +1822,23 @@ L.Map = L.Class.extend({
1736
1822
  if (this._loaded) {
1737
1823
  this.fire('unload');
1738
1824
  }
1825
+
1739
1826
  this._initEvents('off');
1740
- delete this._container._leaflet;
1827
+
1828
+ try {
1829
+ // throws error in IE6-8
1830
+ delete this._container._leaflet;
1831
+ } catch (e) {
1832
+ this._container._leaflet = undefined;
1833
+ }
1834
+
1835
+ this._clearPanes();
1836
+ if (this._clearControlPos) {
1837
+ this._clearControlPos();
1838
+ }
1839
+
1840
+ this._clearHandlers();
1841
+
1741
1842
  return this;
1742
1843
  },
1743
1844
 
@@ -1747,7 +1848,7 @@ L.Map = L.Class.extend({
1747
1848
  getCenter: function () { // (Boolean) -> LatLng
1748
1849
  this._checkIfLoaded();
1749
1850
 
1750
- if (!this._moved()) {
1851
+ if (this._initialCenter && !this._moved()) {
1751
1852
  return this._initialCenter;
1752
1853
  }
1753
1854
  return this.layerPointToLatLng(this._getCenterLayerPoint());
@@ -1766,18 +1867,15 @@ L.Map = L.Class.extend({
1766
1867
  },
1767
1868
 
1768
1869
  getMinZoom: function () {
1769
- var z1 = this.options.minZoom || 0,
1770
- z2 = this._layersMinZoom || 0,
1771
- z3 = this._boundsMinZoom || 0;
1772
-
1773
- return Math.max(z1, z2, z3);
1870
+ var z1 = this._layersMinZoom === undefined ? 0 : this._layersMinZoom,
1871
+ z2 = this._boundsMinZoom === undefined ? 0 : this._boundsMinZoom;
1872
+ return this.options.minZoom === undefined ? Math.max(z1, z2) : this.options.minZoom;
1774
1873
  },
1775
1874
 
1776
1875
  getMaxZoom: function () {
1777
- var z1 = this.options.maxZoom === undefined ? Infinity : this.options.maxZoom,
1778
- z2 = this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom;
1779
-
1780
- return Math.min(z1, z2);
1876
+ return this.options.maxZoom === undefined ?
1877
+ (this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom) :
1878
+ this.options.maxZoom;
1781
1879
  },
1782
1880
 
1783
1881
  getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number
@@ -1920,15 +2018,10 @@ L.Map = L.Class.extend({
1920
2018
  _initLayout: function () {
1921
2019
  var container = this._container;
1922
2020
 
1923
- L.DomUtil.addClass(container, 'leaflet-container');
1924
-
1925
- if (L.Browser.touch) {
1926
- L.DomUtil.addClass(container, 'leaflet-touch');
1927
- }
1928
-
1929
- if (this.options.fadeAnimation) {
1930
- L.DomUtil.addClass(container, 'leaflet-fade-anim');
1931
- }
2021
+ L.DomUtil.addClass(container, 'leaflet-container' +
2022
+ (L.Browser.touch ? ' leaflet-touch' : '') +
2023
+ (L.Browser.retina ? ' leaflet-retina' : '') +
2024
+ (this.options.fadeAnimation ? ' leaflet-fade-anim' : ''));
1932
2025
 
1933
2026
  var position = L.DomUtil.getStyle(container, 'position');
1934
2027
 
@@ -1968,16 +2061,14 @@ L.Map = L.Class.extend({
1968
2061
  return L.DomUtil.create('div', className, container || this._panes.objectsPane);
1969
2062
  },
1970
2063
 
1971
- _initLayers: function (layers) {
1972
- layers = layers ? (L.Util.isArray(layers) ? layers : [layers]) : [];
1973
-
1974
- this._layers = {};
1975
- this._zoomBoundLayers = {};
1976
- this._tileLayersNum = 0;
2064
+ _clearPanes: function () {
2065
+ this._container.removeChild(this._mapPane);
2066
+ },
1977
2067
 
1978
- var i, len;
2068
+ _addLayers: function (layers) {
2069
+ layers = layers ? (L.Util.isArray(layers) ? layers : [layers]) : [];
1979
2070
 
1980
- for (i = 0, len = layers.length; i < len; i++) {
2071
+ for (var i = 0, len = layers.length; i < len; i++) {
1981
2072
  this.addLayer(layers[i]);
1982
2073
  }
1983
2074
  },
@@ -2015,6 +2106,7 @@ L.Map = L.Class.extend({
2015
2106
 
2016
2107
  if (loading) {
2017
2108
  this.fire('load');
2109
+ this.eachLayer(this._layerAdd, this);
2018
2110
  }
2019
2111
 
2020
2112
  this.fire('viewreset', {hard: !preserveMapOffset});
@@ -2103,14 +2195,17 @@ L.Map = L.Class.extend({
2103
2195
  },
2104
2196
 
2105
2197
  _onMouseClick: function (e) {
2106
- if (!this._loaded || (this.dragging && this.dragging.moved())) { return; }
2198
+ if (!this._loaded || (!e._simulated &&
2199
+ ((this.dragging && this.dragging.moved()) ||
2200
+ (this.boxZoom && this.boxZoom.moved()))) ||
2201
+ L.DomEvent._skipped(e)) { return; }
2107
2202
 
2108
2203
  this.fire('preclick');
2109
2204
  this._fireMouseEvent(e);
2110
2205
  },
2111
2206
 
2112
2207
  _fireMouseEvent: function (e) {
2113
- if (!this._loaded) { return; }
2208
+ if (!this._loaded || L.DomEvent._skipped(e)) { return; }
2114
2209
 
2115
2210
  var type = e.type;
2116
2211
 
@@ -2141,6 +2236,12 @@ L.Map = L.Class.extend({
2141
2236
  }
2142
2237
  },
2143
2238
 
2239
+ _clearHandlers: function () {
2240
+ for (var i = 0, len = this._handlers.length; i < len; i++) {
2241
+ this._handlers[i].disable();
2242
+ }
2243
+ },
2244
+
2144
2245
  whenReady: function (callback, context) {
2145
2246
  if (this._loaded) {
2146
2247
  callback.call(context || this, this);
@@ -2150,6 +2251,11 @@ L.Map = L.Class.extend({
2150
2251
  return this;
2151
2252
  },
2152
2253
 
2254
+ _layerAdd: function (layer) {
2255
+ layer.onAdd(this);
2256
+ this.fire('layeradd', {layer: layer});
2257
+ },
2258
+
2153
2259
 
2154
2260
  // private methods for getting map state
2155
2261
 
@@ -2208,7 +2314,7 @@ L.map = function (id, options) {
2208
2314
  L.Projection.Mercator = {
2209
2315
  MAX_LATITUDE: 85.0840591556,
2210
2316
 
2211
- R_MINOR: 6356752.3142,
2317
+ R_MINOR: 6356752.314245179,
2212
2318
  R_MAJOR: 6378137,
2213
2319
 
2214
2320
  project: function (latlng) { // (LatLng) -> Point
@@ -2226,7 +2332,7 @@ L.Projection.Mercator = {
2226
2332
  con = Math.pow((1 - con) / (1 + con), eccent * 0.5);
2227
2333
 
2228
2334
  var ts = Math.tan(0.5 * ((Math.PI * 0.5) - y)) / con;
2229
- y = -r2 * Math.log(ts);
2335
+ y = -r * Math.log(ts);
2230
2336
 
2231
2337
  return new L.Point(x, y);
2232
2338
  },
@@ -2238,7 +2344,7 @@ L.Projection.Mercator = {
2238
2344
  lng = point.x * d / r,
2239
2345
  tmp = r2 / r,
2240
2346
  eccent = Math.sqrt(1 - (tmp * tmp)),
2241
- ts = Math.exp(- point.y / r2),
2347
+ ts = Math.exp(- point.y / r),
2242
2348
  phi = (Math.PI / 2) - 2 * Math.atan(ts),
2243
2349
  numIter = 15,
2244
2350
  tol = 1e-7,
@@ -2267,9 +2373,9 @@ L.CRS.EPSG3395 = L.extend({}, L.CRS, {
2267
2373
  transformation: (function () {
2268
2374
  var m = L.Projection.Mercator,
2269
2375
  r = m.R_MAJOR,
2270
- r2 = m.R_MINOR;
2376
+ scale = 0.5 / (Math.PI * r);
2271
2377
 
2272
- return new L.Transformation(0.5 / (Math.PI * r), 0.5, -0.5 / (Math.PI * r2), 0.5);
2378
+ return new L.Transformation(scale, 0.5, -scale, 0.5);
2273
2379
  }())
2274
2380
  });
2275
2381
 
@@ -2290,7 +2396,8 @@ L.TileLayer = L.Class.extend({
2290
2396
  attribution: '',
2291
2397
  zoomOffset: 0,
2292
2398
  opacity: 1,
2293
- /* (undefined works too)
2399
+ /*
2400
+ maxNativeZoom: null,
2294
2401
  zIndex: null,
2295
2402
  tms: false,
2296
2403
  continuousWorld: false,
@@ -2334,14 +2441,11 @@ L.TileLayer = L.Class.extend({
2334
2441
 
2335
2442
  onAdd: function (map) {
2336
2443
  this._map = map;
2337
- this._animated = map.options.zoomAnimation && L.Browser.any3d;
2444
+ this._animated = map._zoomAnimated;
2338
2445
 
2339
2446
  // create a container div for tiles
2340
2447
  this._initContainer();
2341
2448
 
2342
- // create an image to clone for tiles
2343
- this._createTileProto();
2344
-
2345
2449
  // set up events
2346
2450
  map.on({
2347
2451
  'viewreset': this._reset,
@@ -2495,13 +2599,6 @@ L.TileLayer = L.Class.extend({
2495
2599
  } else {
2496
2600
  L.DomUtil.setOpacity(this._container, this.options.opacity);
2497
2601
  }
2498
-
2499
- // stupid webkit hack to force redrawing of tiles
2500
- if (L.Browser.webkit) {
2501
- for (i in tiles) {
2502
- tiles[i].style.webkitTransform += ' translate(0,0)';
2503
- }
2504
- }
2505
2602
  },
2506
2603
 
2507
2604
  _initContainer: function () {
@@ -2513,10 +2610,11 @@ L.TileLayer = L.Class.extend({
2513
2610
  this._updateZIndex();
2514
2611
 
2515
2612
  if (this._animated) {
2516
- var className = 'leaflet-tile-container leaflet-zoom-animated';
2613
+ var className = 'leaflet-tile-container';
2517
2614
 
2518
2615
  this._bgBuffer = L.DomUtil.create('div', className, this._container);
2519
2616
  this._tileContainer = L.DomUtil.create('div', className, this._container);
2617
+
2520
2618
  } else {
2521
2619
  this._tileContainer = this._container;
2522
2620
  }
@@ -2550,13 +2648,27 @@ L.TileLayer = L.Class.extend({
2550
2648
  this._initContainer();
2551
2649
  },
2552
2650
 
2651
+ _getTileSize: function () {
2652
+ var map = this._map,
2653
+ zoom = map.getZoom(),
2654
+ zoomN = this.options.maxNativeZoom,
2655
+ tileSize = this.options.tileSize;
2656
+
2657
+ if (zoomN && zoom > zoomN) {
2658
+ tileSize = Math.round(map.getZoomScale(zoom) / map.getZoomScale(zoomN) * tileSize);
2659
+ }
2660
+
2661
+ return tileSize;
2662
+ },
2663
+
2553
2664
  _update: function () {
2554
2665
 
2555
2666
  if (!this._map) { return; }
2556
2667
 
2557
- var bounds = this._map.getPixelBounds(),
2558
- zoom = this._map.getZoom(),
2559
- tileSize = this.options.tileSize;
2668
+ var map = this._map,
2669
+ bounds = map.getPixelBounds(),
2670
+ zoom = map.getZoom(),
2671
+ tileSize = this._getTileSize();
2560
2672
 
2561
2673
  if (zoom > this.options.maxZoom || zoom < this.options.minZoom) {
2562
2674
  return;
@@ -2621,11 +2733,11 @@ L.TileLayer = L.Class.extend({
2621
2733
 
2622
2734
  var options = this.options;
2623
2735
 
2624
- if (!options.continuousWorld && options.noWrap) {
2736
+ if (!options.continuousWorld) {
2625
2737
  var limit = this._getWrapTileNum();
2626
2738
 
2627
2739
  // don't load if exceeds world bounds
2628
- if (tilePoint.x < 0 || tilePoint.x >= limit ||
2740
+ if ((options.noWrap && (tilePoint.x < 0 || tilePoint.x >= limit)) ||
2629
2741
  tilePoint.y < 0 || tilePoint.y >= limit) { return false; }
2630
2742
  }
2631
2743
 
@@ -2719,12 +2831,14 @@ L.TileLayer = L.Class.extend({
2719
2831
  zoom = options.maxZoom - zoom;
2720
2832
  }
2721
2833
 
2722
- return zoom + options.zoomOffset;
2834
+ zoom += options.zoomOffset;
2835
+
2836
+ return options.maxNativeZoom ? Math.min(zoom, options.maxNativeZoom) : zoom;
2723
2837
  },
2724
2838
 
2725
2839
  _getTilePos: function (tilePoint) {
2726
2840
  var origin = this._map.getPixelOrigin(),
2727
- tileSize = this.options.tileSize;
2841
+ tileSize = this._getTileSize();
2728
2842
 
2729
2843
  return tilePoint.multiplyBy(tileSize).subtract(origin);
2730
2844
  },
@@ -2766,12 +2880,6 @@ L.TileLayer = L.Class.extend({
2766
2880
  return this.options.subdomains[index];
2767
2881
  },
2768
2882
 
2769
- _createTileProto: function () {
2770
- var img = this._tileImg = L.DomUtil.create('img', 'leaflet-tile');
2771
- img.style.width = img.style.height = this.options.tileSize + 'px';
2772
- img.galleryimg = 'no';
2773
- },
2774
-
2775
2883
  _getTile: function () {
2776
2884
  if (this.options.reuseTiles && this._unusedTiles.length > 0) {
2777
2885
  var tile = this._unusedTiles.pop();
@@ -2785,7 +2893,10 @@ L.TileLayer = L.Class.extend({
2785
2893
  _resetTile: function (/*tile*/) {},
2786
2894
 
2787
2895
  _createTile: function () {
2788
- var tile = this._tileImg.cloneNode(false);
2896
+ var tile = L.DomUtil.create('img', 'leaflet-tile');
2897
+ tile.style.width = tile.style.height = this._getTileSize() + 'px';
2898
+ tile.galleryimg = 'no';
2899
+
2789
2900
  tile.onselectstart = tile.onmousemove = L.Util.falseFn;
2790
2901
 
2791
2902
  if (L.Browser.ielt9 && this.options.opacity !== undefined) {
@@ -2801,10 +2912,20 @@ L.TileLayer = L.Class.extend({
2801
2912
 
2802
2913
  this._adjustTilePoint(tilePoint);
2803
2914
  tile.src = this.getTileUrl(tilePoint);
2915
+
2916
+ this.fire('tileloadstart', {
2917
+ tile: tile,
2918
+ url: tile.src
2919
+ });
2804
2920
  },
2805
2921
 
2806
2922
  _tileLoaded: function () {
2807
2923
  this._tilesToLoad--;
2924
+
2925
+ if (this._animated) {
2926
+ L.DomUtil.addClass(this._tileContainer, 'leaflet-zoom-animated');
2927
+ }
2928
+
2808
2929
  if (!this._tilesToLoad) {
2809
2930
  this.fire('load');
2810
2931
 
@@ -2885,7 +3006,7 @@ L.TileLayer.WMS = L.TileLayer.extend({
2885
3006
 
2886
3007
  for (var i in options) {
2887
3008
  // all keys that are not TileLayer options go to WMS params
2888
- if (!this.options.hasOwnProperty(i)) {
3009
+ if (!this.options.hasOwnProperty(i) && i !== 'crs') {
2889
3010
  wmsParams[i] = options[i];
2890
3011
  }
2891
3012
  }
@@ -2897,29 +3018,33 @@ L.TileLayer.WMS = L.TileLayer.extend({
2897
3018
 
2898
3019
  onAdd: function (map) {
2899
3020
 
2900
- var projectionKey = parseFloat(this.wmsParams.version) >= 1.3 ? 'crs' : 'srs';
2901
- this.wmsParams[projectionKey] = map.options.crs.code;
3021
+ this._crs = this.options.crs || map.options.crs;
3022
+
3023
+ this._wmsVersion = parseFloat(this.wmsParams.version);
3024
+
3025
+ var projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs';
3026
+ this.wmsParams[projectionKey] = this._crs.code;
2902
3027
 
2903
3028
  L.TileLayer.prototype.onAdd.call(this, map);
2904
3029
  },
2905
3030
 
2906
- getTileUrl: function (tilePoint, zoom) { // (Point, Number) -> String
3031
+ getTileUrl: function (tilePoint) { // (Point, Number) -> String
2907
3032
 
2908
3033
  var map = this._map,
2909
- crs = map.options.crs,
2910
3034
  tileSize = this.options.tileSize,
2911
3035
 
2912
3036
  nwPoint = tilePoint.multiplyBy(tileSize),
2913
3037
  sePoint = nwPoint.add([tileSize, tileSize]),
2914
3038
 
2915
- nw = crs.project(map.unproject(nwPoint, zoom)),
2916
- se = crs.project(map.unproject(sePoint, zoom)),
2917
-
2918
- bbox = [nw.x, se.y, se.x, nw.y].join(','),
3039
+ nw = this._crs.project(map.unproject(nwPoint, tilePoint.z)),
3040
+ se = this._crs.project(map.unproject(sePoint, tilePoint.z)),
3041
+ bbox = this._wmsVersion >= 1.3 && this._crs === L.CRS.EPSG4326 ?
3042
+ [se.y, nw.x, nw.y, se.x].join(',') :
3043
+ [nw.x, se.y, se.x, nw.y].join(','),
2919
3044
 
2920
3045
  url = L.Util.template(this._url, {s: this._getSubdomain(tilePoint)});
2921
3046
 
2922
- return url + L.Util.getParamString(this.wmsParams, url) + '&bbox=' + bbox;
3047
+ return url + L.Util.getParamString(this.wmsParams, url, true) + '&BBOX=' + bbox;
2923
3048
  },
2924
3049
 
2925
3050
  setParams: function (params, noRedraw) {
@@ -2954,6 +3079,11 @@ L.TileLayer.Canvas = L.TileLayer.extend({
2954
3079
  },
2955
3080
 
2956
3081
  redraw: function () {
3082
+ if (this._map) {
3083
+ this._reset({hard: true});
3084
+ this._update();
3085
+ }
3086
+
2957
3087
  for (var i in this._tiles) {
2958
3088
  this._redrawTile(this._tiles[i]);
2959
3089
  }
@@ -2964,13 +3094,9 @@ L.TileLayer.Canvas = L.TileLayer.extend({
2964
3094
  this.drawTile(tile, tile._tilePoint, this._map._zoom);
2965
3095
  },
2966
3096
 
2967
- _createTileProto: function () {
2968
- var proto = this._canvasProto = L.DomUtil.create('canvas', 'leaflet-tile');
2969
- proto.width = proto.height = this.options.tileSize;
2970
- },
2971
-
2972
3097
  _createTile: function () {
2973
- var tile = this._canvasProto.cloneNode(false);
3098
+ var tile = L.DomUtil.create('canvas', 'leaflet-tile');
3099
+ tile.width = tile.height = this.options.tileSize;
2974
3100
  tile.onselectstart = tile.onmousemove = L.Util.falseFn;
2975
3101
  return tile;
2976
3102
  },
@@ -3074,6 +3200,15 @@ L.ImageOverlay = L.Class.extend({
3074
3200
  return this;
3075
3201
  },
3076
3202
 
3203
+ setUrl: function (url) {
3204
+ this._url = url;
3205
+ this._image.src = this._url;
3206
+ },
3207
+
3208
+ getAttribution: function () {
3209
+ return this.options.attribution;
3210
+ },
3211
+
3077
3212
  _initImage: function () {
3078
3213
  this._image = L.DomUtil.create('img', 'leaflet-image-layer');
3079
3214
 
@@ -3147,7 +3282,7 @@ L.Icon = L.Class.extend({
3147
3282
  iconSize: (Point) (can be set through CSS)
3148
3283
  iconAnchor: (Point) (centered by default, can be set in CSS with negative margins)
3149
3284
  popupAnchor: (Point) (if not specified, popup opens in the anchor point)
3150
- shadowUrl: (Point) (no shadow by default)
3285
+ shadowUrl: (String) (no shadow by default)
3151
3286
  shadowRetinaUrl: (String) (optional, used for retina devices if detected)
3152
3287
  shadowSize: (Point)
3153
3288
  shadowAnchor: (Point)
@@ -3159,15 +3294,15 @@ L.Icon = L.Class.extend({
3159
3294
  L.setOptions(this, options);
3160
3295
  },
3161
3296
 
3162
- createIcon: function () {
3163
- return this._createIcon('icon');
3297
+ createIcon: function (oldIcon) {
3298
+ return this._createIcon('icon', oldIcon);
3164
3299
  },
3165
3300
 
3166
- createShadow: function () {
3167
- return this._createIcon('shadow');
3301
+ createShadow: function (oldIcon) {
3302
+ return this._createIcon('shadow', oldIcon);
3168
3303
  },
3169
3304
 
3170
- _createIcon: function (name) {
3305
+ _createIcon: function (name, oldIcon) {
3171
3306
  var src = this._getIconUrl(name);
3172
3307
 
3173
3308
  if (!src) {
@@ -3177,7 +3312,12 @@ L.Icon = L.Class.extend({
3177
3312
  return null;
3178
3313
  }
3179
3314
 
3180
- var img = this._createImg(src);
3315
+ var img;
3316
+ if (!oldIcon || oldIcon.tagName !== 'IMG') {
3317
+ img = this._createImg(src);
3318
+ } else {
3319
+ img = this._createImg(src, oldIcon);
3320
+ }
3181
3321
  this._setIconStyles(img, name);
3182
3322
 
3183
3323
  return img;
@@ -3211,14 +3351,17 @@ L.Icon = L.Class.extend({
3211
3351
  }
3212
3352
  },
3213
3353
 
3214
- _createImg: function (src) {
3215
- var el;
3354
+ _createImg: function (src, el) {
3216
3355
 
3217
3356
  if (!L.Browser.ie6) {
3218
- el = document.createElement('img');
3357
+ if (!el) {
3358
+ el = document.createElement('img');
3359
+ }
3219
3360
  el.src = src;
3220
3361
  } else {
3221
- el = document.createElement('div');
3362
+ if (!el) {
3363
+ el = document.createElement('div');
3364
+ }
3222
3365
  el.style.filter =
3223
3366
  'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + src + '")';
3224
3367
  }
@@ -3275,7 +3418,7 @@ L.Icon.Default = L.Icon.extend({
3275
3418
 
3276
3419
  L.Icon.Default.imagePath = (function () {
3277
3420
  var scripts = document.getElementsByTagName('script'),
3278
- leafletRe = /\/?leaflet[\-\._]?([\w\-\._]*)\.js\??/;
3421
+ leafletRe = /[\/^]leaflet[\-\._]?([\w\-\._]*)\.js\??/;
3279
3422
 
3280
3423
  var i, len, src, matches, path;
3281
3424
 
@@ -3302,8 +3445,10 @@ L.Marker = L.Class.extend({
3302
3445
  options: {
3303
3446
  icon: new L.Icon.Default(),
3304
3447
  title: '',
3448
+ alt: '',
3305
3449
  clickable: true,
3306
3450
  draggable: false,
3451
+ keyboard: true,
3307
3452
  zIndexOffset: 0,
3308
3453
  opacity: 1,
3309
3454
  riseOnHover: false,
@@ -3322,6 +3467,7 @@ L.Marker = L.Class.extend({
3322
3467
 
3323
3468
  this._initIcon();
3324
3469
  this.update();
3470
+ this.fire('add');
3325
3471
 
3326
3472
  if (map.options.zoomAnimation && map.options.markerZoomAnimation) {
3327
3473
  map.on('zoomanim', this._animateZoom, this);
@@ -3339,6 +3485,7 @@ L.Marker = L.Class.extend({
3339
3485
  }
3340
3486
 
3341
3487
  this._removeIcon();
3488
+ this._removeShadow();
3342
3489
 
3343
3490
  this.fire('remove');
3344
3491
 
@@ -3370,9 +3517,6 @@ L.Marker = L.Class.extend({
3370
3517
  },
3371
3518
 
3372
3519
  setIcon: function (icon) {
3373
- if (this._map) {
3374
- this._removeIcon();
3375
- }
3376
3520
 
3377
3521
  this.options.icon = icon;
3378
3522
 
@@ -3381,6 +3525,10 @@ L.Marker = L.Class.extend({
3381
3525
  this.update();
3382
3526
  }
3383
3527
 
3528
+ if (this._popup) {
3529
+ this.bindPopup(this._popup);
3530
+ }
3531
+
3384
3532
  return this;
3385
3533
  },
3386
3534
 
@@ -3397,66 +3545,90 @@ L.Marker = L.Class.extend({
3397
3545
  var options = this.options,
3398
3546
  map = this._map,
3399
3547
  animation = (map.options.zoomAnimation && map.options.markerZoomAnimation),
3400
- classToAdd = animation ? 'leaflet-zoom-animated' : 'leaflet-zoom-hide',
3401
- needOpacityUpdate = false;
3548
+ classToAdd = animation ? 'leaflet-zoom-animated' : 'leaflet-zoom-hide';
3402
3549
 
3403
- if (!this._icon) {
3404
- this._icon = options.icon.createIcon();
3550
+ var icon = options.icon.createIcon(this._icon),
3551
+ addIcon = false;
3552
+
3553
+ // if we're not reusing the icon, remove the old one and init new one
3554
+ if (icon !== this._icon) {
3555
+ if (this._icon) {
3556
+ this._removeIcon();
3557
+ }
3558
+ addIcon = true;
3405
3559
 
3406
3560
  if (options.title) {
3407
- this._icon.title = options.title;
3561
+ icon.title = options.title;
3408
3562
  }
3563
+
3564
+ if (options.alt) {
3565
+ icon.alt = options.alt;
3566
+ }
3567
+ }
3409
3568
 
3410
- this._initInteraction();
3411
- needOpacityUpdate = (this.options.opacity < 1);
3569
+ L.DomUtil.addClass(icon, classToAdd);
3412
3570
 
3413
- L.DomUtil.addClass(this._icon, classToAdd);
3571
+ if (options.keyboard) {
3572
+ icon.tabIndex = '0';
3573
+ }
3414
3574
 
3415
- if (options.riseOnHover) {
3416
- L.DomEvent
3417
- .on(this._icon, 'mouseover', this._bringToFront, this)
3418
- .on(this._icon, 'mouseout', this._resetZIndex, this);
3419
- }
3575
+ this._icon = icon;
3576
+
3577
+ this._initInteraction();
3578
+
3579
+ if (options.riseOnHover) {
3580
+ L.DomEvent
3581
+ .on(icon, 'mouseover', this._bringToFront, this)
3582
+ .on(icon, 'mouseout', this._resetZIndex, this);
3420
3583
  }
3421
3584
 
3422
- if (!this._shadow) {
3423
- this._shadow = options.icon.createShadow();
3585
+ var newShadow = options.icon.createShadow(this._shadow),
3586
+ addShadow = false;
3424
3587
 
3425
- if (this._shadow) {
3426
- L.DomUtil.addClass(this._shadow, classToAdd);
3427
- needOpacityUpdate = (this.options.opacity < 1);
3428
- }
3588
+ if (newShadow !== this._shadow) {
3589
+ this._removeShadow();
3590
+ addShadow = true;
3591
+ }
3592
+
3593
+ if (newShadow) {
3594
+ L.DomUtil.addClass(newShadow, classToAdd);
3429
3595
  }
3596
+ this._shadow = newShadow;
3597
+
3430
3598
 
3431
- if (needOpacityUpdate) {
3599
+ if (options.opacity < 1) {
3432
3600
  this._updateOpacity();
3433
3601
  }
3434
3602
 
3603
+
3435
3604
  var panes = this._map._panes;
3436
3605
 
3437
- panes.markerPane.appendChild(this._icon);
3606
+ if (addIcon) {
3607
+ panes.markerPane.appendChild(this._icon);
3608
+ }
3438
3609
 
3439
- if (this._shadow) {
3610
+ if (newShadow && addShadow) {
3440
3611
  panes.shadowPane.appendChild(this._shadow);
3441
3612
  }
3442
3613
  },
3443
3614
 
3444
3615
  _removeIcon: function () {
3445
- var panes = this._map._panes;
3446
-
3447
3616
  if (this.options.riseOnHover) {
3448
3617
  L.DomEvent
3449
3618
  .off(this._icon, 'mouseover', this._bringToFront)
3450
3619
  .off(this._icon, 'mouseout', this._resetZIndex);
3451
3620
  }
3452
3621
 
3453
- panes.markerPane.removeChild(this._icon);
3622
+ this._map._panes.markerPane.removeChild(this._icon);
3623
+
3624
+ this._icon = null;
3625
+ },
3454
3626
 
3627
+ _removeShadow: function () {
3455
3628
  if (this._shadow) {
3456
- panes.shadowPane.removeChild(this._shadow);
3629
+ this._map._panes.shadowPane.removeChild(this._shadow);
3457
3630
  }
3458
-
3459
- this._icon = this._shadow = null;
3631
+ this._shadow = null;
3460
3632
  },
3461
3633
 
3462
3634
  _setPos: function (pos) {
@@ -3476,7 +3648,7 @@ L.Marker = L.Class.extend({
3476
3648
  },
3477
3649
 
3478
3650
  _animateZoom: function (opt) {
3479
- var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center);
3651
+ var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();
3480
3652
 
3481
3653
  this._setPos(pos);
3482
3654
  },
@@ -3492,6 +3664,7 @@ L.Marker = L.Class.extend({
3492
3664
 
3493
3665
  L.DomUtil.addClass(icon, 'leaflet-clickable');
3494
3666
  L.DomEvent.on(icon, 'click', this._onMouseClick, this);
3667
+ L.DomEvent.on(icon, 'keypress', this._onKeyPress, this);
3495
3668
 
3496
3669
  for (var i = 0; i < events.length; i++) {
3497
3670
  L.DomEvent.on(icon, events[i], this._fireMouseEvent, this);
@@ -3523,6 +3696,15 @@ L.Marker = L.Class.extend({
3523
3696
  });
3524
3697
  },
3525
3698
 
3699
+ _onKeyPress: function (e) {
3700
+ if (e.keyCode === 13) {
3701
+ this.fire('click', {
3702
+ originalEvent: e,
3703
+ latlng: this._latlng
3704
+ });
3705
+ }
3706
+ },
3707
+
3526
3708
  _fireMouseEvent: function (e) {
3527
3709
 
3528
3710
  this.fire(e.type, {
@@ -3537,6 +3719,8 @@ L.Marker = L.Class.extend({
3537
3719
  }
3538
3720
  if (e.type !== 'mousedown') {
3539
3721
  L.DomEvent.stopPropagation(e);
3722
+ } else {
3723
+ L.DomEvent.preventDefault(e);
3540
3724
  }
3541
3725
  },
3542
3726
 
@@ -3545,6 +3729,8 @@ L.Marker = L.Class.extend({
3545
3729
  if (this._map) {
3546
3730
  this._updateOpacity();
3547
3731
  }
3732
+
3733
+ return this;
3548
3734
  },
3549
3735
 
3550
3736
  _updateOpacity: function () {
@@ -3582,15 +3768,18 @@ L.DivIcon = L.Icon.extend({
3582
3768
  html: (String)
3583
3769
  bgPos: (Point)
3584
3770
  */
3585
- className: 'leaflet-div-icon'
3771
+ className: 'leaflet-div-icon',
3772
+ html: false
3586
3773
  },
3587
3774
 
3588
- createIcon: function () {
3589
- var div = document.createElement('div'),
3775
+ createIcon: function (oldIcon) {
3776
+ var div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'),
3590
3777
  options = this.options;
3591
3778
 
3592
- if (options.html) {
3779
+ if (options.html !== false) {
3593
3780
  div.innerHTML = options.html;
3781
+ } else {
3782
+ div.innerHTML = '';
3594
3783
  }
3595
3784
 
3596
3785
  if (options.bgPos) {
@@ -3626,11 +3815,13 @@ L.Popup = L.Class.extend({
3626
3815
  options: {
3627
3816
  minWidth: 50,
3628
3817
  maxWidth: 300,
3629
- maxHeight: null,
3818
+ // maxHeight: null,
3630
3819
  autoPan: true,
3631
3820
  closeButton: true,
3632
- offset: [0, 6],
3821
+ offset: [0, 7],
3633
3822
  autoPanPadding: [5, 5],
3823
+ // autoPanPaddingTopLeft: null,
3824
+ // autoPanPaddingBottomRight: null,
3634
3825
  keepInView: false,
3635
3826
  className: '',
3636
3827
  zoomAnimation: true
@@ -3641,6 +3832,7 @@ L.Popup = L.Class.extend({
3641
3832
 
3642
3833
  this._source = source;
3643
3834
  this._animated = L.Browser.any3d && this.options.zoomAnimation;
3835
+ this._isOpen = false;
3644
3836
  },
3645
3837
 
3646
3838
  onAdd: function (map) {
@@ -3649,7 +3841,6 @@ L.Popup = L.Class.extend({
3649
3841
  if (!this._container) {
3650
3842
  this._initLayout();
3651
3843
  }
3652
- this._updateContent();
3653
3844
 
3654
3845
  var animFade = map.options.fadeAnimation;
3655
3846
 
@@ -3660,7 +3851,7 @@ L.Popup = L.Class.extend({
3660
3851
 
3661
3852
  map.on(this._getEvents(), this);
3662
3853
 
3663
- this._update();
3854
+ this.update();
3664
3855
 
3665
3856
  if (animFade) {
3666
3857
  L.DomUtil.setOpacity(this._container, 1);
@@ -3707,18 +3898,40 @@ L.Popup = L.Class.extend({
3707
3898
  }
3708
3899
  },
3709
3900
 
3901
+ getLatLng: function () {
3902
+ return this._latlng;
3903
+ },
3904
+
3710
3905
  setLatLng: function (latlng) {
3711
3906
  this._latlng = L.latLng(latlng);
3712
- this._update();
3907
+ this.update();
3713
3908
  return this;
3714
3909
  },
3715
3910
 
3911
+ getContent: function () {
3912
+ return this._content;
3913
+ },
3914
+
3716
3915
  setContent: function (content) {
3717
3916
  this._content = content;
3718
- this._update();
3917
+ this.update();
3719
3918
  return this;
3720
3919
  },
3721
3920
 
3921
+ update: function () {
3922
+ if (!this._map) { return; }
3923
+
3924
+ this._container.style.visibility = 'hidden';
3925
+
3926
+ this._updateContent();
3927
+ this._updateLayout();
3928
+ this._updatePosition();
3929
+
3930
+ this._container.style.visibility = '';
3931
+
3932
+ this._adjustPan();
3933
+ },
3934
+
3722
3935
  _getEvents: function () {
3723
3936
  var events = {
3724
3937
  viewreset: this._updatePosition
@@ -3727,7 +3940,7 @@ L.Popup = L.Class.extend({
3727
3940
  if (this._animated) {
3728
3941
  events.zoomanim = this._zoomAnimation;
3729
3942
  }
3730
- if (this._map.options.closePopupOnClick) {
3943
+ if ('closeOnClick' in this.options ? this.options.closeOnClick : this._map.options.closePopupOnClick) {
3731
3944
  events.preclick = this._close;
3732
3945
  }
3733
3946
  if (this.options.keepInView) {
@@ -3739,7 +3952,7 @@ L.Popup = L.Class.extend({
3739
3952
 
3740
3953
  _close: function () {
3741
3954
  if (this._map) {
3742
- this._map.removeLayer(this);
3955
+ this._map.closePopup(this);
3743
3956
  }
3744
3957
  },
3745
3958
 
@@ -3765,26 +3978,14 @@ L.Popup = L.Class.extend({
3765
3978
  L.DomEvent.disableClickPropagation(wrapper);
3766
3979
 
3767
3980
  this._contentNode = L.DomUtil.create('div', prefix + '-content', wrapper);
3768
- L.DomEvent.on(this._contentNode, 'mousewheel', L.DomEvent.stopPropagation);
3981
+
3982
+ L.DomEvent.disableScrollPropagation(this._contentNode);
3983
+ L.DomEvent.on(wrapper, 'contextmenu', L.DomEvent.stopPropagation);
3769
3984
 
3770
3985
  this._tipContainer = L.DomUtil.create('div', prefix + '-tip-container', container);
3771
3986
  this._tip = L.DomUtil.create('div', prefix + '-tip', this._tipContainer);
3772
3987
  },
3773
3988
 
3774
- _update: function () {
3775
- if (!this._map) { return; }
3776
-
3777
- this._container.style.visibility = 'hidden';
3778
-
3779
- this._updateContent();
3780
- this._updateLayout();
3781
- this._updatePosition();
3782
-
3783
- this._container.style.visibility = '';
3784
-
3785
- this._adjustPan();
3786
- },
3787
-
3788
3989
  _updateContent: function () {
3789
3990
  if (!this._content) { return; }
3790
3991
 
@@ -3869,21 +4070,23 @@ L.Popup = L.Class.extend({
3869
4070
 
3870
4071
  var containerPos = map.layerPointToContainerPoint(layerPos),
3871
4072
  padding = L.point(this.options.autoPanPadding),
4073
+ paddingTL = L.point(this.options.autoPanPaddingTopLeft || padding),
4074
+ paddingBR = L.point(this.options.autoPanPaddingBottomRight || padding),
3872
4075
  size = map.getSize(),
3873
4076
  dx = 0,
3874
4077
  dy = 0;
3875
4078
 
3876
- if (containerPos.x + containerWidth > size.x) { // right
3877
- dx = containerPos.x + containerWidth - size.x + padding.x;
4079
+ if (containerPos.x + containerWidth + paddingBR.x > size.x) { // right
4080
+ dx = containerPos.x + containerWidth - size.x + paddingBR.x;
3878
4081
  }
3879
- if (containerPos.x - dx < 0) { // left
3880
- dx = containerPos.x - padding.x;
4082
+ if (containerPos.x - dx - paddingTL.x < 0) { // left
4083
+ dx = containerPos.x - paddingTL.x;
3881
4084
  }
3882
- if (containerPos.y + containerHeight > size.y) { // bottom
3883
- dy = containerPos.y + containerHeight - size.y + padding.y;
4085
+ if (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom
4086
+ dy = containerPos.y + containerHeight - size.y + paddingBR.y;
3884
4087
  }
3885
- if (containerPos.y - dy < 0) { // top
3886
- dy = containerPos.y - padding.y;
4088
+ if (containerPos.y - dy - paddingTL.y < 0) { // top
4089
+ dy = containerPos.y - paddingTL.y;
3887
4090
  }
3888
4091
 
3889
4092
  if (dx || dy) {
@@ -3915,16 +4118,21 @@ L.Map.include({
3915
4118
  .setLatLng(latlng)
3916
4119
  .setContent(content);
3917
4120
  }
4121
+ popup._isOpen = true;
3918
4122
 
3919
4123
  this._popup = popup;
3920
4124
  return this.addLayer(popup);
3921
4125
  },
3922
4126
 
3923
- closePopup: function () {
3924
- if (this._popup) {
3925
- this.removeLayer(this._popup);
4127
+ closePopup: function (popup) {
4128
+ if (!popup || popup === this._popup) {
4129
+ popup = this._popup;
3926
4130
  this._popup = null;
3927
4131
  }
4132
+ if (popup) {
4133
+ this.removeLayer(popup);
4134
+ popup._isOpen = false;
4135
+ }
3928
4136
  return this;
3929
4137
  }
3930
4138
  });
@@ -3951,22 +4159,34 @@ L.Marker.include({
3951
4159
  return this;
3952
4160
  },
3953
4161
 
3954
- bindPopup: function (content, options) {
3955
- var anchor = L.point(this.options.icon.options.popupAnchor || [0, 0]);
3956
-
3957
- anchor = anchor.add(L.Popup.prototype.options.offset);
3958
-
3959
- if (options && options.offset) {
4162
+ togglePopup: function () {
4163
+ if (this._popup) {
4164
+ if (this._popup._isOpen) {
4165
+ this.closePopup();
4166
+ } else {
4167
+ this.openPopup();
4168
+ }
4169
+ }
4170
+ return this;
4171
+ },
4172
+
4173
+ bindPopup: function (content, options) {
4174
+ var anchor = L.point(this.options.icon.options.popupAnchor || [0, 0]);
4175
+
4176
+ anchor = anchor.add(L.Popup.prototype.options.offset);
4177
+
4178
+ if (options && options.offset) {
3960
4179
  anchor = anchor.add(options.offset);
3961
4180
  }
3962
4181
 
3963
4182
  options = L.extend({offset: anchor}, options);
3964
4183
 
3965
- if (!this._popup) {
4184
+ if (!this._popupHandlersAdded) {
3966
4185
  this
3967
- .on('click', this.openPopup, this)
4186
+ .on('click', this.togglePopup, this)
3968
4187
  .on('remove', this.closePopup, this)
3969
4188
  .on('move', this._movePopup, this);
4189
+ this._popupHandlersAdded = true;
3970
4190
  }
3971
4191
 
3972
4192
  if (content instanceof L.Popup) {
@@ -3991,13 +4211,18 @@ L.Marker.include({
3991
4211
  if (this._popup) {
3992
4212
  this._popup = null;
3993
4213
  this
3994
- .off('click', this.openPopup)
3995
- .off('remove', this.closePopup)
3996
- .off('move', this._movePopup);
4214
+ .off('click', this.togglePopup, this)
4215
+ .off('remove', this.closePopup, this)
4216
+ .off('move', this._movePopup, this);
4217
+ this._popupHandlersAdded = false;
3997
4218
  }
3998
4219
  return this;
3999
4220
  },
4000
4221
 
4222
+ getPopup: function () {
4223
+ return this._popup;
4224
+ },
4225
+
4001
4226
  _movePopup: function (e) {
4002
4227
  this._popup.setLatLng(e.latlng);
4003
4228
  }
@@ -4035,10 +4260,10 @@ L.LayerGroup = L.Class.extend({
4035
4260
  },
4036
4261
 
4037
4262
  removeLayer: function (layer) {
4038
- var id = this.getLayerId(layer);
4263
+ var id = layer in this._layers ? layer : this.getLayerId(layer);
4039
4264
 
4040
4265
  if (this._map && this._layers[id]) {
4041
- this._map.removeLayer(layer);
4266
+ this._map.removeLayer(this._layers[id]);
4042
4267
  }
4043
4268
 
4044
4269
  delete this._layers[id];
@@ -4049,7 +4274,7 @@ L.LayerGroup = L.Class.extend({
4049
4274
  hasLayer: function (layer) {
4050
4275
  if (!layer) { return false; }
4051
4276
 
4052
- return (this.getLayerId(layer) in this._layers);
4277
+ return (layer in this._layers || this.getLayerId(layer) in this._layers);
4053
4278
  },
4054
4279
 
4055
4280
  clearLayers: function () {
@@ -4094,8 +4319,13 @@ L.LayerGroup = L.Class.extend({
4094
4319
  return this;
4095
4320
  },
4096
4321
 
4322
+ getLayer: function (id) {
4323
+ return this._layers[id];
4324
+ },
4325
+
4097
4326
  getLayers: function () {
4098
4327
  var layers = [];
4328
+
4099
4329
  for (var i in this._layers) {
4100
4330
  layers.push(this._layers[i]);
4101
4331
  }
@@ -4125,7 +4355,7 @@ L.FeatureGroup = L.LayerGroup.extend({
4125
4355
  includes: L.Mixin.Events,
4126
4356
 
4127
4357
  statics: {
4128
- EVENTS: 'click dblclick mouseover mouseout mousemove contextmenu'
4358
+ EVENTS: 'click dblclick mouseover mouseout mousemove contextmenu popupopen popupclose'
4129
4359
  },
4130
4360
 
4131
4361
  addLayer: function (layer) {
@@ -4133,7 +4363,9 @@ L.FeatureGroup = L.LayerGroup.extend({
4133
4363
  return this;
4134
4364
  }
4135
4365
 
4136
- layer.on(L.FeatureGroup.EVENTS, this._propagateEvent, this);
4366
+ if ('on' in layer) {
4367
+ layer.on(L.FeatureGroup.EVENTS, this._propagateEvent, this);
4368
+ }
4137
4369
 
4138
4370
  L.LayerGroup.prototype.addLayer.call(this, layer);
4139
4371
 
@@ -4145,6 +4377,13 @@ L.FeatureGroup = L.LayerGroup.extend({
4145
4377
  },
4146
4378
 
4147
4379
  removeLayer: function (layer) {
4380
+ if (!this.hasLayer(layer)) {
4381
+ return this;
4382
+ }
4383
+ if (layer in this._layers) {
4384
+ layer = this._layers[layer];
4385
+ }
4386
+
4148
4387
  layer.off(L.FeatureGroup.EVENTS, this._propagateEvent, this);
4149
4388
 
4150
4389
  L.LayerGroup.prototype.removeLayer.call(this, layer);
@@ -4210,15 +4449,19 @@ L.Path = L.Class.extend({
4210
4449
  // how much to extend the clip area around the map view
4211
4450
  // (relative to its size, e.g. 0.5 is half the screen in each direction)
4212
4451
  // set it so that SVG element doesn't exceed 1280px (vectors flicker on dragend if it is)
4213
- CLIP_PADDING: L.Browser.mobile ?
4214
- Math.max(0, Math.min(0.5,
4215
- (1280 / Math.max(window.innerWidth, window.innerHeight) - 1) / 2)) : 0.5
4452
+ CLIP_PADDING: (function () {
4453
+ var max = L.Browser.mobile ? 1280 : 2000,
4454
+ target = (max / Math.max(window.outerWidth, window.outerHeight) - 1) / 2;
4455
+ return Math.max(0, Math.min(0.5, target));
4456
+ })()
4216
4457
  },
4217
4458
 
4218
4459
  options: {
4219
4460
  stroke: true,
4220
4461
  color: '#0033ff',
4221
4462
  dashArray: null,
4463
+ lineCap: null,
4464
+ lineJoin: null,
4222
4465
  weight: 5,
4223
4466
  opacity: 0.5,
4224
4467
 
@@ -4398,6 +4641,12 @@ L.Path = L.Path.extend({
4398
4641
  } else {
4399
4642
  this._path.removeAttribute('stroke-dasharray');
4400
4643
  }
4644
+ if (this.options.lineCap) {
4645
+ this._path.setAttribute('stroke-linecap', this.options.lineCap);
4646
+ }
4647
+ if (this.options.lineJoin) {
4648
+ this._path.setAttribute('stroke-linejoin', this.options.lineJoin);
4649
+ }
4401
4650
  } else {
4402
4651
  this._path.setAttribute('stroke', 'none');
4403
4652
  }
@@ -4682,12 +4931,18 @@ L.Path = L.Browser.svg || !L.Browser.vml ? L.Path : L.Path.extend({
4682
4931
  stroke.opacity = options.opacity;
4683
4932
 
4684
4933
  if (options.dashArray) {
4685
- stroke.dashStyle = options.dashArray instanceof Array ?
4934
+ stroke.dashStyle = L.Util.isArray(options.dashArray) ?
4686
4935
  options.dashArray.join(' ') :
4687
4936
  options.dashArray.replace(/( *, *)/g, ' ');
4688
4937
  } else {
4689
4938
  stroke.dashStyle = '';
4690
4939
  }
4940
+ if (options.lineCap) {
4941
+ stroke.endcap = options.lineCap.replace('butt', 'flat');
4942
+ }
4943
+ if (options.lineJoin) {
4944
+ stroke.joinstyle = options.lineJoin;
4945
+ }
4691
4946
 
4692
4947
  } else if (stroke) {
4693
4948
  container.removeChild(stroke);
@@ -4771,6 +5026,7 @@ L.Path = (L.Path.SVG && !window.L_PREFER_CANVAS) || !L.Browser.canvas ? L.Path :
4771
5026
 
4772
5027
  if (this.options.clickable) {
4773
5028
  this._map.off('click', this._onClick, this);
5029
+ this._map.off('mousemove', this._onMouseMove, this);
4774
5030
  }
4775
5031
 
4776
5032
  this._requestUpdate();
@@ -5048,8 +5304,8 @@ L.LineUtil = {
5048
5304
  return false;
5049
5305
  // other cases
5050
5306
  } else {
5051
- codeOut = codeA || codeB,
5052
- p = this._getEdgeIntersection(a, b, codeOut, bounds),
5307
+ codeOut = codeA || codeB;
5308
+ p = this._getEdgeIntersection(a, b, codeOut, bounds);
5053
5309
  newCode = this._getBitCode(p, bounds);
5054
5310
 
5055
5311
  if (codeOut === codeA) {
@@ -5366,10 +5622,12 @@ L.Polygon = L.Polyline.extend({
5366
5622
  },
5367
5623
 
5368
5624
  initialize: function (latlngs, options) {
5369
- var i, len, hole;
5370
-
5371
5625
  L.Polyline.prototype.initialize.call(this, latlngs, options);
5626
+ this._initWithHoles(latlngs);
5627
+ },
5372
5628
 
5629
+ _initWithHoles: function (latlngs) {
5630
+ var i, len, hole;
5373
5631
  if (latlngs && L.Util.isArray(latlngs[0]) && (typeof latlngs[0][0] !== 'number')) {
5374
5632
  this._latlngs = this._convertLatLngs(latlngs[0]);
5375
5633
  this._holes = latlngs.slice(1);
@@ -5385,7 +5643,7 @@ L.Polygon = L.Polyline.extend({
5385
5643
  // filter out last point if its equal to the first one
5386
5644
  latlngs = this._latlngs;
5387
5645
 
5388
- if (latlngs[0].equals(latlngs[latlngs.length - 1])) {
5646
+ if (latlngs.length >= 2 && latlngs[0].equals(latlngs[latlngs.length - 1])) {
5389
5647
  latlngs.pop();
5390
5648
  }
5391
5649
  },
@@ -5410,6 +5668,15 @@ L.Polygon = L.Polyline.extend({
5410
5668
  }
5411
5669
  },
5412
5670
 
5671
+ setLatLngs: function (latlngs) {
5672
+ if (latlngs && L.Util.isArray(latlngs[0]) && (typeof latlngs[0][0] !== 'number')) {
5673
+ this._initWithHoles(latlngs);
5674
+ return this.redraw();
5675
+ } else {
5676
+ return L.Polyline.prototype.setLatLngs.call(this, latlngs);
5677
+ }
5678
+ },
5679
+
5413
5680
  _clipPoints: function () {
5414
5681
  var points = this._originalPoints,
5415
5682
  newParts = [];
@@ -5471,6 +5738,16 @@ L.polygon = function (latlngs, options) {
5471
5738
  }
5472
5739
 
5473
5740
  return this;
5741
+ },
5742
+
5743
+ getLatLngs: function () {
5744
+ var latlngs = [];
5745
+
5746
+ this.eachLayer(function (layer) {
5747
+ latlngs.push(layer.getLatLngs());
5748
+ });
5749
+
5750
+ return latlngs;
5474
5751
  }
5475
5752
  });
5476
5753
  }
@@ -5641,9 +5918,20 @@ L.CircleMarker = L.Circle.extend({
5641
5918
  this.setRadius(this.options.radius);
5642
5919
  },
5643
5920
 
5921
+ setLatLng: function (latlng) {
5922
+ L.Circle.prototype.setLatLng.call(this, latlng);
5923
+ if (this._popup && this._popup._isOpen) {
5924
+ this._popup.setLatLng(latlng);
5925
+ }
5926
+ },
5927
+
5644
5928
  setRadius: function (radius) {
5645
5929
  this.options.radius = this._radius = radius;
5646
5930
  return this.redraw();
5931
+ },
5932
+
5933
+ getRadius: function () {
5934
+ return this._radius;
5647
5935
  }
5648
5936
  });
5649
5937
 
@@ -5743,6 +6031,17 @@ L.Circle.include(!L.Path.CANVAS ? {} : {
5743
6031
  });
5744
6032
 
5745
6033
 
6034
+ /*
6035
+ * CircleMarker canvas specific drawing parts.
6036
+ */
6037
+
6038
+ L.CircleMarker.include(!L.Path.CANVAS ? {} : {
6039
+ _updateStyle: function () {
6040
+ L.Path.prototype._updateStyle.call(this);
6041
+ }
6042
+ });
6043
+
6044
+
5746
6045
  /*
5747
6046
  * L.GeoJSON turns any GeoJSON data into a Leaflet layer.
5748
6047
  */
@@ -5761,12 +6060,13 @@ L.GeoJSON = L.FeatureGroup.extend({
5761
6060
 
5762
6061
  addData: function (geojson) {
5763
6062
  var features = L.Util.isArray(geojson) ? geojson : geojson.features,
5764
- i, len;
6063
+ i, len, feature;
5765
6064
 
5766
6065
  if (features) {
5767
6066
  for (i = 0, len = features.length; i < len; i++) {
5768
6067
  // Only add this if geometry or geometries are set and not null
5769
- if (features[i].geometries || features[i].geometry || features[i].features) {
6068
+ feature = features[i];
6069
+ if (feature.geometries || feature.geometry || feature.features || feature.coordinates) {
5770
6070
  this.addData(features[i]);
5771
6071
  }
5772
6072
  }
@@ -5777,8 +6077,8 @@ L.GeoJSON = L.FeatureGroup.extend({
5777
6077
 
5778
6078
  if (options.filter && !options.filter(geojson)) { return; }
5779
6079
 
5780
- var layer = L.GeoJSON.geometryToLayer(geojson, options.pointToLayer, options.coordsToLatLng);
5781
- layer.feature = geojson;
6080
+ var layer = L.GeoJSON.geometryToLayer(geojson, options.pointToLayer, options.coordsToLatLng, options);
6081
+ layer.feature = L.GeoJSON.asFeature(geojson);
5782
6082
 
5783
6083
  layer.defaultOptions = layer.options;
5784
6084
  this.resetStyle(layer);
@@ -5817,11 +6117,11 @@ L.GeoJSON = L.FeatureGroup.extend({
5817
6117
  });
5818
6118
 
5819
6119
  L.extend(L.GeoJSON, {
5820
- geometryToLayer: function (geojson, pointToLayer, coordsToLatLng) {
6120
+ geometryToLayer: function (geojson, pointToLayer, coordsToLatLng, vectorOptions) {
5821
6121
  var geometry = geojson.type === 'Feature' ? geojson.geometry : geojson,
5822
6122
  coords = geometry.coordinates,
5823
6123
  layers = [],
5824
- latlng, latlngs, i, len, layer;
6124
+ latlng, latlngs, i, len;
5825
6125
 
5826
6126
  coordsToLatLng = coordsToLatLng || this.coordsToLatLng;
5827
6127
 
@@ -5833,37 +6133,37 @@ L.extend(L.GeoJSON, {
5833
6133
  case 'MultiPoint':
5834
6134
  for (i = 0, len = coords.length; i < len; i++) {
5835
6135
  latlng = coordsToLatLng(coords[i]);
5836
- layer = pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng);
5837
- layers.push(layer);
6136
+ layers.push(pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng));
5838
6137
  }
5839
6138
  return new L.FeatureGroup(layers);
5840
6139
 
5841
6140
  case 'LineString':
5842
6141
  latlngs = this.coordsToLatLngs(coords, 0, coordsToLatLng);
5843
- return new L.Polyline(latlngs);
6142
+ return new L.Polyline(latlngs, vectorOptions);
5844
6143
 
5845
6144
  case 'Polygon':
6145
+ if (coords.length === 2 && !coords[1].length) {
6146
+ throw new Error('Invalid GeoJSON object.');
6147
+ }
5846
6148
  latlngs = this.coordsToLatLngs(coords, 1, coordsToLatLng);
5847
- return new L.Polygon(latlngs);
6149
+ return new L.Polygon(latlngs, vectorOptions);
5848
6150
 
5849
6151
  case 'MultiLineString':
5850
6152
  latlngs = this.coordsToLatLngs(coords, 1, coordsToLatLng);
5851
- return new L.MultiPolyline(latlngs);
6153
+ return new L.MultiPolyline(latlngs, vectorOptions);
5852
6154
 
5853
6155
  case 'MultiPolygon':
5854
6156
  latlngs = this.coordsToLatLngs(coords, 2, coordsToLatLng);
5855
- return new L.MultiPolygon(latlngs);
6157
+ return new L.MultiPolygon(latlngs, vectorOptions);
5856
6158
 
5857
6159
  case 'GeometryCollection':
5858
6160
  for (i = 0, len = geometry.geometries.length; i < len; i++) {
5859
6161
 
5860
- layer = this.geometryToLayer({
6162
+ layers.push(this.geometryToLayer({
5861
6163
  geometry: geometry.geometries[i],
5862
6164
  type: 'Feature',
5863
6165
  properties: geojson.properties
5864
- }, pointToLayer);
5865
-
5866
- layers.push(layer);
6166
+ }, pointToLayer, coordsToLatLng, vectorOptions));
5867
6167
  }
5868
6168
  return new L.FeatureGroup(layers);
5869
6169
 
@@ -5903,24 +6203,44 @@ L.extend(L.GeoJSON, {
5903
6203
  }
5904
6204
 
5905
6205
  return coords;
6206
+ },
6207
+
6208
+ getFeature: function (layer, newGeometry) {
6209
+ return layer.feature ? L.extend({}, layer.feature, {geometry: newGeometry}) : L.GeoJSON.asFeature(newGeometry);
6210
+ },
6211
+
6212
+ asFeature: function (geoJSON) {
6213
+ if (geoJSON.type === 'Feature') {
6214
+ return geoJSON;
6215
+ }
6216
+
6217
+ return {
6218
+ type: 'Feature',
6219
+ properties: {},
6220
+ geometry: geoJSON
6221
+ };
5906
6222
  }
5907
6223
  });
5908
6224
 
5909
- L.Marker.include({
6225
+ var PointToGeoJSON = {
5910
6226
  toGeoJSON: function () {
5911
- return {
6227
+ return L.GeoJSON.getFeature(this, {
5912
6228
  type: 'Point',
5913
6229
  coordinates: L.GeoJSON.latLngToCoords(this.getLatLng())
5914
- };
6230
+ });
5915
6231
  }
5916
- });
6232
+ };
6233
+
6234
+ L.Marker.include(PointToGeoJSON);
6235
+ L.Circle.include(PointToGeoJSON);
6236
+ L.CircleMarker.include(PointToGeoJSON);
5917
6237
 
5918
6238
  L.Polyline.include({
5919
6239
  toGeoJSON: function () {
5920
- return {
6240
+ return L.GeoJSON.getFeature(this, {
5921
6241
  type: 'LineString',
5922
6242
  coordinates: L.GeoJSON.latLngsToCoords(this.getLatLngs())
5923
- };
6243
+ });
5924
6244
  }
5925
6245
  });
5926
6246
 
@@ -5939,51 +6259,66 @@ L.Polygon.include({
5939
6259
  }
5940
6260
  }
5941
6261
 
5942
- return {
6262
+ return L.GeoJSON.getFeature(this, {
5943
6263
  type: 'Polygon',
5944
6264
  coordinates: coords
5945
- };
6265
+ });
5946
6266
  }
5947
6267
  });
5948
6268
 
5949
6269
  (function () {
5950
- function includeMulti(Klass, type) {
5951
- Klass.include({
5952
- toGeoJSON: function () {
5953
- var coords = [];
6270
+ function multiToGeoJSON(type) {
6271
+ return function () {
6272
+ var coords = [];
5954
6273
 
5955
- this.eachLayer(function (layer) {
5956
- coords.push(layer.toGeoJSON().coordinates);
5957
- });
6274
+ this.eachLayer(function (layer) {
6275
+ coords.push(layer.toGeoJSON().geometry.coordinates);
6276
+ });
5958
6277
 
5959
- return {
5960
- type: type,
5961
- coordinates: coords
5962
- };
5963
- }
5964
- });
6278
+ return L.GeoJSON.getFeature(this, {
6279
+ type: type,
6280
+ coordinates: coords
6281
+ });
6282
+ };
5965
6283
  }
5966
6284
 
5967
- includeMulti(L.MultiPolyline, 'MultiLineString');
5968
- includeMulti(L.MultiPolygon, 'MultiPolygon');
5969
- }());
6285
+ L.MultiPolyline.include({toGeoJSON: multiToGeoJSON('MultiLineString')});
6286
+ L.MultiPolygon.include({toGeoJSON: multiToGeoJSON('MultiPolygon')});
5970
6287
 
5971
- L.LayerGroup.include({
5972
- toGeoJSON: function () {
5973
- var geoms = [];
6288
+ L.LayerGroup.include({
6289
+ toGeoJSON: function () {
5974
6290
 
5975
- this.eachLayer(function (layer) {
5976
- if (layer.toGeoJSON) {
5977
- geoms.push(layer.toGeoJSON());
6291
+ var geometry = this.feature && this.feature.geometry,
6292
+ jsons = [],
6293
+ json;
6294
+
6295
+ if (geometry && geometry.type === 'MultiPoint') {
6296
+ return multiToGeoJSON('MultiPoint').call(this);
5978
6297
  }
5979
- });
5980
6298
 
5981
- return {
5982
- type: 'GeometryCollection',
5983
- geometries: geoms
5984
- };
5985
- }
5986
- });
6299
+ var isGeometryCollection = geometry && geometry.type === 'GeometryCollection';
6300
+
6301
+ this.eachLayer(function (layer) {
6302
+ if (layer.toGeoJSON) {
6303
+ json = layer.toGeoJSON();
6304
+ jsons.push(isGeometryCollection ? json.geometry : L.GeoJSON.asFeature(json));
6305
+ }
6306
+ });
6307
+
6308
+ if (isGeometryCollection) {
6309
+ return L.GeoJSON.getFeature(this, {
6310
+ geometries: jsons,
6311
+ type: 'GeometryCollection'
6312
+ });
6313
+ }
6314
+
6315
+ return {
6316
+ type: 'FeatureCollection',
6317
+ features: jsons
6318
+ };
6319
+ }
6320
+ });
6321
+ }());
5987
6322
 
5988
6323
  L.geoJson = function (geojson, options) {
5989
6324
  return new L.GeoJSON(geojson, options);
@@ -6008,8 +6343,8 @@ L.DomEvent = {
6008
6343
  return fn.call(context || obj, e || L.DomEvent._getEvent());
6009
6344
  };
6010
6345
 
6011
- if (L.Browser.msTouch && type.indexOf('touch') === 0) {
6012
- return this.addMsTouchListener(obj, type, handler, id);
6346
+ if (L.Browser.pointer && type.indexOf('touch') === 0) {
6347
+ return this.addPointerListener(obj, type, handler, id);
6013
6348
  }
6014
6349
  if (L.Browser.touch && (type === 'dblclick') && this.addDoubleTapListener) {
6015
6350
  this.addDoubleTapListener(obj, handler, id);
@@ -6061,8 +6396,8 @@ L.DomEvent = {
6061
6396
 
6062
6397
  if (!handler) { return this; }
6063
6398
 
6064
- if (L.Browser.msTouch && type.indexOf('touch') === 0) {
6065
- this.removeMsTouchListener(obj, type, id);
6399
+ if (L.Browser.pointer && type.indexOf('touch') === 0) {
6400
+ this.removePointerListener(obj, type, id);
6066
6401
  } else if (L.Browser.touch && (type === 'dblclick') && this.removeDoubleTapListener) {
6067
6402
  this.removeDoubleTapListener(obj, id);
6068
6403
 
@@ -6093,20 +6428,29 @@ L.DomEvent = {
6093
6428
  } else {
6094
6429
  e.cancelBubble = true;
6095
6430
  }
6431
+ L.DomEvent._skipped(e);
6432
+
6096
6433
  return this;
6097
6434
  },
6098
6435
 
6099
- disableClickPropagation: function (el) {
6436
+ disableScrollPropagation: function (el) {
6437
+ var stop = L.DomEvent.stopPropagation;
6100
6438
 
6439
+ return L.DomEvent
6440
+ .on(el, 'mousewheel', stop)
6441
+ .on(el, 'MozMousePixelScroll', stop);
6442
+ },
6443
+
6444
+ disableClickPropagation: function (el) {
6101
6445
  var stop = L.DomEvent.stopPropagation;
6102
6446
 
6103
6447
  for (var i = L.Draggable.START.length - 1; i >= 0; i--) {
6104
- L.DomEvent.addListener(el, L.Draggable.START[i], stop);
6448
+ L.DomEvent.on(el, L.Draggable.START[i], stop);
6105
6449
  }
6106
6450
 
6107
6451
  return L.DomEvent
6108
- .addListener(el, 'click', stop)
6109
- .addListener(el, 'dblclick', stop);
6452
+ .on(el, 'click', L.DomEvent._fakeStop)
6453
+ .on(el, 'dblclick', stop);
6110
6454
  },
6111
6455
 
6112
6456
  preventDefault: function (e) {
@@ -6120,18 +6464,32 @@ L.DomEvent = {
6120
6464
  },
6121
6465
 
6122
6466
  stop: function (e) {
6123
- return L.DomEvent.preventDefault(e).stopPropagation(e);
6467
+ return L.DomEvent
6468
+ .preventDefault(e)
6469
+ .stopPropagation(e);
6124
6470
  },
6125
6471
 
6126
6472
  getMousePosition: function (e, container) {
6127
-
6128
6473
  var body = document.body,
6129
6474
  docEl = document.documentElement,
6130
- x = e.pageX ? e.pageX : e.clientX + body.scrollLeft + docEl.scrollLeft,
6131
- y = e.pageY ? e.pageY : e.clientY + body.scrollTop + docEl.scrollTop,
6475
+ //gecko makes scrollLeft more negative as you scroll in rtl, other browsers don't
6476
+ //ref: https://code.google.com/p/closure-library/source/browse/closure/goog/style/bidi.js
6477
+ x = L.DomUtil.documentIsLtr() ?
6478
+ (e.pageX ? e.pageX - body.scrollLeft - docEl.scrollLeft : e.clientX) :
6479
+ (L.Browser.gecko ? e.pageX - body.scrollLeft - docEl.scrollLeft :
6480
+ e.pageX ? e.pageX - body.scrollLeft + docEl.scrollLeft : e.clientX),
6481
+ y = e.pageY ? e.pageY - body.scrollTop - docEl.scrollTop: e.clientY,
6132
6482
  pos = new L.Point(x, y);
6133
6483
 
6134
- return (container ? pos._subtract(L.DomUtil.getViewportOffset(container)) : pos);
6484
+ if (!container) {
6485
+ return pos;
6486
+ }
6487
+
6488
+ var rect = container.getBoundingClientRect(),
6489
+ left = rect.left - container.clientLeft,
6490
+ top = rect.top - container.clientTop;
6491
+
6492
+ return pos._subtract(new L.Point(left, top));
6135
6493
  },
6136
6494
 
6137
6495
  getWheelDelta: function (e) {
@@ -6147,6 +6505,20 @@ L.DomEvent = {
6147
6505
  return delta;
6148
6506
  },
6149
6507
 
6508
+ _skipEvents: {},
6509
+
6510
+ _fakeStop: function (e) {
6511
+ // fakes stopPropagation by setting a special event flag, checked/reset with L.DomEvent._skipped(e)
6512
+ L.DomEvent._skipEvents[e.type] = true;
6513
+ },
6514
+
6515
+ _skipped: function (e) {
6516
+ var skipped = this._skipEvents[e.type];
6517
+ // reset when checking, as it's only used in map container and propagates outside of the map
6518
+ this._skipEvents[e.type] = false;
6519
+ return skipped;
6520
+ },
6521
+
6150
6522
  // check if element really left/entered the event target (for mouseenter/mouseleave)
6151
6523
  _checkMouse: function (el, e) {
6152
6524
 
@@ -6180,16 +6552,17 @@ L.DomEvent = {
6180
6552
  return e;
6181
6553
  },
6182
6554
 
6183
- // this solves a bug in Android WebView where a single touch triggers two click events.
6555
+ // this is a horrible workaround for a bug in Android where a single touch triggers two click events
6184
6556
  _filterClick: function (e, handler) {
6185
- var timeStamp = (e.timeStamp || e.originalEvent.timeStamp);
6186
- var elapsed = L.DomEvent._lastClick && (timeStamp - L.DomEvent._lastClick);
6557
+ var timeStamp = (e.timeStamp || e.originalEvent.timeStamp),
6558
+ elapsed = L.DomEvent._lastClick && (timeStamp - L.DomEvent._lastClick);
6187
6559
 
6188
- // are they closer together than 400ms yet more than 100ms?
6560
+ // are they closer together than 1000ms yet more than 100ms?
6189
6561
  // Android typically triggers them ~300ms apart while multiple listeners
6190
- // on the same event should be triggered far faster.
6562
+ // on the same event should be triggered far faster;
6563
+ // or check if click is simulated on the element, and if it is, reject any non-simulated events
6191
6564
 
6192
- if (elapsed && elapsed > 100 && elapsed < 400) {
6565
+ if ((elapsed && elapsed > 100 && elapsed < 1000) || (e.target._simulatedClick && !e._simulated)) {
6193
6566
  L.DomEvent.stop(e);
6194
6567
  return;
6195
6568
  }
@@ -6215,20 +6588,20 @@ L.Draggable = L.Class.extend({
6215
6588
  END: {
6216
6589
  mousedown: 'mouseup',
6217
6590
  touchstart: 'touchend',
6591
+ pointerdown: 'touchend',
6218
6592
  MSPointerDown: 'touchend'
6219
6593
  },
6220
6594
  MOVE: {
6221
6595
  mousedown: 'mousemove',
6222
6596
  touchstart: 'touchmove',
6597
+ pointerdown: 'touchmove',
6223
6598
  MSPointerDown: 'touchmove'
6224
- },
6225
- TAP_TOLERANCE: 15
6599
+ }
6226
6600
  },
6227
6601
 
6228
- initialize: function (element, dragStartTarget, longPress) {
6602
+ initialize: function (element, dragStartTarget) {
6229
6603
  this._element = element;
6230
6604
  this._dragStartTarget = dragStartTarget || element;
6231
- this._longPress = longPress && !L.Browser.msTouch;
6232
6605
  },
6233
6606
 
6234
6607
  enable: function () {
@@ -6253,61 +6626,34 @@ L.Draggable = L.Class.extend({
6253
6626
  },
6254
6627
 
6255
6628
  _onDown: function (e) {
6629
+ this._moved = false;
6630
+
6256
6631
  if (e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }
6257
6632
 
6258
- L.DomEvent
6259
- .preventDefault(e)
6260
- .stopPropagation(e);
6633
+ L.DomEvent.stopPropagation(e);
6261
6634
 
6262
6635
  if (L.Draggable._disabled) { return; }
6263
6636
 
6264
- this._simulateClick = true;
6265
-
6266
- var touchesNum = (e.touches && e.touches.length) || 0;
6267
-
6268
- // don't simulate click or track longpress if more than 1 touch
6269
- if (touchesNum > 1) {
6270
- this._simulateClick = false;
6271
- clearTimeout(this._longPressTimeout);
6272
- return;
6273
- }
6274
-
6275
- var first = touchesNum === 1 ? e.touches[0] : e,
6276
- el = first.target;
6277
-
6278
- // if touching a link, highlight it
6279
- if (L.Browser.touch && el.tagName.toLowerCase() === 'a') {
6280
- L.DomUtil.addClass(el, 'leaflet-active');
6281
- }
6282
-
6283
- this._moved = false;
6637
+ L.DomUtil.disableImageDrag();
6638
+ L.DomUtil.disableTextSelection();
6284
6639
 
6285
6640
  if (this._moving) { return; }
6286
6641
 
6642
+ var first = e.touches ? e.touches[0] : e;
6643
+
6287
6644
  this._startPoint = new L.Point(first.clientX, first.clientY);
6288
6645
  this._startPos = this._newPos = L.DomUtil.getPosition(this._element);
6289
6646
 
6290
- // touch contextmenu event emulation
6291
- if (touchesNum === 1 && L.Browser.touch && this._longPress) {
6292
-
6293
- this._longPressTimeout = setTimeout(L.bind(function () {
6294
- var dist = (this._newPos && this._newPos.distanceTo(this._startPos)) || 0;
6295
-
6296
- if (dist < L.Draggable.TAP_TOLERANCE) {
6297
- this._simulateClick = false;
6298
- this._onUp();
6299
- this._simulateEvent('contextmenu', first);
6300
- }
6301
- }, this), 1000);
6302
- }
6303
-
6304
6647
  L.DomEvent
6305
6648
  .on(document, L.Draggable.MOVE[e.type], this._onMove, this)
6306
6649
  .on(document, L.Draggable.END[e.type], this._onUp, this);
6307
6650
  },
6308
6651
 
6309
6652
  _onMove: function (e) {
6310
- if (e.touches && e.touches.length > 1) { return; }
6653
+ if (e.touches && e.touches.length > 1) {
6654
+ this._moved = true;
6655
+ return;
6656
+ }
6311
6657
 
6312
6658
  var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),
6313
6659
  newPoint = new L.Point(first.clientX, first.clientY),
@@ -6324,7 +6670,6 @@ L.Draggable = L.Class.extend({
6324
6670
  this._startPos = L.DomUtil.getPosition(this._element).subtract(offset);
6325
6671
 
6326
6672
  if (!L.Browser.touch) {
6327
- L.DomUtil.disableTextSelection();
6328
6673
  L.DomUtil.addClass(document.body, 'leaflet-dragging');
6329
6674
  }
6330
6675
  }
@@ -6342,38 +6687,20 @@ L.Draggable = L.Class.extend({
6342
6687
  this.fire('drag');
6343
6688
  },
6344
6689
 
6345
- _onUp: function (e) {
6346
- var first, el, dist, simulateClickTouch, i;
6347
-
6348
- clearTimeout(this._longPressTimeout);
6349
-
6350
- if (this._simulateClick && e.changedTouches) {
6351
-
6352
- dist = (this._newPos && this._newPos.distanceTo(this._startPos)) || 0;
6353
- first = e.changedTouches[0];
6354
- el = first.target;
6355
-
6356
- if (el.tagName.toLowerCase() === 'a') {
6357
- L.DomUtil.removeClass(el, 'leaflet-active');
6358
- }
6359
-
6360
- // simulate click if the touch didn't move too much
6361
- if (dist < L.Draggable.TAP_TOLERANCE) {
6362
- simulateClickTouch = true;
6363
- }
6364
- }
6365
-
6690
+ _onUp: function () {
6366
6691
  if (!L.Browser.touch) {
6367
- L.DomUtil.enableTextSelection();
6368
6692
  L.DomUtil.removeClass(document.body, 'leaflet-dragging');
6369
6693
  }
6370
6694
 
6371
- for (i in L.Draggable.MOVE) {
6695
+ for (var i in L.Draggable.MOVE) {
6372
6696
  L.DomEvent
6373
6697
  .off(document, L.Draggable.MOVE[i], this._onMove)
6374
6698
  .off(document, L.Draggable.END[i], this._onUp);
6375
6699
  }
6376
6700
 
6701
+ L.DomUtil.enableImageDrag();
6702
+ L.DomUtil.enableTextSelection();
6703
+
6377
6704
  if (this._moved) {
6378
6705
  // ensure drag is not fired after dragend
6379
6706
  L.Util.cancelAnimFrame(this._animRequest);
@@ -6382,23 +6709,6 @@ L.Draggable = L.Class.extend({
6382
6709
  }
6383
6710
 
6384
6711
  this._moving = false;
6385
-
6386
- if (simulateClickTouch) {
6387
- this._moved = false;
6388
- this._simulateEvent('click', first);
6389
- }
6390
- },
6391
-
6392
- _simulateEvent: function (type, e) {
6393
- var simulatedEvent = document.createEvent('MouseEvents');
6394
-
6395
- simulatedEvent.initMouseEvent(
6396
- type, true, true, window, 1,
6397
- e.screenX, e.screenY,
6398
- e.clientX, e.clientY,
6399
- false, false, false, false, 0, null);
6400
-
6401
- e.target.dispatchEvent(simulatedEvent);
6402
6712
  }
6403
6713
  });
6404
6714
 
@@ -6446,8 +6756,6 @@ L.Map.mergeOptions({
6446
6756
  inertiaThreshold: L.Browser.touch ? 32 : 18, // ms
6447
6757
  easeLinearity: 0.25,
6448
6758
 
6449
- longPress: true,
6450
-
6451
6759
  // TODO refactor, move to CRS
6452
6760
  worldCopyJump: false
6453
6761
  });
@@ -6457,7 +6765,7 @@ L.Map.Drag = L.Handler.extend({
6457
6765
  if (!this._draggable) {
6458
6766
  var map = this._map;
6459
6767
 
6460
- this._draggable = new L.Draggable(map._mapPane, map._container, map.options.longPress);
6768
+ this._draggable = new L.Draggable(map._mapPane, map._container);
6461
6769
 
6462
6770
  this._draggable.on({
6463
6771
  'dragstart': this._onDragStart,
@@ -6468,6 +6776,8 @@ L.Map.Drag = L.Handler.extend({
6468
6776
  if (map.options.worldCopyJump) {
6469
6777
  this._draggable.on('predrag', this._onPreDrag, this);
6470
6778
  map.on('viewreset', this._onViewReset, this);
6779
+
6780
+ map.whenReady(this._onViewReset, this);
6471
6781
  }
6472
6782
  }
6473
6783
  this._draggable.enable();
@@ -6571,7 +6881,11 @@ L.Map.Drag = L.Handler.extend({
6571
6881
 
6572
6882
  } else {
6573
6883
  L.Util.requestAnimFrame(function () {
6574
- map.panBy(offset, decelerationDuration, ease, true);
6884
+ map.panBy(offset, {
6885
+ duration: decelerationDuration,
6886
+ easeLinearity: ease,
6887
+ noMoveStart: true
6888
+ });
6575
6889
  });
6576
6890
  }
6577
6891
  }
@@ -6591,15 +6905,22 @@ L.Map.mergeOptions({
6591
6905
 
6592
6906
  L.Map.DoubleClickZoom = L.Handler.extend({
6593
6907
  addHooks: function () {
6594
- this._map.on('dblclick', this._onDoubleClick);
6908
+ this._map.on('dblclick', this._onDoubleClick, this);
6595
6909
  },
6596
6910
 
6597
6911
  removeHooks: function () {
6598
- this._map.off('dblclick', this._onDoubleClick);
6912
+ this._map.off('dblclick', this._onDoubleClick, this);
6599
6913
  },
6600
6914
 
6601
6915
  _onDoubleClick: function (e) {
6602
- this.setZoomAround(e.containerPoint, this._zoom + 1);
6916
+ var map = this._map,
6917
+ zoom = map.getZoom() + 1;
6918
+
6919
+ if (map.options.doubleClickZoom === 'center') {
6920
+ map.setZoom(zoom);
6921
+ } else {
6922
+ map.setZoomAround(e.containerPoint, zoom);
6923
+ }
6603
6924
  }
6604
6925
  });
6605
6926
 
@@ -6617,11 +6938,13 @@ L.Map.mergeOptions({
6617
6938
  L.Map.ScrollWheelZoom = L.Handler.extend({
6618
6939
  addHooks: function () {
6619
6940
  L.DomEvent.on(this._map._container, 'mousewheel', this._onWheelScroll, this);
6941
+ L.DomEvent.on(this._map._container, 'MozMousePixelScroll', L.DomEvent.preventDefault);
6620
6942
  this._delta = 0;
6621
6943
  },
6622
6944
 
6623
6945
  removeHooks: function () {
6624
6946
  L.DomEvent.off(this._map._container, 'mousewheel', this._onWheelScroll);
6947
+ L.DomEvent.off(this._map._container, 'MozMousePixelScroll', L.DomEvent.preventDefault);
6625
6948
  },
6626
6949
 
6627
6950
  _onWheelScroll: function (e) {
@@ -6657,7 +6980,11 @@ L.Map.ScrollWheelZoom = L.Handler.extend({
6657
6980
 
6658
6981
  if (!delta) { return; }
6659
6982
 
6660
- map.setZoomAround(this._lastMousePos, zoom + delta);
6983
+ if (map.options.scrollWheelZoom === 'center') {
6984
+ map.setZoom(zoom + delta);
6985
+ } else {
6986
+ map.setZoomAround(this._lastMousePos, zoom + delta);
6987
+ }
6661
6988
  }
6662
6989
  });
6663
6990
 
@@ -6670,8 +6997,8 @@ L.Map.addInitHook('addHandler', 'scrollWheelZoom', L.Map.ScrollWheelZoom);
6670
6997
 
6671
6998
  L.extend(L.DomEvent, {
6672
6999
 
6673
- _touchstart: L.Browser.msTouch ? 'MSPointerDown' : 'touchstart',
6674
- _touchend: L.Browser.msTouch ? 'MSPointerUp' : 'touchend',
7000
+ _touchstart: L.Browser.msPointer ? 'MSPointerDown' : L.Browser.pointer ? 'pointerdown' : 'touchstart',
7001
+ _touchend: L.Browser.msPointer ? 'MSPointerUp' : L.Browser.pointer ? 'pointerup' : 'touchend',
6675
7002
 
6676
7003
  // inspired by Zepto touch code by Thomas Fuchs
6677
7004
  addDoubleTapListener: function (obj, handler, id) {
@@ -6687,7 +7014,7 @@ L.extend(L.DomEvent, {
6687
7014
  function onTouchStart(e) {
6688
7015
  var count;
6689
7016
 
6690
- if (L.Browser.msTouch) {
7017
+ if (L.Browser.pointer) {
6691
7018
  trackedTouches.push(e.pointerId);
6692
7019
  count = trackedTouches.length;
6693
7020
  } else {
@@ -6706,7 +7033,7 @@ L.extend(L.DomEvent, {
6706
7033
  }
6707
7034
 
6708
7035
  function onTouchEnd(e) {
6709
- if (L.Browser.msTouch) {
7036
+ if (L.Browser.pointer) {
6710
7037
  var idx = trackedTouches.indexOf(e.pointerId);
6711
7038
  if (idx === -1) {
6712
7039
  return;
@@ -6715,7 +7042,7 @@ L.extend(L.DomEvent, {
6715
7042
  }
6716
7043
 
6717
7044
  if (doubleTap) {
6718
- if (L.Browser.msTouch) {
7045
+ if (L.Browser.pointer) {
6719
7046
  // work around .type being readonly with MSPointer* events
6720
7047
  var newTouch = { },
6721
7048
  prop;
@@ -6739,15 +7066,15 @@ L.extend(L.DomEvent, {
6739
7066
  obj[pre + touchstart + id] = onTouchStart;
6740
7067
  obj[pre + touchend + id] = onTouchEnd;
6741
7068
 
6742
- // on msTouch we need to listen on the document, otherwise a drag starting on the map and moving off screen
7069
+ // on pointer we need to listen on the document, otherwise a drag starting on the map and moving off screen
6743
7070
  // will not come through to us, so we will lose track of how many touches are ongoing
6744
- var endElement = L.Browser.msTouch ? document.documentElement : obj;
7071
+ var endElement = L.Browser.pointer ? document.documentElement : obj;
6745
7072
 
6746
7073
  obj.addEventListener(touchstart, onTouchStart, false);
6747
7074
  endElement.addEventListener(touchend, onTouchEnd, false);
6748
7075
 
6749
- if (L.Browser.msTouch) {
6750
- endElement.addEventListener('MSPointerCancel', onTouchEnd, false);
7076
+ if (L.Browser.pointer) {
7077
+ endElement.addEventListener(L.DomEvent.POINTER_CANCEL, onTouchEnd, false);
6751
7078
  }
6752
7079
 
6753
7080
  return this;
@@ -6757,11 +7084,12 @@ L.extend(L.DomEvent, {
6757
7084
  var pre = '_leaflet_';
6758
7085
 
6759
7086
  obj.removeEventListener(this._touchstart, obj[pre + this._touchstart + id], false);
6760
- (L.Browser.msTouch ? document.documentElement : obj).removeEventListener(
7087
+ (L.Browser.pointer ? document.documentElement : obj).removeEventListener(
6761
7088
  this._touchend, obj[pre + this._touchend + id], false);
6762
7089
 
6763
- if (L.Browser.msTouch) {
6764
- document.documentElement.removeEventListener('MSPointerCancel', obj[pre + this._touchend + id], false);
7090
+ if (L.Browser.pointer) {
7091
+ document.documentElement.removeEventListener(L.DomEvent.POINTER_CANCEL, obj[pre + this._touchend + id],
7092
+ false);
6765
7093
  }
6766
7094
 
6767
7095
  return this;
@@ -6775,81 +7103,90 @@ L.extend(L.DomEvent, {
6775
7103
 
6776
7104
  L.extend(L.DomEvent, {
6777
7105
 
6778
- _msTouches: [],
6779
- _msDocumentListener: false,
7106
+ //static
7107
+ POINTER_DOWN: L.Browser.msPointer ? 'MSPointerDown' : 'pointerdown',
7108
+ POINTER_MOVE: L.Browser.msPointer ? 'MSPointerMove' : 'pointermove',
7109
+ POINTER_UP: L.Browser.msPointer ? 'MSPointerUp' : 'pointerup',
7110
+ POINTER_CANCEL: L.Browser.msPointer ? 'MSPointerCancel' : 'pointercancel',
7111
+
7112
+ _pointers: [],
7113
+ _pointerDocumentListener: false,
6780
7114
 
6781
- // Provides a touch events wrapper for msPointer events.
7115
+ // Provides a touch events wrapper for (ms)pointer events.
6782
7116
  // Based on changes by veproza https://github.com/CloudMade/Leaflet/pull/1019
7117
+ //ref http://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890
6783
7118
 
6784
- addMsTouchListener: function (obj, type, handler, id) {
7119
+ addPointerListener: function (obj, type, handler, id) {
6785
7120
 
6786
7121
  switch (type) {
6787
7122
  case 'touchstart':
6788
- return this.addMsTouchListenerStart(obj, type, handler, id);
7123
+ return this.addPointerListenerStart(obj, type, handler, id);
6789
7124
  case 'touchend':
6790
- return this.addMsTouchListenerEnd(obj, type, handler, id);
7125
+ return this.addPointerListenerEnd(obj, type, handler, id);
6791
7126
  case 'touchmove':
6792
- return this.addMsTouchListenerMove(obj, type, handler, id);
7127
+ return this.addPointerListenerMove(obj, type, handler, id);
6793
7128
  default:
6794
7129
  throw 'Unknown touch event type';
6795
7130
  }
6796
7131
  },
6797
7132
 
6798
- addMsTouchListenerStart: function (obj, type, handler, id) {
7133
+ addPointerListenerStart: function (obj, type, handler, id) {
6799
7134
  var pre = '_leaflet_',
6800
- touches = this._msTouches;
7135
+ pointers = this._pointers;
6801
7136
 
6802
7137
  var cb = function (e) {
6803
7138
 
7139
+ L.DomEvent.preventDefault(e);
7140
+
6804
7141
  var alreadyInArray = false;
6805
- for (var i = 0; i < touches.length; i++) {
6806
- if (touches[i].pointerId === e.pointerId) {
7142
+ for (var i = 0; i < pointers.length; i++) {
7143
+ if (pointers[i].pointerId === e.pointerId) {
6807
7144
  alreadyInArray = true;
6808
7145
  break;
6809
7146
  }
6810
7147
  }
6811
7148
  if (!alreadyInArray) {
6812
- touches.push(e);
7149
+ pointers.push(e);
6813
7150
  }
6814
7151
 
6815
- e.touches = touches.slice();
7152
+ e.touches = pointers.slice();
6816
7153
  e.changedTouches = [e];
6817
7154
 
6818
7155
  handler(e);
6819
7156
  };
6820
7157
 
6821
7158
  obj[pre + 'touchstart' + id] = cb;
6822
- obj.addEventListener('MSPointerDown', cb, false);
7159
+ obj.addEventListener(this.POINTER_DOWN, cb, false);
6823
7160
 
6824
- // need to also listen for end events to keep the _msTouches list accurate
7161
+ // need to also listen for end events to keep the _pointers list accurate
6825
7162
  // this needs to be on the body and never go away
6826
- if (!this._msDocumentListener) {
7163
+ if (!this._pointerDocumentListener) {
6827
7164
  var internalCb = function (e) {
6828
- for (var i = 0; i < touches.length; i++) {
6829
- if (touches[i].pointerId === e.pointerId) {
6830
- touches.splice(i, 1);
7165
+ for (var i = 0; i < pointers.length; i++) {
7166
+ if (pointers[i].pointerId === e.pointerId) {
7167
+ pointers.splice(i, 1);
6831
7168
  break;
6832
7169
  }
6833
7170
  }
6834
7171
  };
6835
7172
  //We listen on the documentElement as any drags that end by moving the touch off the screen get fired there
6836
- document.documentElement.addEventListener('MSPointerUp', internalCb, false);
6837
- document.documentElement.addEventListener('MSPointerCancel', internalCb, false);
7173
+ document.documentElement.addEventListener(this.POINTER_UP, internalCb, false);
7174
+ document.documentElement.addEventListener(this.POINTER_CANCEL, internalCb, false);
6838
7175
 
6839
- this._msDocumentListener = true;
7176
+ this._pointerDocumentListener = true;
6840
7177
  }
6841
7178
 
6842
7179
  return this;
6843
7180
  },
6844
7181
 
6845
- addMsTouchListenerMove: function (obj, type, handler, id) {
7182
+ addPointerListenerMove: function (obj, type, handler, id) {
6846
7183
  var pre = '_leaflet_',
6847
- touches = this._msTouches;
7184
+ touches = this._pointers;
6848
7185
 
6849
7186
  function cb(e) {
6850
7187
 
6851
7188
  // don't fire touch moves when mouse isn't down
6852
- if (e.pointerType === e.MSPOINTER_TYPE_MOUSE && e.buttons === 0) { return; }
7189
+ if ((e.pointerType === e.MSPOINTER_TYPE_MOUSE || e.pointerType === 'mouse') && e.buttons === 0) { return; }
6853
7190
 
6854
7191
  for (var i = 0; i < touches.length; i++) {
6855
7192
  if (touches[i].pointerId === e.pointerId) {
@@ -6865,14 +7202,14 @@ L.extend(L.DomEvent, {
6865
7202
  }
6866
7203
 
6867
7204
  obj[pre + 'touchmove' + id] = cb;
6868
- obj.addEventListener('MSPointerMove', cb, false);
7205
+ obj.addEventListener(this.POINTER_MOVE, cb, false);
6869
7206
 
6870
7207
  return this;
6871
7208
  },
6872
7209
 
6873
- addMsTouchListenerEnd: function (obj, type, handler, id) {
7210
+ addPointerListenerEnd: function (obj, type, handler, id) {
6874
7211
  var pre = '_leaflet_',
6875
- touches = this._msTouches;
7212
+ touches = this._pointers;
6876
7213
 
6877
7214
  var cb = function (e) {
6878
7215
  for (var i = 0; i < touches.length; i++) {
@@ -6889,26 +7226,26 @@ L.extend(L.DomEvent, {
6889
7226
  };
6890
7227
 
6891
7228
  obj[pre + 'touchend' + id] = cb;
6892
- obj.addEventListener('MSPointerUp', cb, false);
6893
- obj.addEventListener('MSPointerCancel', cb, false);
7229
+ obj.addEventListener(this.POINTER_UP, cb, false);
7230
+ obj.addEventListener(this.POINTER_CANCEL, cb, false);
6894
7231
 
6895
7232
  return this;
6896
7233
  },
6897
7234
 
6898
- removeMsTouchListener: function (obj, type, id) {
7235
+ removePointerListener: function (obj, type, id) {
6899
7236
  var pre = '_leaflet_',
6900
7237
  cb = obj[pre + type + id];
6901
7238
 
6902
7239
  switch (type) {
6903
7240
  case 'touchstart':
6904
- obj.removeEventListener('MSPointerDown', cb, false);
7241
+ obj.removeEventListener(this.POINTER_DOWN, cb, false);
6905
7242
  break;
6906
7243
  case 'touchmove':
6907
- obj.removeEventListener('MSPointerMove', cb, false);
7244
+ obj.removeEventListener(this.POINTER_MOVE, cb, false);
6908
7245
  break;
6909
7246
  case 'touchend':
6910
- obj.removeEventListener('MSPointerUp', cb, false);
6911
- obj.removeEventListener('MSPointerCancel', cb, false);
7247
+ obj.removeEventListener(this.POINTER_UP, cb, false);
7248
+ obj.removeEventListener(this.POINTER_CANCEL, cb, false);
6912
7249
  break;
6913
7250
  }
6914
7251
 
@@ -6922,7 +7259,8 @@ L.extend(L.DomEvent, {
6922
7259
  */
6923
7260
 
6924
7261
  L.Map.mergeOptions({
6925
- touchZoom: L.Browser.touch && !L.Browser.android23
7262
+ touchZoom: L.Browser.touch && !L.Browser.android23,
7263
+ bounceAtZoomLimits: true
6926
7264
  });
6927
7265
 
6928
7266
  L.Map.TouchZoom = L.Handler.extend({
@@ -6975,6 +7313,11 @@ L.Map.TouchZoom = L.Handler.extend({
6975
7313
 
6976
7314
  if (this._scale === 1) { return; }
6977
7315
 
7316
+ if (!map.options.bounceAtZoomLimits) {
7317
+ if ((map.getZoom() === map.getMinZoom() && this._scale < 1) ||
7318
+ (map.getZoom() === map.getMaxZoom() && this._scale > 1)) { return; }
7319
+ }
7320
+
6978
7321
  if (!this._moved) {
6979
7322
  L.DomUtil.addClass(map._mapPane, 'leaflet-touching');
6980
7323
 
@@ -6998,7 +7341,7 @@ L.Map.TouchZoom = L.Handler.extend({
6998
7341
  center = map.layerPointToLatLng(origin),
6999
7342
  zoom = map.getScaleZoom(this._scale);
7000
7343
 
7001
- map._animateZoom(center, zoom, this._startCenter, this._scale, this._delta, true);
7344
+ map._animateZoom(center, zoom, this._startCenter, this._scale, this._delta);
7002
7345
  },
7003
7346
 
7004
7347
  _onTouchEnd: function () {
@@ -7028,7 +7371,7 @@ L.Map.TouchZoom = L.Handler.extend({
7028
7371
  zoom = map._limitZoom(oldZoom + roundZoomDelta),
7029
7372
  scale = map.getZoomScale(zoom) / this._scale;
7030
7373
 
7031
- map._animateZoom(center, zoom, origin, scale, null, true);
7374
+ map._animateZoom(center, zoom, origin, scale);
7032
7375
  },
7033
7376
 
7034
7377
  _getScaleOrigin: function () {
@@ -7040,6 +7383,115 @@ L.Map.TouchZoom = L.Handler.extend({
7040
7383
  L.Map.addInitHook('addHandler', 'touchZoom', L.Map.TouchZoom);
7041
7384
 
7042
7385
 
7386
+ /*
7387
+ * L.Map.Tap is used to enable mobile hacks like quick taps and long hold.
7388
+ */
7389
+
7390
+ L.Map.mergeOptions({
7391
+ tap: true,
7392
+ tapTolerance: 15
7393
+ });
7394
+
7395
+ L.Map.Tap = L.Handler.extend({
7396
+ addHooks: function () {
7397
+ L.DomEvent.on(this._map._container, 'touchstart', this._onDown, this);
7398
+ },
7399
+
7400
+ removeHooks: function () {
7401
+ L.DomEvent.off(this._map._container, 'touchstart', this._onDown, this);
7402
+ },
7403
+
7404
+ _onDown: function (e) {
7405
+ if (!e.touches) { return; }
7406
+
7407
+ L.DomEvent.preventDefault(e);
7408
+
7409
+ this._fireClick = true;
7410
+
7411
+ // don't simulate click or track longpress if more than 1 touch
7412
+ if (e.touches.length > 1) {
7413
+ this._fireClick = false;
7414
+ clearTimeout(this._holdTimeout);
7415
+ return;
7416
+ }
7417
+
7418
+ var first = e.touches[0],
7419
+ el = first.target;
7420
+
7421
+ this._startPos = this._newPos = new L.Point(first.clientX, first.clientY);
7422
+
7423
+ // if touching a link, highlight it
7424
+ if (el.tagName && el.tagName.toLowerCase() === 'a') {
7425
+ L.DomUtil.addClass(el, 'leaflet-active');
7426
+ }
7427
+
7428
+ // simulate long hold but setting a timeout
7429
+ this._holdTimeout = setTimeout(L.bind(function () {
7430
+ if (this._isTapValid()) {
7431
+ this._fireClick = false;
7432
+ this._onUp();
7433
+ this._simulateEvent('contextmenu', first);
7434
+ }
7435
+ }, this), 1000);
7436
+
7437
+ L.DomEvent
7438
+ .on(document, 'touchmove', this._onMove, this)
7439
+ .on(document, 'touchend', this._onUp, this);
7440
+ },
7441
+
7442
+ _onUp: function (e) {
7443
+ clearTimeout(this._holdTimeout);
7444
+
7445
+ L.DomEvent
7446
+ .off(document, 'touchmove', this._onMove, this)
7447
+ .off(document, 'touchend', this._onUp, this);
7448
+
7449
+ if (this._fireClick && e && e.changedTouches) {
7450
+
7451
+ var first = e.changedTouches[0],
7452
+ el = first.target;
7453
+
7454
+ if (el && el.tagName && el.tagName.toLowerCase() === 'a') {
7455
+ L.DomUtil.removeClass(el, 'leaflet-active');
7456
+ }
7457
+
7458
+ // simulate click if the touch didn't move too much
7459
+ if (this._isTapValid()) {
7460
+ this._simulateEvent('click', first);
7461
+ }
7462
+ }
7463
+ },
7464
+
7465
+ _isTapValid: function () {
7466
+ return this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance;
7467
+ },
7468
+
7469
+ _onMove: function (e) {
7470
+ var first = e.touches[0];
7471
+ this._newPos = new L.Point(first.clientX, first.clientY);
7472
+ },
7473
+
7474
+ _simulateEvent: function (type, e) {
7475
+ var simulatedEvent = document.createEvent('MouseEvents');
7476
+
7477
+ simulatedEvent._simulated = true;
7478
+ e.target._simulatedClick = true;
7479
+
7480
+ simulatedEvent.initMouseEvent(
7481
+ type, true, true, window, 1,
7482
+ e.screenX, e.screenY,
7483
+ e.clientX, e.clientY,
7484
+ false, false, false, false, 0, null);
7485
+
7486
+ e.target.dispatchEvent(simulatedEvent);
7487
+ }
7488
+ });
7489
+
7490
+ if (L.Browser.touch && !L.Browser.pointer) {
7491
+ L.Map.addInitHook('addHandler', 'tap', L.Map.Tap);
7492
+ }
7493
+
7494
+
7043
7495
  /*
7044
7496
  * L.Handler.ShiftDragZoom is used to add shift-drag zoom interaction to the map
7045
7497
  * (zoom to a selected bounding box), enabled by default.
@@ -7054,6 +7506,7 @@ L.Map.BoxZoom = L.Handler.extend({
7054
7506
  this._map = map;
7055
7507
  this._container = map._container;
7056
7508
  this._pane = map._panes.overlayPane;
7509
+ this._moved = false;
7057
7510
  },
7058
7511
 
7059
7512
  addHooks: function () {
@@ -7062,12 +7515,20 @@ L.Map.BoxZoom = L.Handler.extend({
7062
7515
 
7063
7516
  removeHooks: function () {
7064
7517
  L.DomEvent.off(this._container, 'mousedown', this._onMouseDown);
7518
+ this._moved = false;
7519
+ },
7520
+
7521
+ moved: function () {
7522
+ return this._moved;
7065
7523
  },
7066
7524
 
7067
7525
  _onMouseDown: function (e) {
7526
+ this._moved = false;
7527
+
7068
7528
  if (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; }
7069
7529
 
7070
7530
  L.DomUtil.disableTextSelection();
7531
+ L.DomUtil.disableImageDrag();
7071
7532
 
7072
7533
  this._startLayerPoint = this._map.mouseEventToLayerPoint(e);
7073
7534
 
@@ -7080,8 +7541,7 @@ L.Map.BoxZoom = L.Handler.extend({
7080
7541
  L.DomEvent
7081
7542
  .on(document, 'mousemove', this._onMouseMove, this)
7082
7543
  .on(document, 'mouseup', this._onMouseUp, this)
7083
- .on(document, 'keydown', this._onKeyDown, this)
7084
- .preventDefault(e);
7544
+ .on(document, 'keydown', this._onKeyDown, this);
7085
7545
 
7086
7546
  this._map.fire('boxzoomstart');
7087
7547
  },
@@ -7099,6 +7559,8 @@ L.Map.BoxZoom = L.Handler.extend({
7099
7559
 
7100
7560
  L.DomUtil.setPosition(box, newPos);
7101
7561
 
7562
+ this._moved = true;
7563
+
7102
7564
  // TODO refactor: remove hardcoded 4 pixels
7103
7565
  box.style.width = (Math.max(0, Math.abs(offset.x) - 4)) + 'px';
7104
7566
  box.style.height = (Math.max(0, Math.abs(offset.y) - 4)) + 'px';
@@ -7109,6 +7571,7 @@ L.Map.BoxZoom = L.Handler.extend({
7109
7571
  this._container.style.cursor = '';
7110
7572
 
7111
7573
  L.DomUtil.enableTextSelection();
7574
+ L.DomUtil.enableImageDrag();
7112
7575
 
7113
7576
  L.DomEvent
7114
7577
  .off(document, 'mousemove', this._onMouseMove)
@@ -7163,7 +7626,7 @@ L.Map.Keyboard = L.Handler.extend({
7163
7626
  right: [39],
7164
7627
  down: [40],
7165
7628
  up: [38],
7166
- zoomIn: [187, 107, 61],
7629
+ zoomIn: [187, 107, 61, 171],
7167
7630
  zoomOut: [189, 109, 173]
7168
7631
  },
7169
7632
 
@@ -7213,7 +7676,7 @@ L.Map.Keyboard = L.Handler.extend({
7213
7676
  var body = document.body,
7214
7677
  docEl = document.documentElement,
7215
7678
  top = body.scrollTop || docEl.scrollTop,
7216
- left = body.scrollTop || docEl.scrollLeft;
7679
+ left = body.scrollLeft || docEl.scrollLeft;
7217
7680
 
7218
7681
  this._map._container.focus();
7219
7682
 
@@ -7275,6 +7738,9 @@ L.Map.Keyboard = L.Handler.extend({
7275
7738
  map = this._map;
7276
7739
 
7277
7740
  if (key in this._panKeys) {
7741
+
7742
+ if (map._panAnim && map._panAnim._inProgress) { return; }
7743
+
7278
7744
  map.panBy(this._panKeys[key]);
7279
7745
 
7280
7746
  if (map.options.maxBounds) {
@@ -7315,15 +7781,17 @@ L.Handler.MarkerDrag = L.Handler.extend({
7315
7781
  .on('drag', this._onDrag, this)
7316
7782
  .on('dragend', this._onDragEnd, this);
7317
7783
  this._draggable.enable();
7784
+ L.DomUtil.addClass(this._marker._icon, 'leaflet-marker-draggable');
7318
7785
  },
7319
7786
 
7320
7787
  removeHooks: function () {
7321
7788
  this._draggable
7322
- .off('dragstart', this._onDragStart)
7323
- .off('drag', this._onDrag)
7324
- .off('dragend', this._onDragEnd);
7789
+ .off('dragstart', this._onDragStart, this)
7790
+ .off('drag', this._onDrag, this)
7791
+ .off('dragend', this._onDragEnd, this);
7325
7792
 
7326
7793
  this._draggable.disable();
7794
+ L.DomUtil.removeClass(this._marker._icon, 'leaflet-marker-draggable');
7327
7795
  },
7328
7796
 
7329
7797
  moved: function () {
@@ -7335,6 +7803,7 @@ L.Handler.MarkerDrag = L.Handler.extend({
7335
7803
  .closePopup()
7336
7804
  .fire('movestart')
7337
7805
  .fire('dragstart');
7806
+ L.DomUtil.addClass(this._marker._icon, 'leaflet-marker-dragging');
7338
7807
  },
7339
7808
 
7340
7809
  _onDrag: function () {
@@ -7359,6 +7828,7 @@ L.Handler.MarkerDrag = L.Handler.extend({
7359
7828
  this._marker
7360
7829
  .fire('moveend')
7361
7830
  .fire('dragend');
7831
+ L.DomUtil.removeClass(this._marker._icon, 'leaflet-marker-dragging');
7362
7832
  }
7363
7833
  });
7364
7834
 
@@ -7431,6 +7901,12 @@ L.Control = L.Class.extend({
7431
7901
  }
7432
7902
 
7433
7903
  return this;
7904
+ },
7905
+
7906
+ _refocusOnMap: function () {
7907
+ if (this._map) {
7908
+ this._map.getContainer().focus();
7909
+ }
7434
7910
  }
7435
7911
  });
7436
7912
 
@@ -7468,6 +7944,10 @@ L.Map.include({
7468
7944
  createCorner('top', 'right');
7469
7945
  createCorner('bottom', 'left');
7470
7946
  createCorner('bottom', 'right');
7947
+ },
7948
+
7949
+ _clearControlPos: function () {
7950
+ this._container.removeChild(this._controlContainer);
7471
7951
  }
7472
7952
  });
7473
7953
 
@@ -7478,7 +7958,11 @@ L.Map.include({
7478
7958
 
7479
7959
  L.Control.Zoom = L.Control.extend({
7480
7960
  options: {
7481
- position: 'topleft'
7961
+ position: 'topleft',
7962
+ zoomInText: '+',
7963
+ zoomInTitle: 'Zoom in',
7964
+ zoomOutText: '-',
7965
+ zoomOutTitle: 'Zoom out'
7482
7966
  },
7483
7967
 
7484
7968
  onAdd: function (map) {
@@ -7488,10 +7972,13 @@ L.Control.Zoom = L.Control.extend({
7488
7972
  this._map = map;
7489
7973
 
7490
7974
  this._zoomInButton = this._createButton(
7491
- '+', 'Zoom in', zoomName + '-in', container, this._zoomIn, this);
7975
+ this.options.zoomInText, this.options.zoomInTitle,
7976
+ zoomName + '-in', container, this._zoomIn, this);
7492
7977
  this._zoomOutButton = this._createButton(
7493
- '-', 'Zoom out', zoomName + '-out', container, this._zoomOut, this);
7978
+ this.options.zoomOutText, this.options.zoomOutTitle,
7979
+ zoomName + '-out', container, this._zoomOut, this);
7494
7980
 
7981
+ this._updateDisabled();
7495
7982
  map.on('zoomend zoomlevelschange', this._updateDisabled, this);
7496
7983
 
7497
7984
  return container;
@@ -7522,7 +8009,8 @@ L.Control.Zoom = L.Control.extend({
7522
8009
  .on(link, 'mousedown', stop)
7523
8010
  .on(link, 'dblclick', stop)
7524
8011
  .on(link, 'click', L.DomEvent.preventDefault)
7525
- .on(link, 'click', fn, context);
8012
+ .on(link, 'click', fn, context)
8013
+ .on(link, 'click', this._refocusOnMap, context);
7526
8014
 
7527
8015
  return link;
7528
8016
  },
@@ -7858,9 +8346,13 @@ L.Control.Layers = L.Control.extend({
7858
8346
  var className = 'leaflet-control-layers',
7859
8347
  container = this._container = L.DomUtil.create('div', className);
7860
8348
 
8349
+ //Makes this work on IE10 Touch devices by stopping it from firing a mouseout event when the touch is released
8350
+ container.setAttribute('aria-haspopup', true);
8351
+
7861
8352
  if (!L.Browser.touch) {
7862
- L.DomEvent.disableClickPropagation(container);
7863
- L.DomEvent.on(container, 'mousewheel', L.DomEvent.stopPropagation);
8353
+ L.DomEvent
8354
+ .disableClickPropagation(container)
8355
+ .disableScrollPropagation(container);
7864
8356
  } else {
7865
8357
  L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation);
7866
8358
  }
@@ -7868,25 +8360,25 @@ L.Control.Layers = L.Control.extend({
7868
8360
  var form = this._form = L.DomUtil.create('form', className + '-list');
7869
8361
 
7870
8362
  if (this.options.collapsed) {
7871
- L.DomEvent
7872
- .on(container, 'mouseover', this._expand, this)
7873
- .on(container, 'mouseout', this._collapse, this);
7874
-
8363
+ if (!L.Browser.android) {
8364
+ L.DomEvent
8365
+ .on(container, 'mouseover', this._expand, this)
8366
+ .on(container, 'mouseout', this._collapse, this);
8367
+ }
7875
8368
  var link = this._layersLink = L.DomUtil.create('a', className + '-toggle', container);
7876
8369
  link.href = '#';
7877
8370
  link.title = 'Layers';
7878
8371
 
7879
8372
  if (L.Browser.touch) {
7880
8373
  L.DomEvent
7881
- .on(link, 'click', L.DomEvent.stopPropagation)
7882
- .on(link, 'click', L.DomEvent.preventDefault)
8374
+ .on(link, 'click', L.DomEvent.stop)
7883
8375
  .on(link, 'click', this._expand, this);
7884
8376
  }
7885
8377
  else {
7886
8378
  L.DomEvent.on(link, 'focus', this._expand, this);
7887
8379
  }
7888
8380
 
7889
- this._map.on('movestart', this._collapse, this);
8381
+ this._map.on('click', this._collapse, this);
7890
8382
  // TODO keyboard accessibility
7891
8383
  } else {
7892
8384
  this._expand();
@@ -7937,11 +8429,21 @@ L.Control.Layers = L.Control.extend({
7937
8429
  },
7938
8430
 
7939
8431
  _onLayerChange: function (e) {
7940
- var id = L.stamp(e.layer);
8432
+ var obj = this._layers[L.stamp(e.layer)];
8433
+
8434
+ if (!obj) { return; }
7941
8435
 
7942
- if (this._layers[id] && !this._handlingClick) {
8436
+ if (!this._handlingClick) {
7943
8437
  this._update();
7944
8438
  }
8439
+
8440
+ var type = obj.overlay ?
8441
+ (e.type === 'layeradd' ? 'overlayadd' : 'overlayremove') :
8442
+ (e.type === 'layeradd' ? 'baselayerchange' : null);
8443
+
8444
+ if (type) {
8445
+ this._map.fire(type, obj);
8446
+ }
7945
8447
  },
7946
8448
 
7947
8449
  // IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe)
@@ -7992,8 +8494,7 @@ L.Control.Layers = L.Control.extend({
7992
8494
  _onInputClick: function () {
7993
8495
  var i, input, obj,
7994
8496
  inputs = this._form.getElementsByTagName('input'),
7995
- inputsLen = inputs.length,
7996
- baseLayer;
8497
+ inputsLen = inputs.length;
7997
8498
 
7998
8499
  this._handlingClick = true;
7999
8500
 
@@ -8003,23 +8504,15 @@ L.Control.Layers = L.Control.extend({
8003
8504
 
8004
8505
  if (input.checked && !this._map.hasLayer(obj.layer)) {
8005
8506
  this._map.addLayer(obj.layer);
8006
- if (!obj.overlay) {
8007
- baseLayer = obj.layer;
8008
- } else {
8009
- this._map.fire('overlayadd', {layer: obj});
8010
- }
8507
+
8011
8508
  } else if (!input.checked && this._map.hasLayer(obj.layer)) {
8012
8509
  this._map.removeLayer(obj.layer);
8013
- this._map.fire('overlayremove', {layer: obj});
8014
8510
  }
8015
8511
  }
8016
8512
 
8017
- if (baseLayer) {
8018
- this._map.setZoom(this._map.getZoom());
8019
- this._map.fire('baselayerchange', {layer: baseLayer});
8020
- }
8021
-
8022
8513
  this._handlingClick = false;
8514
+
8515
+ this._refocusOnMap();
8023
8516
  },
8024
8517
 
8025
8518
  _expand: function () {
@@ -8048,6 +8541,7 @@ L.PosAnimation = L.Class.extend({
8048
8541
 
8049
8542
  this._el = el;
8050
8543
  this._inProgress = true;
8544
+ this._newPos = newPos;
8051
8545
 
8052
8546
  this.fire('start');
8053
8547
 
@@ -8076,9 +8570,14 @@ L.PosAnimation = L.Class.extend({
8076
8570
  },
8077
8571
 
8078
8572
  _onStep: function () {
8573
+ var stepPos = this._getPos();
8574
+ if (!stepPos) {
8575
+ this._onTransitionEnd();
8576
+ return;
8577
+ }
8079
8578
  // jshint camelcase: false
8080
8579
  // make L.DomUtil.getPosition return intermediate position value during animation
8081
- this._el._leaflet_pos = this._getPos();
8580
+ this._el._leaflet_pos = stepPos;
8082
8581
 
8083
8582
  this.fire('step');
8084
8583
  },
@@ -8086,7 +8585,7 @@ L.PosAnimation = L.Class.extend({
8086
8585
  // you can't easily get intermediate values of properties animated with CSS3 Transitions,
8087
8586
  // we need to parse computed style (in case of transform it returns matrix string)
8088
8587
 
8089
- _transformRe: /(-?[\d\.]+), (-?[\d\.]+)\)/,
8588
+ _transformRe: /([-+]?(?:\d*\.)?\d+)\D*, ([-+]?(?:\d*\.)?\d+)\D*\)/,
8090
8589
 
8091
8590
  _getPos: function () {
8092
8591
  var left, top, matches,
@@ -8095,6 +8594,7 @@ L.PosAnimation = L.Class.extend({
8095
8594
 
8096
8595
  if (L.Browser.any3d) {
8097
8596
  matches = style[L.DomUtil.TRANSFORM].match(this._transformRe);
8597
+ if (!matches) { return; }
8098
8598
  left = parseFloat(matches[1]);
8099
8599
  top = parseFloat(matches[2]);
8100
8600
  } else {
@@ -8113,6 +8613,10 @@ L.PosAnimation = L.Class.extend({
8113
8613
 
8114
8614
  this._el.style[L.DomUtil.TRANSITION] = '';
8115
8615
 
8616
+ // jshint camelcase: false
8617
+ // make sure L.DomUtil.getPosition returns the final position value after animation
8618
+ this._el._leaflet_pos = this._newPos;
8619
+
8116
8620
  clearInterval(this._stepTimer);
8117
8621
 
8118
8622
  this.fire('step').fire('end');
@@ -8127,24 +8631,27 @@ L.PosAnimation = L.Class.extend({
8127
8631
 
8128
8632
  L.Map.include({
8129
8633
 
8130
- setView: function (center, zoom, forceReset) {
8634
+ setView: function (center, zoom, options) {
8131
8635
 
8132
- zoom = this._limitZoom(zoom);
8636
+ zoom = zoom === undefined ? this._zoom : this._limitZoom(zoom);
8133
8637
  center = L.latLng(center);
8638
+ options = options || {};
8134
8639
 
8135
8640
  if (this._panAnim) {
8136
8641
  this._panAnim.stop();
8137
8642
  }
8138
8643
 
8139
- var zoomChanged = (this._zoom !== zoom),
8140
- canBeAnimated = this._loaded && !forceReset && !!this._layers;
8644
+ if (this._loaded && !options.reset && options !== true) {
8141
8645
 
8142
- if (canBeAnimated) {
8646
+ if (options.animate !== undefined) {
8647
+ options.zoom = L.extend({animate: options.animate}, options.zoom);
8648
+ options.pan = L.extend({animate: options.animate}, options.pan);
8649
+ }
8143
8650
 
8144
8651
  // try animating pan or zoom
8145
- var animated = zoomChanged ?
8146
- this.options.zoomAnimation && this._animateZoomIfClose && this._animateZoomIfClose(center, zoom) :
8147
- this._animatePanIfClose(center);
8652
+ var animated = (this._zoom !== zoom) ?
8653
+ this._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom, options.zoom) :
8654
+ this._tryAnimatedPan(center, options.pan);
8148
8655
 
8149
8656
  if (animated) {
8150
8657
  // prevent resize handler call, the view will refresh after animation anyway
@@ -8159,10 +8666,9 @@ L.Map.include({
8159
8666
  return this;
8160
8667
  },
8161
8668
 
8162
- panBy: function (offset, duration, easeLinearity, noMoveStart) {
8669
+ panBy: function (offset, options) {
8163
8670
  offset = L.point(offset).round();
8164
-
8165
- // TODO add options instead of arguments to setView/panTo/panBy/etc.
8671
+ options = options || {};
8166
8672
 
8167
8673
  if (!offset.x && !offset.y) {
8168
8674
  return this;
@@ -8178,14 +8684,20 @@ L.Map.include({
8178
8684
  }
8179
8685
 
8180
8686
  // don't fire movestart if animating inertia
8181
- if (!noMoveStart) {
8687
+ if (!options.noMoveStart) {
8182
8688
  this.fire('movestart');
8183
8689
  }
8184
8690
 
8185
- L.DomUtil.addClass(this._mapPane, 'leaflet-pan-anim');
8691
+ // animate pan unless animate: false specified
8692
+ if (options.animate !== false) {
8693
+ L.DomUtil.addClass(this._mapPane, 'leaflet-pan-anim');
8186
8694
 
8187
- var newPos = this._getMapPanePos().subtract(offset);
8188
- this._panAnim.run(this._mapPane, newPos, duration || 0.25, easeLinearity);
8695
+ var newPos = this._getMapPanePos().subtract(offset);
8696
+ this._panAnim.run(this._mapPane, newPos, options.duration || 0.25, options.easeLinearity);
8697
+ } else {
8698
+ this._rawPanBy(offset);
8699
+ this.fire('move').fire('moveend');
8700
+ }
8189
8701
 
8190
8702
  return this;
8191
8703
  },
@@ -8199,13 +8711,15 @@ L.Map.include({
8199
8711
  this.fire('moveend');
8200
8712
  },
8201
8713
 
8202
- _animatePanIfClose: function (center) {
8714
+ _tryAnimatedPan: function (center, options) {
8203
8715
  // difference between the new and current centers in pixels
8204
8716
  var offset = this._getCenterOffset(center)._floor();
8205
8717
 
8206
- if (!this.getSize().contains(offset)) { return false; }
8718
+ // don't animate too far unless animate: true specified in options
8719
+ if ((options && options.animate) !== true && !this.getSize().contains(offset)) { return false; }
8720
+
8721
+ this.panBy(offset, options);
8207
8722
 
8208
- this.panBy(offset);
8209
8723
  return true;
8210
8724
  }
8211
8725
  });
@@ -8285,17 +8799,22 @@ L.PosAnimation = L.DomUtil.TRANSITION ? L.PosAnimation : L.PosAnimation.extend({
8285
8799
  */
8286
8800
 
8287
8801
  L.Map.mergeOptions({
8288
- zoomAnimation: L.DomUtil.TRANSITION && !L.Browser.android23 && !L.Browser.mobileOpera,
8802
+ zoomAnimation: true,
8289
8803
  zoomAnimationThreshold: 4
8290
8804
  });
8291
8805
 
8292
8806
  if (L.DomUtil.TRANSITION) {
8293
8807
 
8294
8808
  L.Map.addInitHook(function () {
8809
+ // don't animate on browsers without hardware-accelerated transitions or old Android/Opera
8810
+ this._zoomAnimated = this.options.zoomAnimation && L.DomUtil.TRANSITION &&
8811
+ L.Browser.any3d && !L.Browser.android23 && !L.Browser.mobileOpera;
8812
+
8295
8813
  // zoom transitions run with the same duration for all layers, so if one of transitionend events
8296
8814
  // happens after starting zoom animation (propagating to the map pane), we know that it ended globally
8297
-
8298
- L.DomEvent.on(this._mapPane, L.DomUtil.TRANSITION_END, this._catchTransitionEnd, this);
8815
+ if (this._zoomAnimated) {
8816
+ L.DomEvent.on(this._mapPane, L.DomUtil.TRANSITION_END, this._catchTransitionEnd, this);
8817
+ }
8299
8818
  });
8300
8819
  }
8301
8820
 
@@ -8307,26 +8826,33 @@ L.Map.include(!L.DomUtil.TRANSITION ? {} : {
8307
8826
  }
8308
8827
  },
8309
8828
 
8310
- _animateZoomIfClose: function (center, zoom) {
8829
+ _nothingToAnimate: function () {
8830
+ return !this._container.getElementsByClassName('leaflet-zoom-animated').length;
8831
+ },
8832
+
8833
+ _tryAnimatedZoom: function (center, zoom, options) {
8311
8834
 
8312
8835
  if (this._animatingZoom) { return true; }
8313
8836
 
8314
- // don't animate if zoom difference is too large
8315
- if (Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; }
8837
+ options = options || {};
8838
+
8839
+ // don't animate if disabled, not supported or zoom difference is too large
8840
+ if (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() ||
8841
+ Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; }
8316
8842
 
8317
8843
  // offset is the pixel coords of the zoom origin relative to the current center
8318
8844
  var scale = this.getZoomScale(zoom),
8319
8845
  offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale),
8320
8846
  origin = this._getCenterLayerPoint()._add(offset);
8321
8847
 
8322
- // only animate if the zoom origin is within one screen from the current center
8323
- if (!this.getSize().contains(offset)) { return false; }
8848
+ // don't animate if the zoom origin isn't within one screen from the current center, unless forced
8849
+ if (options.animate !== true && !this.getSize().contains(offset)) { return false; }
8324
8850
 
8325
8851
  this
8326
8852
  .fire('movestart')
8327
8853
  .fire('zoomstart');
8328
8854
 
8329
- this._animateZoom(center, zoom, origin, scale);
8855
+ this._animateZoom(center, zoom, origin, scale, null, true);
8330
8856
 
8331
8857
  return true;
8332
8858
  },
@@ -8378,34 +8904,19 @@ L.Map.include(!L.DomUtil.TRANSITION ? {} : {
8378
8904
 
8379
8905
  L.TileLayer.include({
8380
8906
  _animateZoom: function (e) {
8381
- var firstFrame = false;
8382
-
8383
8907
  if (!this._animating) {
8384
8908
  this._animating = true;
8385
- firstFrame = true;
8386
- }
8387
-
8388
- if (firstFrame) {
8389
8909
  this._prepareBgBuffer();
8390
8910
  }
8391
8911
 
8392
- var transform = L.DomUtil.TRANSFORM,
8393
- bg = this._bgBuffer;
8394
-
8395
- if (firstFrame) {
8396
- //prevent bg buffer from clearing right after zoom
8397
- clearTimeout(this._clearBgBufferTimer);
8398
-
8399
- // hack to make sure transform is updated before running animation
8400
- L.Util.falseFn(bg.offsetWidth);
8401
- }
8402
-
8403
- var scaleStr = L.DomUtil.getScaleString(e.scale, e.origin),
8404
- oldTransform = bg.style[transform];
8912
+ var bg = this._bgBuffer,
8913
+ transform = L.DomUtil.TRANSFORM,
8914
+ initialTransform = e.delta ? L.DomUtil.getTranslateString(e.delta) : bg.style[transform],
8915
+ scaleStr = L.DomUtil.getScaleString(e.scale, e.origin);
8405
8916
 
8406
8917
  bg.style[transform] = e.backwards ?
8407
- (e.delta ? L.DomUtil.getTranslateString(e.delta) : oldTransform) + ' ' + scaleStr :
8408
- scaleStr + ' ' + oldTransform;
8918
+ scaleStr + ' ' + initialTransform :
8919
+ initialTransform + ' ' + scaleStr;
8409
8920
  },
8410
8921
 
8411
8922
  _endZoomAnim: function () {
@@ -8413,9 +8924,7 @@ L.TileLayer.include({
8413
8924
  bg = this._bgBuffer;
8414
8925
 
8415
8926
  front.style.visibility = '';
8416
- front.style.zIndex = 2;
8417
-
8418
- bg.style.zIndex = 1;
8927
+ front.parentNode.appendChild(front); // Bring to fore
8419
8928
 
8420
8929
  // force reflow
8421
8930
  L.Util.falseFn(bg.offsetWidth);
@@ -8440,8 +8949,10 @@ L.TileLayer.include({
8440
8949
  // if foreground layer doesn't have many tiles but bg layer does,
8441
8950
  // keep the existing bg layer and just zoom it some more
8442
8951
 
8443
- if (bg && this._getLoadedTilesPercentage(bg) > 0.5 &&
8444
- this._getLoadedTilesPercentage(front) < 0.5) {
8952
+ var bgLoaded = this._getLoadedTilesPercentage(bg),
8953
+ frontLoaded = this._getLoadedTilesPercentage(front);
8954
+
8955
+ if (bg && bgLoaded > 0.5 && frontLoaded < 0.5) {
8445
8956
 
8446
8957
  front.style.visibility = 'hidden';
8447
8958
  this._stopLoadingImages(front);
@@ -8457,6 +8968,9 @@ L.TileLayer.include({
8457
8968
  bg = this._bgBuffer = front;
8458
8969
 
8459
8970
  this._stopLoadingImages(bg);
8971
+
8972
+ //prevent bg buffer from clearing right after zoom
8973
+ clearTimeout(this._clearBgBufferTimer);
8460
8974
  },
8461
8975
 
8462
8976
  _getLoadedTilesPercentage: function (container) {
@@ -8574,12 +9088,19 @@ L.Map.include({
8574
9088
  this.setView(latlng, zoom);
8575
9089
  }
8576
9090
 
8577
- var event = L.extend({
9091
+ var data = {
8578
9092
  latlng: latlng,
8579
- bounds: bounds
8580
- }, pos.coords);
9093
+ bounds: bounds,
9094
+ timestamp: pos.timestamp
9095
+ };
9096
+
9097
+ for (var i in pos.coords) {
9098
+ if (typeof pos.coords[i] === 'number') {
9099
+ data[i] = pos.coords[i];
9100
+ }
9101
+ }
8581
9102
 
8582
- this.fire('locationfound', event);
9103
+ this.fire('locationfound', data);
8583
9104
  }
8584
9105
  });
8585
9106