From 73bbee5df9f01eb927ff6d830f8e74802d0318c8 Mon Sep 17 00:00:00 2001 From: Tom MacWright Date: Mon, 10 Jun 2013 11:20:29 -0700 Subject: [PATCH] Add leaflet-locate control, invisible currently. --- app/assets/javascripts/application.js | 1 + app/assets/javascripts/browse.js | 2 +- app/assets/javascripts/index.js | 6 +- app/assets/javascripts/map.js.erb | 11 +- vendor/assets/leaflet/leaflet.locate.js | 190 ++++++++++++++++++++++++ 5 files changed, 207 insertions(+), 3 deletions(-) create mode 100644 vendor/assets/leaflet/leaflet.locate.js diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index b9d09bd82..ea29ec21c 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -6,6 +6,7 @@ //= require leaflet //= require leaflet.osm //= require leaflet.locationfilter +//= require leaflet.locate //= require i18n/translations //= require oauth //= require osm diff --git a/app/assets/javascripts/browse.js b/app/assets/javascripts/browse.js index edfb4643a..24fe5171e 100644 --- a/app/assets/javascripts/browse.js +++ b/app/assets/javascripts/browse.js @@ -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); diff --git a/app/assets/javascripts/index.js b/app/assets/javascripts/index.js index 7fad2ed23..82b6d03b8 100644 --- a/app/assets/javascripts/index.js +++ b/app/assets/javascripts/index.js @@ -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); diff --git a/app/assets/javascripts/map.js.erb b/app/assets/javascripts/map.js.erb index 2354593ff..80e77f26c 100644 --- a/app/assets/javascripts/map.js.erb +++ b/app/assets/javascripts/map.js.erb @@ -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 index 000000000..89b4e8ce4 --- /dev/null +++ b/vendor/assets/leaflet/leaflet.locate.js @@ -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); +}; -- 2.39.5