]> git.openstreetmap.org Git - rails.git/blobdiff - vendor/assets/leaflet/leaflet.locate.js
Merge branch 'master' into overpass
[rails.git] / vendor / assets / leaflet / leaflet.locate.js
index fd017d4c89da97ce03e5399f55c79ab17f1e0826..822b24da23daa0490be3a2bd62bee181f09da3c5 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2013 Dominik Moritz
+Copyright (c) 2014 Dominik Moritz
 
 This file is part of the leaflet locate control. It is licensed under the MIT license.
 You can find the project at: https://github.com/domoritz/leaflet-locatecontrol
@@ -9,7 +9,7 @@ L.Control.Locate = L.Control.extend({
         position: 'topleft',
         drawCircle: true,
         follow: false,  // follow with zoom and pan the user's location
-        stopFollowingOnDrag: false, // if follow is true, stop following when map is dragged
+        stopFollowingOnDrag: false, // if follow is true, stop following when map is dragged (deprecated)
         // range circle
         circleStyle: {
             color: '#136AEC',
@@ -34,23 +34,32 @@ L.Control.Locate = L.Control.extend({
             //color: '#FFA500',
             //fillColor: '#FFB000'
         },
+        icon: 'icon-location',  // icon-location or icon-direction
+        iconLoading: 'icon-spinner animate-spin',
+        circlePadding: [0, 0],
         metric: true,
         onLocationError: function(err) {
             // this event is called in case of any location error
             // that is not a time out error.
             alert(err.message);
         },
-        onLocationOutsideMapBounds: function(context) {
+        onLocationOutsideMapBounds: function(control) {
             // this event is repeatedly called when the location changes
+            control.stopLocate();
             alert(context.options.strings.outsideMapBoundsMsg);
         },
         setView: true, // automatically sets the map view to the user's location
+        // keep the current map zoom level when displaying the user's location. (if 'false', use maxZoom)
+        keepCurrentZoomLevel: false,
         strings: {
             title: "Show me where I am",
             popup: "You are within {distance} {unit} from this point",
             outsideMapBoundsMsg: "You seem located outside the boundaries of the map"
         },
-        locateOptions: {}
+        locateOptions: {
+            maxZoom: Infinity,
+            watch: true  // if you overwrite this, visualization cannot be updated
+        }
     },
 
     onAdd: function (map) {
@@ -61,9 +70,7 @@ L.Control.Locate = L.Control.extend({
         this._layer.addTo(map);
         this._event = undefined;
 
-        this._locateOptions = {
-            watch: true  // if you overwrite this, visualization cannot be updated
-        };
+        this._locateOptions = this.options.locateOptions;
         L.extend(this._locateOptions, this.options.locateOptions);
         L.extend(this._locateOptions, {
             setView: false // have to set this to false because we have to
@@ -78,7 +85,7 @@ L.Control.Locate = L.Control.extend({
         L.extend(tmp, this.options.circleStyle, this.options.followCircleStyle);
         this.options.followCircleStyle = tmp;
 
-        var link = L.DomUtil.create('a', 'control-button', container);
+        var link = L.DomUtil.create('a', 'control-button ' + this.options.icon, container);
         link.innerHTML = "<span class='icon geolocate'></span>";
         link.href = '#';
         link.title = this.options.strings.title;
@@ -87,36 +94,39 @@ L.Control.Locate = L.Control.extend({
             .on(link, 'click', L.DomEvent.stopPropagation)
             .on(link, 'click', L.DomEvent.preventDefault)
             .on(link, 'click', function() {
-                if (self._active && (map.getBounds().contains(self._event.latlng) || !self.options.setView ||
+                if (self._active && (self._event === undefined || map.getBounds().contains(self._event.latlng) || !self.options.setView ||
                     isOutsideMapBounds())) {
                     stopLocate();
                 } else {
-                    if (self.options.setView) {
-                        self._locateOnNextLocationFound = true;
-                    }
-                    if(!self._active) {
-                        map.locate(self._locateOptions);
-                    }
-                    self._active = true;
-                    if (self.options.follow) {
-                        startFollowing();
-                    }
-                    if (!self._event) {
-                        L.DomUtil.addClass(self._container, "requesting");
-                        L.DomUtil.removeClass(self._container, "active");
-                        L.DomUtil.removeClass(self._container, "following");
-                    } else {
-                        visualizeLocation();
-                    }
+                    locate();
                 }
             })
             .on(link, 'dblclick', L.DomEvent.stopPropagation);
 
+        var locate = function () {
+            if (self.options.setView) {
+                self._locateOnNextLocationFound = true;
+            }
+            if(!self._active) {
+                map.locate(self._locateOptions);
+            }
+            self._active = true;
+            if (self.options.follow) {
+                startFollowing();
+            }
+            if (!self._event) {
+                setClasses('requesting');
+            } else {
+                visualizeLocation();
+            }
+        };
+
         var onLocationFound = function (e) {
             // no need to do anything if the location has not changed
             if (self._event &&
-                (self._event.latlng.lat == e.latlng.lat &&
-                 self._event.latlng.lng == e.latlng.lng)) {
+                (self._event.latlng.lat === e.latlng.lat &&
+                 self._event.latlng.lng === e.latlng.lng &&
+                 self._event.accuracy === e.accuracy)) {
                 return;
             }
 
@@ -134,6 +144,7 @@ L.Control.Locate = L.Control.extend({
         };
 
         var startFollowing = function() {
+            map.fire('startfollowing', self);
             self._following = true;
             if (self.options.stopFollowingOnDrag) {
                 map.on('dragstart', stopFollowing);
@@ -141,6 +152,7 @@ L.Control.Locate = L.Control.extend({
         };
 
         var stopFollowing = function() {
+            map.fire('stopfollowing', self);
             self._following = false;
             if (self.options.stopFollowingOnDrag) {
                 map.off('dragstart', stopFollowing);
@@ -164,13 +176,16 @@ L.Control.Locate = L.Control.extend({
                 if (isOutsideMapBounds()) {
                     self.options.onLocationOutsideMapBounds(self);
                 } else {
-                    map.fitBounds(self._event.bounds);
+                    map.fitBounds(self._event.bounds, {
+                        padding: self.options.circlePadding,
+                        maxZoom: self.options.keepCurrentZoomLevel ? map.getZoom() : self._locateOptions.maxZoom
+                    });
                 }
                 self._locateOnNextLocationFound = false;
             }
 
             // circle with the radius of the location's accuracy
-            var style;
+            var style, o;
             if (self.options.drawCircle) {
                 if (self._following) {
                     style = self.options.followCircleStyle;
@@ -183,6 +198,9 @@ L.Control.Locate = L.Control.extend({
                         .addTo(self._layer);
                 } else {
                     self._circle.setLatLng(self._event.latlng).setRadius(radius);
+                    for (o in style) {
+                        self._circle.options[o] = style[o];
+                    }
                 }
             }
 
@@ -196,37 +214,58 @@ L.Control.Locate = L.Control.extend({
             }
 
             // small inner marker
-            var m;
+            var mStyle;
             if (self._following) {
-                m = self.options.followMarkerStyle;
+                mStyle = self.options.followMarkerStyle;
             } else {
-                m = self.options.markerStyle;
+                mStyle = self.options.markerStyle;
             }
 
             var t = self.options.strings.popup;
             if (!self._circleMarker) {
-                self._circleMarker = L.circleMarker(self._event.latlng, m)
+                self._circleMarker = L.circleMarker(self._event.latlng, mStyle)
                     .bindPopup(L.Util.template(t, {distance: distance, unit: unit}))
                     .addTo(self._layer);
             } else {
                 self._circleMarker.setLatLng(self._event.latlng)
                     .bindPopup(L.Util.template(t, {distance: distance, unit: unit}))
                     ._popup.setLatLng(self._event.latlng);
+                for (o in mStyle) {
+                    self._circleMarker.options[o] = mStyle[o];
+                }
             }
 
             if (!self._container)
                 return;
             if (self._following) {
-                L.DomUtil.removeClass(self._container, "requesting");
-                L.DomUtil.addClass(self._container, "active");
-                L.DomUtil.addClass(self._container, "following");
+                setClasses('following');
             } else {
-                L.DomUtil.removeClass(self._container, "requesting");
-                L.DomUtil.addClass(self._container, "active");
-                L.DomUtil.removeClass(self._container, "following");
+                setClasses('active');
             }
         };
 
+        var setClasses = function(state) {
+            if (state == 'requesting') {
+                L.DomUtil.removeClasses(self._container, "active following");
+                L.DomUtil.addClasses(self._container, "requesting");
+
+                L.DomUtil.removeClasses(link, self.options.icon);
+                L.DomUtil.addClasses(link, self.options.iconLoading);
+            } else if (state == 'active') {
+                L.DomUtil.removeClasses(self._container, "requesting following");
+                L.DomUtil.addClasses(self._container, "active");
+
+                L.DomUtil.removeClasses(link, self.options.iconLoading);
+                L.DomUtil.addClasses(link, self.options.icon);
+            } else if (state == 'following') {
+                L.DomUtil.removeClasses(self._container, "requesting");
+                L.DomUtil.addClasses(self._container, "active following");
+
+                L.DomUtil.removeClasses(link, self.options.iconLoading);
+                L.DomUtil.addClasses(link, self.options.icon);
+            }
+        }
+
         var resetVariables = function() {
             self._active = false;
             self._locateOnNextLocationFound = self.options.setView;
@@ -238,6 +277,9 @@ L.Control.Locate = L.Control.extend({
         var stopLocate = function() {
             map.stopLocate();
             map.off('dragstart', stopFollowing);
+            if (self.options.follow && self._following) {
+                stopFollowing();
+            }
 
             L.DomUtil.removeClass(self._container, "requesting");
             L.DomUtil.removeClass(self._container, "active");
@@ -251,7 +293,7 @@ L.Control.Locate = L.Control.extend({
 
         var onLocationError = function (err) {
             // ignore time out error if the location is watched
-            if (err.code == 3 && this._locateOptions.watch) {
+            if (err.code == 3 && self._locateOptions.watch) {
                 return;
             }
 
@@ -263,6 +305,11 @@ L.Control.Locate = L.Control.extend({
         map.on('locationfound', onLocationFound, self);
         map.on('locationerror', onLocationError, self);
 
+        // make locate functions available to outside world
+        this.locate = locate;
+        this.stopLocate = stopLocate;
+        this.stopFollowing = stopFollowing;
+
         return container;
     }
 });
@@ -277,3 +324,17 @@ L.Map.addInitHook(function () {
 L.control.locate = function (options) {
     return new L.Control.Locate(options);
 };
+
+(function(){
+  // leaflet.js raises bug when trying to addClass / removeClass multiple classes at once
+  // Let's create a wrapper on it which fixes it.
+  var LDomUtilApplyClassesMethod = function(method, element, classNames) {
+    classNames = classNames.split(' ');
+    classNames.forEach(function(className) {
+        L.DomUtil[method].call(this, element, className);
+    });
+  };
+
+  L.DomUtil.addClasses = function(el, names) { LDomUtilApplyClassesMethod('addClass', el, names); }
+  L.DomUtil.removeClasses = function(el, names) { LDomUtilApplyClassesMethod('removeClass', el, names); }
+})();