194 lines
5.9 KiB
JavaScript
194 lines
5.9 KiB
JavaScript
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 = 'control-locate',
|
|
container = L.DomUtil.create('div', className);
|
|
|
|
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', 'control-button', container);
|
|
link.innerHTML = "<span class='icon geolocate'></span>";
|
|
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) {
|
|
L.DomUtil.addClass(self._container, "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;
|
|
|
|
L.DomUtil.removeClass(self._container, "requesting");
|
|
L.DomUtil.addClass(self._container, "active");
|
|
};
|
|
|
|
var resetVariables = function() {
|
|
self._active = false;
|
|
self._locateOnNextLocationFound = true;
|
|
};
|
|
|
|
resetVariables();
|
|
|
|
var stopLocate = function() {
|
|
_log('stopLocate');
|
|
map.stopLocate();
|
|
|
|
L.DomUtil.removeClass(self._container, "requesting");
|
|
L.DomUtil.removeClass(self._container, "active");
|
|
|
|
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);
|
|
};
|