From: John Firebaugh Date: Thu, 8 Aug 2013 21:06:18 +0000 (-0700) Subject: Update leaflet.locate (fixes #438) X-Git-Tag: live~4777 X-Git-Url: https://git.openstreetmap.org/rails.git/commitdiff_plain/1b2738af809843a07361b657c0b64e27732effca Update leaflet.locate (fixes #438) --- diff --git a/app/assets/javascripts/index.js b/app/assets/javascripts/index.js index 5190277c9..e46ca6d9d 100644 --- a/app/assets/javascripts/index.js +++ b/app/assets/javascripts/index.js @@ -75,7 +75,10 @@ $(document).ready(function () { L.control.locate({ position: position, - title: I18n.t('javascripts.map.locate.title') + strings: { + title: I18n.t('javascripts.map.locate.title'), + popup: I18n.t('javascripts.map.locate.popup') + } }).addTo(map); var sidebar = L.OSM.sidebar('#map-ui') diff --git a/config/locales/en.yml b/config/locales/en.yml index 697c9a747..c01abe71a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2075,6 +2075,7 @@ en: out: Zoom Out locate: title: Show My Location + popup: You are within {distance} {unit} of this point base: standard: Standard cycle_map: Cycle Map diff --git a/vendor/assets/leaflet/leaflet.locate.js b/vendor/assets/leaflet/leaflet.locate.js index 77754d84d..64fb144d4 100644 --- a/vendor/assets/leaflet/leaflet.locate.js +++ b/vendor/assets/leaflet/leaflet.locate.js @@ -1,16 +1,23 @@ +/* +Copyright (c) 2013 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 +*/ L.Control.Locate = L.Control.extend({ options: { 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 // range circle circleStyle: { - color: '#136AEC', - fillColor: '#136AEC', - fillOpacity: 0.15, - weight: 2, - opacity: 0.5 - }, + color: '#136AEC', + fillColor: '#136AEC', + fillOpacity: 0.15, + weight: 2, + opacity: 0.5 + }, // inner marker markerStyle: { color: '#136AEC', @@ -18,52 +25,70 @@ L.Control.Locate = L.Control.extend({ fillOpacity: 0.7, weight: 2, opacity: 0.9, - radius: 4 + radius: 5 + }, + // changes to range circle and inner marker while following + // it is only necessary to provide the things that should change + followCircleStyle: {}, + followMarkerStyle: { + //color: '#FFA500', + //fillColor: '#FFB000' }, metric: true, - debug: false, onLocationError: function(err) { + // this event is called in case of any location error + // that is not a time out error. alert(err.message); }, - title: "Show me where I am", - popupText: ["You are within ", " from this point"], + onLocationOutsideMapBounds: function(context) { + // this event is repeatedly called when the location changes + alert(context.options.strings.outsideMapBoundsMsg); + }, setView: true, // automatically sets the map view to the user's location + 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: {} }, onAdd: function (map) { - var className = 'control-locate', - container = L.DomUtil.create('div', className); + var container = L.DomUtil.create('div', + 'leaflet-control-locate leaflet-bar leaflet-control'); 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 + + this._locateOptions = { + watch: true // if you overwrite this, visualization cannot be updated + }; + L.extend(this._locateOptions, this.options.locateOptions); + L.extend(this._locateOptions, { + setView: false // have to set this to false because we have to + // do setView manually }); - var link = L.DomUtil.create('a', 'control-button', container); - link.innerHTML = ""; - link.href = '#'; - link.title = this.options.title; + // extend the follow marker style and circle from the normal style + var tmp = {}; + L.extend(tmp, this.options.markerStyle, this.options.followMarkerStyle); + this.options.followMarkerStyle = tmp; + tmp = {}; + L.extend(tmp, this.options.circleStyle, this.options.followCircleStyle); + this.options.followCircleStyle = tmp; - var _log = function(data) { - if (self.options.debug) { - console.log(data); - } - }; + var link = L.DomUtil.create('a', 'leaflet-bar-part leaflet-bar-part-single', container); + link.href = '#'; + link.title = this.options.strings.title; 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)) { + if (self._active && (map.getBounds().contains(self._event.latlng) || !self.options.setView || + isOutsideMapBounds())) { stopLocate(); } else { if (self.options.setView) { @@ -73,8 +98,13 @@ L.Control.Locate = L.Control.extend({ 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(); } @@ -83,41 +113,77 @@ L.Control.Locate = L.Control.extend({ .on(link, 'dblclick', L.DomEvent.stopPropagation); var onLocationFound = function (e) { - _log('onLocationFound'); - - self._active = true; - + // 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)) { - _log('location has changed'); + (self._event.latlng.lat == e.latlng.lat && + self._event.latlng.lng == e.latlng.lng)) { + return; + } + + if (!self._active) { + return; } self._event = e; - if (self.options.follow) { + if (self.options.follow && self._following) { self._locateOnNextLocationFound = true; } visualizeLocation(); }; - var visualizeLocation = function() { - _log('visualizeLocation,' + 'setView:' + self._locateOnNextLocationFound); + var startFollowing = function() { + self._following = true; + if (self.options.stopFollowingOnDrag) { + map.on('dragstart', stopFollowing); + } + }; - var radius = self._event.accuracy / 2; + var stopFollowing = function() { + self._following = false; + if (self.options.stopFollowingOnDrag) { + map.off('dragstart', stopFollowing); + } + visualizeLocation(); + }; + var isOutsideMapBounds = function () { + if (self._event === undefined) + return false; + return map.options.maxBounds && + !map.options.maxBounds.contains(self._event.latlng); + }; + + var visualizeLocation = function() { + if (self._event.accuracy === undefined) + self._event.accuracy = 0; + + var radius = self._event.accuracy; if (self._locateOnNextLocationFound) { - map.fitBounds(self._event.bounds); + if (isOutsideMapBounds()) { + self.options.onLocationOutsideMapBounds(self); + } else { + map.fitBounds(self._event.bounds); + } self._locateOnNextLocationFound = false; } - self._layer.clearLayers(); - // circle with the radius of the location's accuracy + var style; if (self.options.drawCircle) { - L.circle(self._event.latlng, radius, self.options.circleStyle) - .addTo(self._layer); + if (self._following) { + style = self.options.followCircleStyle; + } else { + style = self.options.circleStyle; + } + + if (!self._circle) { + self._circle = L.circle(self._event.latlng, radius, style) + .addTo(self._layer); + } else { + self._circle.setLatLng(self._event.latlng).setRadius(radius); + } } var distance, unit; @@ -130,43 +196,62 @@ L.Control.Locate = L.Control.extend({ } // 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); + var m; + if (self._following) { + m = self.options.followMarkerStyle; + } else { + m = self.options.markerStyle; + } + + var t = self.options.strings.popup; + if (!self._circleMarker) { + self._circleMarker = L.circleMarker(self._event.latlng, m) + .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); + } if (!self._container) return; - - L.DomUtil.removeClass(self._container, "requesting"); - L.DomUtil.addClass(self._container, "active"); + if (self._following) { + L.DomUtil.removeClass(self._container, "requesting"); + L.DomUtil.addClass(self._container, "active"); + L.DomUtil.addClass(self._container, "following"); + } else { + L.DomUtil.removeClass(self._container, "requesting"); + L.DomUtil.addClass(self._container, "active"); + L.DomUtil.removeClass(self._container, "following"); + } }; var resetVariables = function() { self._active = false; - self._locateOnNextLocationFound = true; + self._locateOnNextLocationFound = self.options.setView; + self._following = false; }; resetVariables(); var stopLocate = function() { - _log('stopLocate'); map.stopLocate(); + map.off('dragstart', stopFollowing); L.DomUtil.removeClass(self._container, "requesting"); L.DomUtil.removeClass(self._container, "active"); - + L.DomUtil.removeClass(self._container, "following"); resetVariables(); self._layer.clearLayers(); + self._circleMarker = undefined; + self._circle = undefined; }; - var onLocationError = function (err) { - _log('onLocationError'); - - // ignore timeout error if the location is watched - if (err.code==3 && this._locateOptions.watch) { + // ignore time out error if the location is watched + if (err.code == 3 && this._locateOptions.watch) { return; }