UNPKG

npmap.js

Version:

A JavaScript web mapping library, built as a Leaflet plugin, for the National Park Service.

272 lines (235 loc) 7.28 kB
/* global alert, L */ 'use strict'; var LocateControl = L.Control.extend({ options: { circlePadding: [0, 0], circleStyle: { clickable: false, color: '#136aec', fillColor: '#136aec', fillOpacity: 0.15, opacity: 0.5, weight: 2 }, drawCircle: true, follow: false, followCircleStyle: {}, followMarkerStyle: {}, locateOptions: {}, markerStyle: { clickable: false, color: '#136aec', fillColor: '#2a93ee', fillOpacity: 0.7, opacity: 0.9, radius: 5, weight: 2 }, metric: true, onLocationError: function(context, error) { context._map.notify.danger(error.message); }, onLocationOutsideMapBounds: function(context) { context._map.notify.danger(context.options.strings.outsideMapBoundsMsg); }, position: 'topleft', setView: true, stopFollowingOnDrag: true, strings: { outsideMapBoundsMsg: 'You seem to be located outside of the boundaries of the map', popup: 'You are within {distance} {unit} of this point', title: 'Show me where I am' } }, onAdd: function (map) { var me = this, obj = {}; this._container = L.DomUtil.create('div', 'npmap-control-locate leaflet-bar leaflet-control'); this._event = undefined; this._layer = new L.LayerGroup().addTo(map); this._locateOptions = { watch: true }; this._map = map; L.extend(this._locateOptions, this.options.locateOptions); L.extend(this._locateOptions, { setView: false }); L.extend(obj, this.options.markerStyle, this.options.followMarkerStyle); this.options.followMarkerStyle = obj; obj = {}; L.extend(obj, this.options.circleStyle, this.options.followCircleStyle); this.options.followCircleStyle = obj; me._button = L.DomUtil.create('button', 'leaflet-bar-single', this._container); me._button.title = this.options.strings.title; L.DomEvent .on(me._button, 'click', L.DomEvent.stopPropagation) .on(me._button, 'click', L.DomEvent.preventDefault) .on(me._button, 'click', function() { if (me._active && (me._event === undefined || map.getBounds().contains(me._event.latlng) || !me.options.setView || isOutsideMapBounds())) { stopLocate(); } else { locate(); } }) .on(me._button, 'dblclick', L.DomEvent.stopPropagation); function isOutsideMapBounds() { if (me._event === undefined) { return false; } return map.options.maxBounds && !map.options.maxBounds.contains(me._event.latlng); } function locate() { if (!me._event) { L.DomUtil.addClass(me._button, 'requesting'); L.DomUtil.addClass(me._button, 'pressed'); L.DomUtil.removeClass(me._button, 'following'); } else { visualizeLocation(); } if (!me._active) { map.locate(me._locateOptions); } me._active = true; if (me.options.follow) { startFollowing(); } if (me.options.setView) { me._locateOnNextLocationFound = true; } } function onLocationError(err) { if (err.code === 3 && me._locateOptions.watch) { return; } stopLocate(); me.options.onLocationError(me, err); } function onLocationFound(e) { if (me._event && (me._event.latlng.lat === e.latlng.lat && me._event.latlng.lng === e.latlng.lng && me._event.accuracy === e.accuracy)) { return; } if (!me._active) { return; } me._event = e; if (me.options.follow && me._following) { me._locateOnNextLocationFound = true; } visualizeLocation(); } function resetVariables() { me._active = false; me._following = false; me._locateOnNextLocationFound = me.options.setView; } function startFollowing() { map.fire('startfollowing'); me._following = true; if (me.options.stopFollowingOnDrag) { map.on('dragstart', stopFollowing); } } function stopFollowing() { map.fire('stopfollowing'); me._following = false; if (me.options.stopFollowingOnDrag) { map.off('dragstart', stopFollowing); } visualizeLocation(); } function stopLocate() { map.stopLocate(); map.off('dragstart', stopFollowing); L.DomUtil.removeClass(me._button, 'following'); L.DomUtil.removeClass(me._button, 'pressed'); L.DomUtil.removeClass(me._button, 'requesting'); resetVariables(); me._layer.clearLayers(); me._circleMarker = undefined; me._circle = undefined; } function visualizeLocation() { var distance, mStyle, o, radius, style, unit; if (me._event.accuracy === undefined) { me._event.accuracy = 0; } radius = me._event.accuracy; if (me._locateOnNextLocationFound) { if (isOutsideMapBounds()) { me.options.onLocationOutsideMapBounds(me); } else { map.fitBounds(me._event.bounds, { padding: me.options.circlePadding }); } me._locateOnNextLocationFound = false; } if (me.options.drawCircle) { if (me._following) { style = me.options.followCircleStyle; } else { style = me.options.circleStyle; } if (!me._circle) { me._circle = L.circle(me._event.latlng, radius, style).addTo(me._layer); } else { me._circle.setLatLng(me._event.latlng).setRadius(radius); for (o in style) { me._circle.options[o] = style[o]; } } } if (me.options.metric) { distance = radius.toFixed(0); unit = 'meters'; } else { distance = (radius * 3.2808399).toFixed(0); unit = 'feet'; } if (me._following) { mStyle = me.options.followMarkerStyle; } else { mStyle = me.options.markerStyle; } if (!me._circleMarker) { me._circleMarker = L.circleMarker(me._event.latlng, mStyle) .addTo(me._layer); } else { me._circleMarker.setLatLng(me._event.latlng); for (o in mStyle) { me._circleMarker.options[o] = mStyle[o]; } } if (!me._container) { return; } L.DomUtil.removeClass(me._button, 'requesting'); L.DomUtil.addClass(me._button, 'pressed'); if (me._following) { L.DomUtil.addClass(me._button, 'following'); } else { L.DomUtil.removeClass(me._button, 'following'); } } resetVariables(); map.on('locationerror', onLocationError, me); map.on('locationfound', onLocationFound, me); this.locate = locate; this.stopFollowing = stopFollowing; this.stopLocate = stopLocate; return this._container; } }); L.Map.addInitHook(function () { if (this.options.locateControl) { var options = {}; if (typeof this.options.locateControl === 'object') { options = this.options.locateControl; } this.locateControl = L.npmap.control.locate(options).addTo(this); } }); module.exports = function (options) { return new LocateControl(options); };