1/* 2Copyright (c) 2014 Dominik Moritz 3 4This file is part of the leaflet locate control. It is licensed under the MIT license. 5You can find the project at: https://github.com/domoritz/leaflet-locatecontrol 6*/ 7L.Control.Locate = L.Control.extend({ 8 options: { 9 position: 'topleft', 10 drawCircle: true, 11 follow: false, // follow with zoom and pan the user's location 12 stopFollowingOnDrag: false, // if follow is true, stop following when map is dragged (deprecated) 13 // range circle 14 circleStyle: { 15 color: '#136AEC', 16 fillColor: '#136AEC', 17 fillOpacity: 0.15, 18 weight: 2, 19 opacity: 0.5 20 }, 21 // inner marker 22 markerStyle: { 23 color: '#136AEC', 24 fillColor: '#2A93EE', 25 fillOpacity: 0.7, 26 weight: 2, 27 opacity: 0.9, 28 radius: 5 29 }, 30 // changes to range circle and inner marker while following 31 // it is only necessary to provide the things that should change 32 followCircleStyle: {}, 33 followMarkerStyle: { 34 //color: '#FFA500',
35 //fillColor: '#FFB000' 36 }, 37 circlePadding: [0, 0], 38 metric: true, 39 onLocationError: function(err) { 40 // this event is called in case of any location error 41 // that is not a time out error. 42 alert(err.message); 43 }, 44 onLocationOutsideMapBounds: function(control) { 45 // this event is repeatedly called when the location changes 46 control.stopLocate(); 47 alert(context.options.strings.outsideMapBoundsMsg); 48 }, 49 setView: true, // automatically sets the map view to the user's location 50 strings: { 51 title: "Show me where I am", 52 popup: "You are within {distance} {unit} from this point", 53 outsideMapBoundsMsg: "You seem located outside the boundaries of the map" 54 }, 55 locateOptions: { 56 maxZoom: Infinity, 57 watch: true // if you overwrite this, visualization cannot be updated 58 } 59 }, 60 61 onAdd: function (map) { 62 var container = L.DomUtil.create('div', 63 'leaflet-control-locate leaflet-bar leaflet-control'); 64 65 var self = this; 66 this._layer = new L.LayerGroup(); 67 this._layer.addTo(map); 68 this._event = undefined; 69 70 this._locateOptions = this.options.locateOptions; 71 L.extend(this._locateOptions, this.options.locateOptions); 72 L.extend(this._locateOptions, { 73 setView: false // have to set this to false because we have to 74 // do setView manually 75 }); 76 77 // extend the follow marker style and circle from the normal style 78 var tmp = {}; 79 L.extend(tmp, this.options.markerStyle, this.options.followMarkerStyle); 80 this.options.followMarkerStyle = tmp; 81 tmp = {}; 82 L.extend(tmp, this.options.circleStyle, this.options.followCircleStyle); 83 this.options.followCircleStyle = tmp; 84 85 var link = L.DomUtil.create('a', 'leaflet-bar-part leaflet-bar-part-single', container); 86 link.href = '#'; 87 link.title = this.options.strings.title; 88 89 L.DomEvent 90 .on(link, 'click', L.DomEvent.stopPropagation) 91 .on(link, 'click', L.DomEvent.preventDefault) 92 .on(link, 'click', function() { 93 if (self._active && (self._event === undefined || map.getBounds().contains(self._event.latlng) || !self.options.setView || 94 isOutsideMapBounds())) { 95 stopLocate(); 96 } else { 97 locate(); 98 } 99 }) 100 .on(link, 'dblclick', L.DomEvent.stopPropagation); 101 102 var locate = function () { 103 if (self.options.setView) { 104 self._locateOnNextLocationFound = true; 105 } 106 if(!self._active) { 107 map.locate(self._locateOptions); 108 } 109 self._active = true; 110 if (self.options.follow) { 111 startFollowing(); 112 } 113 if (!self._event) { 114 L.DomUtil.addClass(self._container, "requesting"); 115 L.DomUtil.removeClass(self._container, "active"); 116 L.DomUtil.removeClass(self._container, "following"); 117 } else { 118 visualizeLocation(); 119 } 120 }; 121 122 var onLocationFound = function (e) { 123 // no need to do anything if the location has not changed 124 if (self._event && 125 (self._event.latlng.lat === e.latlng.lat && 126 self._event.latlng.lng === e.latlng.lng && 127 self._event.accuracy === e.accuracy)) { 128 return; 129 } 130 131 if (!self._active) { 132 return; 133 } 134 135 self._event = e; 136 137 if (self.options.follow && self._following) { 138 self._locateOnNextLocationFound = true; 139 } 140 141 visualizeLocation(); 142 }; 143 144 var startFollowing = function() { 145 map.fire('startfollowing', self); 146 self._following = true; 147 if (self.options.stopFollowingOnDrag) { 148 map.on('dragstart', stopFollowing); 149 } 150 }; 151 152 var stopFollowing = function() { 153 map.fire('stopfollowing', self); 154 self._following = false;
155 if (self.options.stopFollowingOnDrag) { 156 map.off('dragstart', stopFollowing); 157 } 158 visualizeLocation(); 159 }; 160 161 var isOutsideMapBounds = function () { 162 if (self._event === undefined) 163 return false; 164 return map.options.maxBounds && 165 !map.options.maxBounds.contains(self._event.latlng); 166 }; 167 168 var visualizeLocation = function() { 169 if (self._event.accuracy === undefined) 170 self._event.accuracy = 0; 171 172 var radius = self._event.accuracy; 173 if (self._locateOnNextLocationFound) { 174 if (isOutsideMapBounds()) { 175 self.options.onLocationOutsideMapBounds(self); 176 } else { 177 map.fitBounds(self._event.bounds, { 178 padding: self.options.circlePadding, 179 maxZoom: self._locateOptions.maxZoom 180 }); 181 } 182 self._locateOnNextLocationFound = false; 183 } 184 185 // circle with the radius of the location's accuracy 186 var style, o; 187 if (self.options.drawCircle) { 188 if (self._following) { 189 style = self.options.followCircleStyle; 190 } else { 191 style = self.options.circleStyle; 192 } 193 194 if (!self._circle) { 195 self._circle = L.circle(self._event.latlng, radius, style) 196 .addTo(self._layer); 197 } else { 198 self._circle.setLatLng(self._event.latlng).setRadius(radius); 199 for (o in style) { 200 self._circle.options[o] = style[o]; 201 } 202 } 203 } 204 205 var distance, unit; 206 if (self.options.metric) { 207 distance = radius.toFixed(0); 208 unit = "meters"; 209 } else { 210 distance = (radius * 3.2808399).toFixed(0); 211 unit = "feet"; 212 } 213 214 // small inner marker 215 var mStyle; 216 if (self._following) { 217 mStyle = self.options.followMarkerStyle; 218 } else { 219 mStyle = self.options.markerStyle; 220 } 221 222 var t = self.options.strings.popup; 223 if (!self._circleMarker) { 224 self._circleMarker = L.circleMarker(self._event.latlng, mStyle) 225 .bindPopup(L.Util.template(t, {distance: distance, unit: unit})) 226 .addTo(self._layer); 227 } else { 228 self._circleMarker.setLatLng(self._event.latlng) 229 .bindPopup(L.Util.template(t, {distance: distance, unit: unit})) 230 ._popup.setLatLng(self._event.latlng); 231 for (o in mStyle) { 232 self._circleMarker.options[o] = mStyle[o]; 233 } 234 } 235 236 if (!self._container) 237 return; 238 if (self._following) { 239 L.DomUtil.removeClass(self._container, "requesting"); 240 L.DomUtil.addClass(self._container, "active"); 241 L.DomUtil.addClass(self._container, "following"); 242 } else { 243 L.DomUtil.removeClass(self._container, "requesting"); 244 L.DomUtil.addClass(self._container, "active"); 245 L.DomUtil.removeClass(self._container, "following"); 246 } 247 }; 248 249 var resetVariables = function() { 250 self._active = false; 251 self._locateOnNextLocationFound = self.options.setView; 252 self._following = false; 253 }; 254 255 resetVariables(); 256 257 var stopLocate = function() { 258 map.stopLocate(); 259 map.off('dragstart', stopFollowing); 260 261 L.DomUtil.removeClass(self._container, "requesting"); 262 L.DomUtil.removeClass(self._container, "active"); 263 L.DomUtil.removeClass(self._container, "following"); 264 resetVariables(); 265 266 self._layer.clearLayers(); 267 self._circleMarker = undefined; 268 self._circle = undefined; 269 }; 270 271 var onLocationError = function (err) { 272 // ignore time out error if the location is watched 273 if (err.code == 3 && this._locateOptions.watch) { 274 return; 275 } 276 277 stopLocate(); 278 self.options.onLocationError(err); 279 }; 280 281 // event hooks 282 map.on('locationfound', onLocationFound, self); 283 map.on('locationerror', onLocationError, self); 284 285 // make locate functions available to outside world 286 this.locate = locate; 287 this.stopLocate = stopLocate; 288 this.stopFollowing = stopFollowing; 289 290 return container; 291 } 292}); 293 294L.Map.addInitHook(function () { 295 if (this.options.locateControl) { 296 this.locateControl = L.control.locate(); 297 this.addControl(this.locateControl); 298 } 299}); 300 301L.control.locate = function (options) { 302 return new L.Control.Locate(options); 303};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.