Add leaflet-locate control, invisible currently.
authorTom MacWright <tom@macwright.org>
Mon, 10 Jun 2013 18:20:29 +0000 (11:20 -0700)
committerJohn Firebaugh <john.firebaugh@gmail.com>
Thu, 18 Jul 2013 17:31:19 +0000 (10:31 -0700)
app/assets/javascripts/application.js
app/assets/javascripts/browse.js
app/assets/javascripts/index.js
app/assets/javascripts/map.js.erb
vendor/assets/leaflet/leaflet.locate.js [new file with mode: 0644]

index b9d09bd82e1921643c94a92c0802434080cd46dd..ea29ec21ca7d7deda4defa5fa9b1dd869a2b9752 100644 (file)
@@ -6,6 +6,7 @@
 //= require leaflet
 //= require leaflet.osm
 //= require leaflet.locationfilter
+//= require leaflet.locate
 //= require i18n/translations
 //= require oauth
 //= require osm
index edfb4643aef8e80216f0f087909a37a369dfe712..24fe5171e50968d2b3f6e78e567974375d0e5843 100644 (file)
@@ -60,7 +60,7 @@ $(document).ready(function () {
       return remoteEditHandler(bbox);
     });
 
-    updatelinks(params.lon, params.lat, 16, null, 
+    updatelinks(params.lon, params.lat, 16, null,
                 bbox.getWest(), bbox.getSouth(),
                 bbox.getEast(), bbox.getNorth(),
                 object);
index 7fad2ed239cc2317526cd334bbbf18aa8bc76fa6..82b6d03b8dbaaf3208095d42bbe45c3b222ece75 100644 (file)
@@ -9,7 +9,11 @@ $(document).ready(function () {
   var permalinks = $("#permalink").detach().html();
   var marker;
   var params = OSM.mapParams();
-  var map = createMap("map", {layerControl: false});
+  var map = createMap("map", {
+    layerControl: false
+  }, {
+    locateControl: true
+  });
 
   OSM.mapUI().addTo(map);
 
index 2354593ff9ed368d34d125e06c2ef76557ec6236..80e77f26ca7af5e5969c8bd4200962283e0a14f6 100644 (file)
@@ -17,7 +17,7 @@ var layers;
 var objectLayer;
 var objectLoader;
 
-function createMap(divName, options) {
+function createMap(divName, options, moreOptions) {
   if (!layers) {
     layers = [
       {
@@ -51,6 +51,8 @@ function createMap(divName, options) {
     ];
   }
 
+  moreOptions = moreOptions || {};
+
   options = $.extend({zoomControl: true, panZoomControl: true, layerControl: true}, options);
 
   map = L.map(divName, $.extend({}, options, {panControl: false, zoomsliderControl: false, maxZoom: 18}));
@@ -67,6 +69,13 @@ function createMap(divName, options) {
     map.layersControl = layersControl;
   }
 
+  if (moreOptions.locateControl) {
+    var loc = L.control.locate({
+        position: 'topright'
+    });
+    loc.addTo(map);
+  }
+
   for (var i = 0; i < layers.length; i++) {
     layers[i].layer = new (layers[i].klass)(layers[i]);
     layersControl.addBaseLayer(layers[i].layer, layers[i].name);
diff --git a/vendor/assets/leaflet/leaflet.locate.js b/vendor/assets/leaflet/leaflet.locate.js
new file mode 100644 (file)
index 0000000..89b4e8c
--- /dev/null
@@ -0,0 +1,190 @@
+L.Control.Locate = L.Control.extend({
+    options: {
+        position: 'topleft',
+        drawCircle: true,
+        follow: false,  // follow with zoom and pan the user's location
+        // range circle
+        circleStyle: {
+                color: '#136AEC',
+                fillColor: '#136AEC',
+                fillOpacity: 0.15,
+                weight: 2,
+                opacity: 0.5
+            },
+        // inner marker
+        markerStyle: {
+            color: '#136AEC',
+            fillColor: '#2A93EE',
+            fillOpacity: 0.7,
+            weight: 2,
+            opacity: 0.9,
+            radius: 4
+        },
+        metric: true,
+        debug: false,
+        onLocationError: function(err) {
+            alert(err.message);
+        },
+        title: "Show me where I am",
+        popupText: ["You are within ", " from this point"],
+        setView: true, // automatically sets the map view to the user's location
+        locateOptions: {}
+    },
+
+    onAdd: function (map) {
+        var className = 'leaflet-control-locate',
+            classNames = className + ' leaflet-control-zoom leaflet-bar leaflet-control',
+            container = L.DomUtil.create('div', classNames);
+
+        var self = this;
+        this._layer = new L.LayerGroup();
+        this._layer.addTo(map);
+        this._event = undefined;
+        // nested extend so that the first can overwrite the second
+        // and the second can overwrite the third
+        this._locateOptions = L.extend(L.extend({
+            'setView': false // have to set this to false because we have to
+                             // do setView manually
+        }, this.options.locateOptions), {
+            'watch': true  // if you overwrite this, visualization cannot be updated
+        });
+
+        var link = L.DomUtil.create('a', 'leaflet-bar-part leaflet-bar-part-single', container);
+        link.href = '#';
+        link.title = this.options.title;
+
+        var _log = function(data) {
+            if (self.options.debug) {
+                console.log(data);
+            }
+        };
+
+        L.DomEvent
+            .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)) {
+                    stopLocate();
+                } else {
+                    if (self.options.setView) {
+                        self._locateOnNextLocationFound = true;
+                    }
+                    if(!self._active) {
+                        map.locate(self._locateOptions);
+                    }
+                    self._active = true;
+                    if (!self._event) {
+                        self._container.className = classNames + " requesting";
+                    } else {
+                        visualizeLocation();
+                    }
+                }
+            })
+            .on(link, 'dblclick', L.DomEvent.stopPropagation);
+
+        var onLocationFound = function (e) {
+            _log('onLocationFound');
+
+            self._active = true;
+
+            if (self._event &&
+                (self._event.latlng.lat != e.latlng.lat ||
+                 self._event.latlng.lng != e.latlng.lng)) {
+                _log('location has changed');
+            }
+
+            self._event = e;
+
+            if (self.options.follow) {
+                self._locateOnNextLocationFound = true;
+            }
+
+            visualizeLocation();
+        };
+
+        var visualizeLocation = function() {
+            _log('visualizeLocation,' + 'setView:' + self._locateOnNextLocationFound);
+
+            var radius = self._event.accuracy / 2;
+
+            if (self._locateOnNextLocationFound) {
+                map.fitBounds(self._event.bounds);
+                self._locateOnNextLocationFound = false;
+            }
+
+            self._layer.clearLayers();
+
+            // circle with the radius of the location's accuracy
+            if (self.options.drawCircle) {
+                L.circle(self._event.latlng, radius, self.options.circleStyle)
+                    .addTo(self._layer);
+            }
+
+            var distance, unit;
+            if (self.options.metric) {
+                distance = radius.toFixed(0);
+                unit = "meters";
+            } else {
+                distance = (radius * 3.2808399).toFixed(0);
+                unit = "feet";
+            }
+
+            // small inner marker
+            var t = self.options.popupText;
+            L.circleMarker(self._event.latlng, self.options.markerStyle)
+                .bindPopup(t[0] + distance + " " + unit  + t[1])
+                .addTo(self._layer);
+
+            if (!self._container)
+                return;
+            self._container.className = classNames + " active";
+        };
+
+        var resetVariables = function() {
+            self._active = false;
+            self._locateOnNextLocationFound = true;
+        };
+
+        resetVariables();
+
+        var stopLocate = function() {
+            _log('stopLocate');
+            map.stopLocate();
+
+            self._container.className = classNames;
+            resetVariables();
+
+            self._layer.clearLayers();
+        };
+
+
+        var onLocationError = function (err) {
+            _log('onLocationError');
+
+            // ignore timeout error if the location is watched
+            if (err.code==3 && this._locateOptions.watch) {
+                return;
+            }
+
+            stopLocate();
+            self.options.onLocationError(err);
+        };
+
+        // event hooks
+        map.on('locationfound', onLocationFound, self);
+        map.on('locationerror', onLocationError, self);
+
+        return container;
+    }
+});
+
+L.Map.addInitHook(function () {
+    if (this.options.locateControl) {
+        this.locateControl = L.control.locate();
+        this.addControl(this.locateControl);
+    }
+});
+
+L.control.locate = function (options) {
+    return new L.Control.Locate(options);
+};