Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2504 | - | 1 | L.Control.Locate = L.Control.extend({ |
2 | options: { |
||
3 | position: 'topleft', |
||
4 | drawCircle: true, |
||
5 | follow: false, // follow with zoom and pan the user's location |
||
6 | // range circle |
||
7 | circleStyle: { |
||
8 | color: '#136AEC', |
||
9 | fillColor: '#136AEC', |
||
10 | fillOpacity: 0.15, |
||
11 | weight: 2, |
||
12 | opacity: 0.5 |
||
13 | }, |
||
14 | // inner marker |
||
15 | markerStyle: { |
||
16 | color: '#136AEC', |
||
17 | fillColor: '#2A93EE', |
||
18 | fillOpacity: 0.7, |
||
19 | weight: 2, |
||
20 | opacity: 0.9, |
||
21 | radius: 4 |
||
22 | }, |
||
23 | metric: true, |
||
24 | debug: false, |
||
25 | onLocationError: function(err) { |
||
26 | alert(err.message); |
||
27 | }, |
||
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 |
||
31 | locateOptions: {} |
||
32 | }, |
||
33 | |||
34 | onAdd: function (map) { |
||
35 | var className = 'leaflet-control-locate', |
||
36 | classNames = className + ' leaflet-control-zoom leaflet-bar leaflet-control', |
||
37 | container = L.DomUtil.create('div', classNames); |
||
38 | |||
39 | var self = this; |
||
40 | this._layer = new L.LayerGroup(); |
||
41 | this._layer.addTo(map); |
||
42 | this._event = undefined; |
||
43 | // nested extend so that the first can overwrite the second |
||
44 | // and the second can overwrite the third |
||
45 | this._locateOptions = L.extend(L.extend({ |
||
46 | 'setView': false // have to set this to false because we have to |
||
47 | // do setView manually |
||
48 | }, this.options.locateOptions), { |
||
49 | 'watch': true // if you overwrite this, visualization cannot be updated |
||
50 | }); |
||
51 | |||
52 | var link = L.DomUtil.create('a', 'leaflet-bar-part leaflet-bar-part-single', container); |
||
53 | link.href = '#'; |
||
54 | link.title = this.options.title; |
||
55 | |||
56 | var _log = function(data) { |
||
57 | if (self.options.debug) { |
||
58 | console.log(data); |
||
59 | } |
||
60 | }; |
||
61 | |||
62 | L.DomEvent |
||
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)) { |
||
67 | stopLocate(); |
||
68 | } else { |
||
69 | if (self.options.setView) { |
||
70 | self._locateOnNextLocationFound = true; |
||
71 | } |
||
72 | if(!self._active) { |
||
73 | map.locate(self._locateOptions); |
||
74 | } |
||
75 | self._active = true; |
||
76 | if (!self._event) { |
||
77 | self._container.className = classNames + " requesting"; |
||
78 | } else { |
||
79 | visualizeLocation(); |
||
80 | } |
||
81 | } |
||
82 | }) |
||
83 | .on(link, 'dblclick', L.DomEvent.stopPropagation); |
||
84 | |||
85 | var onLocationFound = function (e) { |
||
86 | _log('onLocationFound'); |
||
87 | |||
88 | self._active = true; |
||
89 | |||
90 | if (self._event && |
||
91 | (self._event.latlng.lat != e.latlng.lat || |
||
92 | self._event.latlng.lng != e.latlng.lng)) { |
||
93 | _log('location has changed'); |
||
94 | } |
||
95 | |||
96 | self._event = e; |
||
97 | |||
98 | if (self.options.follow) { |
||
99 | self._locateOnNextLocationFound = true; |
||
100 | } |
||
101 | |||
102 | visualizeLocation(); |
||
103 | }; |
||
104 | |||
105 | var visualizeLocation = function() { |
||
106 | _log('visualizeLocation,' + 'setView:' + self._locateOnNextLocationFound); |
||
107 | |||
108 | var radius = self._event.accuracy / 2; |
||
109 | |||
110 | if (self._locateOnNextLocationFound) { |
||
111 | map.fitBounds(self._event.bounds); |
||
112 | self._locateOnNextLocationFound = false; |
||
113 | } |
||
114 | |||
115 | self._layer.clearLayers(); |
||
116 | |||
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) |
||
120 | .addTo(self._layer); |
||
121 | } |
||
122 | |||
123 | var distance, unit; |
||
124 | if (self.options.metric) { |
||
125 | distance = radius.toFixed(0); |
||
126 | unit = "meters"; |
||
127 | } else { |
||
128 | distance = (radius * 3.2808399).toFixed(0); |
||
129 | unit = "feet"; |
||
130 | } |
||
131 | |||
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]) |
||
136 | .addTo(self._layer); |
||
137 | |||
138 | if (!self._container) |
||
139 | return; |
||
140 | self._container.className = classNames + " active"; |
||
141 | }; |
||
142 | |||
143 | var resetVariables = function() { |
||
144 | self._active = false; |
||
145 | self._locateOnNextLocationFound = true; |
||
146 | }; |
||
147 | |||
148 | resetVariables(); |
||
149 | |||
150 | var stopLocate = function() { |
||
151 | _log('stopLocate'); |
||
152 | map.stopLocate(); |
||
153 | |||
154 | self._container.className = classNames; |
||
155 | resetVariables(); |
||
156 | |||
157 | self._layer.clearLayers(); |
||
158 | }; |
||
159 | |||
160 | |||
161 | var onLocationError = function (err) { |
||
162 | _log('onLocationError'); |
||
163 | |||
164 | // ignore timeout error if the location is watched |
||
165 | if (err.code==3 && this._locateOptions.watch) { |
||
166 | return; |
||
167 | } |
||
168 | |||
169 | stopLocate(); |
||
170 | self.options.onLocationError(err); |
||
171 | }; |
||
172 | |||
173 | // event hooks |
||
174 | map.on('locationfound', onLocationFound, self); |
||
175 | map.on('locationerror', onLocationError, self); |
||
176 | |||
177 | return container; |
||
178 | } |
||
179 | }); |
||
180 | |||
181 | L.Map.addInitHook(function () { |
||
182 | if (this.options.locateControl) { |
||
183 | this.locateControl = L.control.locate(); |
||
184 | this.addControl(this.locateControl); |
||
185 | } |
||
186 | }); |
||
187 | |||
188 | L.control.locate = function (options) { |
||
189 | return new L.Control.Locate(options); |
||
190 | }; |