]> git.proxmox.com Git - extjs.git/blob - extjs/modern/modern/src/util/Geolocation.js
add extjs 6.0.1 sources
[extjs.git] / extjs / modern / modern / src / util / Geolocation.js
1 /**
2 * Provides a cross browser class for retrieving location information.
3 *
4 * Based on the [Geolocation API Specification](http://dev.w3.org/geo/api/spec-source.html)
5 *
6 * When instantiated, by default this class immediately begins tracking location information,
7 * firing a {@link #locationupdate} event when new location information is available. To disable this
8 * location tracking (which may be battery intensive on mobile devices), set {@link #autoUpdate} to `false`.
9 *
10 * When this is done, only calls to {@link #updateLocation} will trigger a location retrieval.
11 *
12 * A {@link #locationerror} event is raised when an error occurs retrieving the location, either due to a user
13 * denying the application access to it, or the browser not supporting it.
14 *
15 * The below code shows a GeoLocation making a single retrieval of location information.
16 *
17 * var geo = Ext.create('Ext.util.Geolocation', {
18 * autoUpdate: false,
19 * listeners: {
20 * locationupdate: function(geo) {
21 * alert('New latitude: ' + geo.getLatitude());
22 * },
23 * locationerror: function(geo, bTimeout, bPermissionDenied, bLocationUnavailable, message) {
24 * if(bTimeout){
25 * alert('Timeout occurred.');
26 * } else {
27 * alert('Error occurred.');
28 * }
29 * }
30 * }
31 * });
32 * geo.updateLocation();
33 */
34 Ext.define('Ext.util.Geolocation', {
35 extend: 'Ext.Evented',
36 alternateClassName: ['Ext.util.GeoLocation'],
37
38 config: {
39 /**
40 * @event locationerror
41 * Raised when a location retrieval operation failed.
42 *
43 * In the case of calling updateLocation, this event will be raised only once.
44 *
45 * If {@link #autoUpdate} is set to `true`, this event could be raised repeatedly.
46 * The first error is relative to the moment {@link #autoUpdate} was set to `true`
47 * (or this {@link Ext.util.Geolocation} was initialized with the {@link #autoUpdate} config option set to `true`).
48 * Subsequent errors are relative to the moment when the device determines that it's position has changed.
49 * @param {Ext.util.Geolocation} this
50 * @param {Boolean} timeout
51 * Boolean indicating a timeout occurred
52 * @param {Boolean} permissionDenied
53 * Boolean indicating the user denied the location request
54 * @param {Boolean} locationUnavailable
55 * Boolean indicating that the location of the device could not be determined.
56 * For instance, one or more of the location providers used in the location acquisition
57 * process reported an internal error that caused the process to fail entirely.
58 * @param {String} message An error message describing the details of the error encountered.
59 *
60 * This attribute is primarily intended for debugging and should not be used
61 * directly in an application user interface.
62 */
63
64 /**
65 * @event locationupdate
66 * Raised when a location retrieval operation has been completed successfully.
67 * @param {Ext.util.Geolocation} this
68 * Retrieve the current location information from the GeoLocation object by using the read-only
69 * properties: {@link #latitude}, {@link #longitude}, {@link #accuracy}, {@link #altitude}, {@link #altitudeAccuracy}, {@link #heading}, and {@link #speed}.
70 */
71
72 /**
73 * @cfg {Boolean} autoUpdate
74 * When set to `true`, continually monitor the location of the device (beginning immediately)
75 * and fire {@link #locationupdate} and {@link #locationerror} events.
76 */
77 autoUpdate: true,
78
79 /**
80 * @cfg {Number} frequency
81 * The frequency of each update if {@link #autoUpdate} is set to `true`.
82 */
83 frequency: 10000,
84
85 /**
86 * @cfg {Number} latitude
87 * Read-only property representing the last retrieved
88 * geographical coordinate specified in degrees.
89 * @readonly
90 */
91 latitude: null,
92
93 /**
94 * @cfg {Number} longitude
95 * Read-only property representing the last retrieved
96 * geographical coordinate specified in degrees.
97 * @readonly
98 */
99 longitude: null,
100
101 /**
102 * @cfg {Number} accuracy
103 * Read-only property representing the last retrieved
104 * accuracy level of the latitude and longitude coordinates,
105 * specified in meters.
106 *
107 * This will always be a non-negative number.
108 *
109 * This corresponds to a 95% confidence level.
110 * @readonly
111 */
112 accuracy: null,
113
114 /**
115 * @cfg {Number} altitude
116 * Read-only property representing the last retrieved
117 * height of the position, specified in meters above the ellipsoid
118 * [WGS84](http://dev.w3.org/geo/api/spec-source.html#ref-wgs).
119 * @readonly
120 */
121 altitude: null,
122
123 /**
124 * @cfg {Number} altitudeAccuracy
125 * Read-only property representing the last retrieved
126 * accuracy level of the altitude coordinate, specified in meters.
127 *
128 * If altitude is not null then this will be a non-negative number.
129 * Otherwise this returns `null`.
130 *
131 * This corresponds to a 95% confidence level.
132 * @readonly
133 */
134 altitudeAccuracy: null,
135
136 /**
137 * @cfg {Number} heading
138 * Read-only property representing the last retrieved
139 * direction of travel of the hosting device,
140 * specified in non-negative degrees between 0 and 359,
141 * counting clockwise relative to the true north.
142 *
143 * If speed is 0 (device is stationary), then this returns `NaN`.
144 * @readonly
145 */
146 heading: null,
147
148 /**
149 * @cfg {Number} speed
150 * Read-only property representing the last retrieved
151 * current ground speed of the device, specified in meters per second.
152 *
153 * If this feature is unsupported by the device, this returns `null`.
154 *
155 * If the device is stationary, this returns 0,
156 * otherwise it returns a non-negative number.
157 * @readonly
158 */
159 speed: null,
160
161 /**
162 * @cfg {Date} timestamp
163 * Read-only property representing when the last retrieved
164 * positioning information was acquired by the device.
165 * @readonly
166 */
167 timestamp: null,
168
169 //PositionOptions interface
170 /**
171 * @cfg {Boolean} allowHighAccuracy
172 * When set to `true`, provide a hint that the application would like to receive
173 * the best possible results. This may result in slower response times or increased power consumption.
174 * The user might also deny this capability, or the device might not be able to provide more accurate
175 * results than if this option was set to `false`.
176 */
177 allowHighAccuracy: false,
178
179 /**
180 * @cfg {Number} timeout
181 * The maximum number of milliseconds allowed to elapse between a location update operation
182 * and the corresponding {@link #locationupdate} event being raised. If a location was not successfully
183 * acquired before the given timeout elapses (and no other internal errors have occurred in this interval),
184 * then a {@link #locationerror} event will be raised indicating a timeout as the cause.
185 *
186 * Note that the time that is spent obtaining the user permission is **not** included in the period
187 * covered by the timeout. The `timeout` attribute only applies to the location acquisition operation.
188 *
189 * In the case of calling `updateLocation`, the {@link #locationerror} event will be raised only once.
190 *
191 * If {@link #autoUpdate} is set to `true`, the {@link #locationerror} event could be raised repeatedly.
192 * The first timeout is relative to the moment {@link #autoUpdate} was set to `true`
193 * (or this {@link Ext.util.Geolocation} was initialized with the {@link #autoUpdate} config option set to `true`).
194 * Subsequent timeouts are relative to the moment when the device determines that it's position has changed.
195 */
196 timeout: Infinity,
197
198 /**
199 * @cfg {Number} maximumAge
200 * This option indicates that the application is willing to accept cached location information whose age
201 * is no greater than the specified time in milliseconds. If `maximumAge` is set to 0, an attempt to retrieve
202 * new location information is made immediately.
203 *
204 * Setting the `maximumAge` to Infinity returns a cached position regardless of its age.
205 *
206 * If the device does not have cached location information available whose age is no
207 * greater than the specified `maximumAge`, then it must acquire new location information.
208 *
209 * For example, if location information no older than 10 minutes is required, set this property to 600000.
210 */
211 maximumAge: 0,
212
213 /**
214 * @private
215 */
216 provider : undefined
217 },
218
219 updateMaximumAge: function() {
220 if (this.watchOperation) {
221 this.updateWatchOperation();
222 }
223 },
224
225 updateTimeout: function() {
226 if (this.watchOperation) {
227 this.updateWatchOperation();
228 }
229 },
230
231 updateAllowHighAccuracy: function() {
232 if (this.watchOperation) {
233 this.updateWatchOperation();
234 }
235 },
236
237 applyProvider: function(config) {
238 if (Ext.feature.has.Geolocation) {
239 if (!config) {
240 if (navigator && navigator.geolocation) {
241 config = navigator.geolocation;
242 }
243 else if (window.google) {
244 config = google.gears.factory.create('beta.geolocation');
245 }
246 }
247 }
248 else {
249 this.fireEvent('locationerror', this, false, false, true, 'This device does not support Geolocation.');
250 }
251 return config;
252 },
253
254 updateAutoUpdate: function(newAutoUpdate, oldAutoUpdate) {
255 var me = this,
256 provider = me.getProvider();
257
258 if (oldAutoUpdate && provider) {
259 clearInterval(me.watchOperationId);
260 me.watchOperationId = null;
261 }
262
263 if (newAutoUpdate) {
264 if (!provider) {
265 me.fireEvent('locationerror', me, false, false, true, null);
266 return;
267 }
268
269 try {
270 me.updateWatchOperation();
271 }
272 catch(e) {
273 me.fireEvent('locationerror', me, false, false, true, e.message);
274 }
275 }
276 },
277
278 /**
279 * @private
280 */
281 updateWatchOperation: function() {
282 var me = this,
283 provider = me.getProvider();
284
285 // The native watchPosition method is currently broken in iOS5...
286
287 if (me.watchOperationId) {
288 clearInterval(me.watchOperationId);
289 }
290
291 function pollPosition() {
292 provider.getCurrentPosition(
293 Ext.bind(me.fireUpdate, me),
294 Ext.bind(me.fireError, me),
295 me.parseOptions()
296 );
297 }
298
299 pollPosition();
300 me.watchOperationId = Ext.interval(pollPosition, this.getFrequency());
301 },
302
303 /**
304 * Executes a onetime location update operation,
305 * raising either a {@link #locationupdate} or {@link #locationerror} event.
306 *
307 * Does not interfere with or restart ongoing location monitoring.
308 * @param {Function} callback
309 * A callback method to be called when the location retrieval has been completed.
310 *
311 * Will be called on both success and failure.
312 *
313 * The method will be passed one parameter, {@link Ext.util.Geolocation}
314 * (**this** reference), set to `null` on failure.
315 *
316 * geo.updateLocation(function (geo) {
317 * alert('Latitude: ' + (geo !== null ? geo.latitude : 'failed'));
318 * });
319 *
320 * @param {Object} [scope]
321 * The scope (**this** reference) in which the handler function is executed.
322 *
323 * **If omitted, defaults to the object which fired the event.**
324 *
325 * <!--positonOptions undocumented param, see W3C spec-->
326 */
327 updateLocation: function(callback, scope, positionOptions) {
328 var me = this,
329 provider = me.getProvider();
330
331 var failFunction = function(message, error) {
332 if (error) {
333 me.fireError(error);
334 }
335 else {
336 me.fireEvent('locationerror', me, false, false, true, message);
337 }
338 if (callback) {
339 callback.call(scope || me, null, me); //last parameter for legacy purposes
340 }
341 };
342
343 if (!provider) {
344 failFunction(null);
345 return;
346 }
347
348 try {
349 provider.getCurrentPosition(
350 //success callback
351 function(position) {
352 me.fireUpdate(position);
353 if (callback) {
354 callback.call(scope || me, me, me); //last parameter for legacy purposes
355 }
356 },
357 //error callback
358 function(error) {
359 failFunction(null, error);
360 },
361 positionOptions || me.parseOptions()
362 );
363 }
364 catch(e) {
365 failFunction(e.message);
366 }
367 },
368
369 /**
370 * @private
371 */
372 fireUpdate: function(position) {
373 var me = this,
374 coords = position.coords;
375
376 this.position = position;
377
378 me.setConfig({
379 timestamp: position.timestamp,
380 latitude: coords.latitude,
381 longitude: coords.longitude,
382 accuracy: coords.accuracy,
383 altitude: coords.altitude,
384 altitudeAccuracy: coords.altitudeAccuracy,
385 heading: coords.heading,
386 speed: coords.speed
387 });
388
389 me.fireEvent('locationupdate', me);
390 },
391
392 /**
393 * @private
394 */
395 fireError: function(error) {
396 var errorCode = error.code;
397 this.fireEvent('locationerror', this,
398 errorCode == error.TIMEOUT,
399 errorCode == error.PERMISSION_DENIED,
400 errorCode == error.POSITION_UNAVAILABLE,
401 error.message == undefined ? null : error.message
402 );
403 },
404
405 /**
406 * @private
407 */
408 parseOptions: function() {
409 var timeout = this.getTimeout(),
410 ret = {
411 maximumAge: this.getMaximumAge(),
412 enableHighAccuracy: this.getAllowHighAccuracy()
413 };
414
415 //Google doesn't like Infinity
416 if (timeout !== Infinity) {
417 ret.timeout = timeout;
418 }
419 return ret;
420 },
421
422 destroy: function() {
423 this.setAutoUpdate(false);
424 this.callParent();
425 }
426 });