1 L.Control.Locate = L.Control.extend({
5 follow: false, // follow with zoom and pan the user's location
25 onLocationError: function(err) {
28 title: "Show me where I am",
29 popupText: ["You are within ", " from this point"],
30 setView: true, // automatically sets the map view to the user's location
34 onAdd: function (map) {
35 var className = 'control-locate',
36 container = L.DomUtil.create('div', className);
39 this._layer = new L.LayerGroup();
40 this._layer.addTo(map);
41 this._event = undefined;
42 // nested extend so that the first can overwrite the second
43 // and the second can overwrite the third
44 this._locateOptions = L.extend(L.extend({
45 'setView': false // have to set this to false because we have to
46 // do setView manually
47 }, this.options.locateOptions), {
48 'watch': true // if you overwrite this, visualization cannot be updated
51 var link = L.DomUtil.create('a', 'control-button', container);
52 link.innerHTML = "<span class='icon geolocate'></span>";
54 link.title = this.options.title;
56 var _log = function(data) {
57 if (self.options.debug) {
63 .on(link, 'click', L.DomEvent.stopPropagation)
64 .on(link, 'click', L.DomEvent.preventDefault)
65 .on(link, 'click', function() {
66 if (self._active && (map.getBounds().contains(self._event.latlng) || !self.options.setView)) {
69 if (self.options.setView) {
70 self._locateOnNextLocationFound = true;
73 map.locate(self._locateOptions);
77 L.DomUtil.addClass(self._container, "requesting");
83 .on(link, 'dblclick', L.DomEvent.stopPropagation);
85 var onLocationFound = function (e) {
86 _log('onLocationFound');
91 (self._event.latlng.lat != e.latlng.lat ||
92 self._event.latlng.lng != e.latlng.lng)) {
93 _log('location has changed');
98 if (self.options.follow) {
99 self._locateOnNextLocationFound = true;
105 var visualizeLocation = function() {
106 _log('visualizeLocation,' + 'setView:' + self._locateOnNextLocationFound);
108 var radius = self._event.accuracy / 2;
110 if (self._locateOnNextLocationFound) {
111 map.fitBounds(self._event.bounds);
112 self._locateOnNextLocationFound = false;
115 self._layer.clearLayers();
117 // circle with the radius of the location's accuracy
118 if (self.options.drawCircle) {
119 L.circle(self._event.latlng, radius, self.options.circleStyle)
124 if (self.options.metric) {
125 distance = radius.toFixed(0);
128 distance = (radius * 3.2808399).toFixed(0);
132 // small inner marker
133 var t = self.options.popupText;
134 L.circleMarker(self._event.latlng, self.options.markerStyle)
135 .bindPopup(t[0] + distance + " " + unit + t[1])
138 if (!self._container)
141 L.DomUtil.removeClass(self._container, "requesting");
142 L.DomUtil.addClass(self._container, "active");
145 var resetVariables = function() {
146 self._active = false;
147 self._locateOnNextLocationFound = true;
152 var stopLocate = function() {
156 L.DomUtil.removeClass(self._container, "requesting");
157 L.DomUtil.removeClass(self._container, "active");
161 self._layer.clearLayers();
165 var onLocationError = function (err) {
166 _log('onLocationError');
168 // ignore timeout error if the location is watched
169 if (err.code==3 && this._locateOptions.watch) {
174 self.options.onLocationError(err);
178 map.on('locationfound', onLocationFound, self);
179 map.on('locationerror', onLocationError, self);
185 L.Map.addInitHook(function () {
186 if (this.options.locateControl) {
187 this.locateControl = L.control.locate();
188 this.addControl(this.locateControl);
192 L.control.locate = function (options) {
193 return new L.Control.Locate(options);