0
# Location Services
1
2
Geolocation API integration providing location access and monitoring capabilities for web environments using the browser's native Geolocation API with Mini Program compatibility.
3
4
## Capabilities
5
6
### Get Current Location
7
8
Retrieve the device's current geographical location with configurable accuracy and coordinate system options.
9
10
```typescript { .api }
11
/**
12
* Get current device location
13
* @param options - Location retrieval configuration
14
* @returns Promise resolving to current location coordinates
15
*/
16
function getLocation(options: LocationOption): Promise<LocationResult>;
17
18
interface LocationOption extends CallbackOptions {
19
/** Coordinate system type (default: 'wgs84') */
20
type?: 'wgs84' | 'gcj02';
21
/** Whether to include altitude information (default: false) */
22
altitude?: boolean;
23
/** Use high accuracy mode (default: false) */
24
isHighAccuracy?: boolean;
25
/** High accuracy timeout in milliseconds (default: 3000) */
26
highAccuracyExpireTime?: number;
27
/** Overall operation timeout in milliseconds (default: 5000) */
28
timeout?: number;
29
/** Cache valid time in milliseconds (default: 0, no cache) */
30
cacheTime?: number;
31
}
32
33
interface LocationResult {
34
/** Latitude coordinate */
35
latitude: number;
36
/** Longitude coordinate */
37
longitude: number;
38
/** Movement speed in m/s */
39
speed: number;
40
/** Location accuracy in meters */
41
accuracy: number;
42
/** Altitude in meters (if altitude: true) */
43
altitude: number;
44
/** Vertical accuracy in meters (if altitude: true) */
45
verticalAccuracy: number;
46
/** Horizontal accuracy in meters */
47
horizontalAccuracy: number;
48
/** Location acquisition timestamp */
49
timestamp?: number;
50
}
51
```
52
53
**Usage Examples:**
54
55
```typescript
56
import { getLocation } from "@tarojs/taro-h5";
57
58
// Basic location retrieval
59
async function getCurrentPosition() {
60
try {
61
const location = await getLocation({
62
type: 'wgs84',
63
isHighAccuracy: true
64
});
65
66
console.log(`Latitude: ${location.latitude}`);
67
console.log(`Longitude: ${location.longitude}`);
68
console.log(`Accuracy: ${location.accuracy}m`);
69
70
return location;
71
} catch (error) {
72
console.error('Failed to get location:', error);
73
throw error;
74
}
75
}
76
77
// High-precision location with altitude
78
const preciseLoc = await getLocation({
79
type: 'wgs84',
80
altitude: true,
81
isHighAccuracy: true,
82
highAccuracyExpireTime: 10000,
83
timeout: 15000
84
});
85
86
console.log(`Position: ${preciseLoc.latitude}, ${preciseLoc.longitude}`);
87
console.log(`Altitude: ${preciseLoc.altitude}m ±${preciseLoc.verticalAccuracy}m`);
88
console.log(`Speed: ${preciseLoc.speed} m/s`);
89
90
// Location with Chinese coordinate system (GCJ-02)
91
const chinaLocation = await getLocation({
92
type: 'gcj02', // Chinese coordinate system
93
isHighAccuracy: false,
94
timeout: 8000
95
});
96
97
// Location with callbacks
98
getLocation({
99
type: 'wgs84',
100
isHighAccuracy: true,
101
success: (location) => {
102
console.log('Location obtained:', location);
103
displayLocationOnMap(location);
104
},
105
fail: (error) => {
106
console.error('Location failed:', error);
107
showLocationError();
108
},
109
complete: () => {
110
console.log('Location request completed');
111
}
112
});
113
```
114
115
### Location Picker
116
117
Allow users to select a location from a map interface or location picker.
118
119
```typescript { .api }
120
/**
121
* Open location picker for user selection
122
* @param options - Location picker configuration
123
* @returns Promise resolving to selected location
124
*/
125
function chooseLocation(options: ChooseLocationOption): Promise<LocationResult>;
126
127
interface ChooseLocationOption extends CallbackOptions {
128
/** Initial latitude for map center */
129
latitude?: number;
130
/** Initial longitude for map center */
131
longitude?: number;
132
/** Map zoom level (1-20, default: 15) */
133
scale?: number;
134
/** Location name search keyword */
135
keyword?: string;
136
}
137
```
138
139
**Usage Examples:**
140
141
```typescript
142
import { chooseLocation } from "@tarojs/taro-h5";
143
144
// Open location picker
145
async function selectLocation() {
146
try {
147
const selectedLocation = await chooseLocation({
148
latitude: 39.908823,
149
longitude: 116.39747,
150
scale: 15
151
});
152
153
console.log('Selected location:', selectedLocation);
154
return selectedLocation;
155
} catch (error) {
156
console.log('User cancelled location selection');
157
return null;
158
}
159
}
160
161
// Location picker with search
162
const searchLocation = await chooseLocation({
163
keyword: 'coffee shop',
164
scale: 16
165
});
166
167
// Location picker near current position
168
async function pickNearbyLocation() {
169
const currentLoc = await getLocation({ type: 'wgs84' });
170
171
const pickedLocation = await chooseLocation({
172
latitude: currentLoc.latitude,
173
longitude: currentLoc.longitude,
174
scale: 17
175
});
176
177
return pickedLocation;
178
}
179
```
180
181
### Open External Map
182
183
Open the selected location in an external map application for navigation or detailed viewing.
184
185
```typescript { .api }
186
/**
187
* Open location in external map application
188
* @param options - External map configuration
189
* @returns Promise that resolves when map is opened
190
*/
191
function openLocation(options: OpenLocationOption): Promise<void>;
192
193
interface OpenLocationOption extends CallbackOptions {
194
/** Target latitude (required) */
195
latitude: number;
196
/** Target longitude (required) */
197
longitude: number;
198
/** Location name/title */
199
name?: string;
200
/** Detailed address description */
201
address?: string;
202
/** Map zoom level (1-20, default: 15) */
203
scale?: number;
204
}
205
```
206
207
**Usage Examples:**
208
209
```typescript
210
import { openLocation } from "@tarojs/taro-h5";
211
212
// Open specific location in external map
213
await openLocation({
214
latitude: 39.908823,
215
longitude: 116.39747,
216
name: 'Tiananmen Square',
217
address: 'Dongcheng District, Beijing',
218
scale: 16
219
});
220
221
// Open user's selected location
222
async function openSelectedLocation(location: LocationResult) {
223
await openLocation({
224
latitude: location.latitude,
225
longitude: location.longitude,
226
name: 'Selected Location',
227
scale: 15
228
});
229
}
230
231
// Open business location with full details
232
await openLocation({
233
latitude: 40.7589,
234
longitude: -73.9851,
235
name: 'Times Square',
236
address: 'Manhattan, New York, NY 10036, USA',
237
scale: 17
238
});
239
```
240
241
### Location Monitoring
242
243
Monitor location changes in real-time for navigation or tracking applications.
244
245
```typescript { .api }
246
/**
247
* Add listener for location changes
248
* @param callback - Function called when location changes
249
*/
250
function onLocationChange(callback: LocationChangeCallback): void;
251
252
/**
253
* Remove listener for location changes
254
* @param callback - Previously registered callback function
255
*/
256
function offLocationChange(callback: LocationChangeCallback): void;
257
258
/**
259
* Add listener for location change errors
260
* @param callback - Function called when location errors occur
261
*/
262
function onLocationChangeError(callback: LocationErrorCallback): void;
263
264
/**
265
* Remove listener for location change errors
266
* @param callback - Previously registered error callback function
267
*/
268
function offLocationChangeError(callback: LocationErrorCallback): void;
269
270
/**
271
* Start location monitoring
272
* @param options - Location monitoring configuration
273
* @returns Promise that resolves when monitoring starts
274
*/
275
function startLocationUpdate(options?: LocationUpdateOption): Promise<void>;
276
277
/**
278
* Stop location monitoring
279
* @returns Promise that resolves when monitoring stops
280
*/
281
function stopLocationUpdate(): Promise<void>;
282
283
interface LocationUpdateOption {
284
/** Coordinate system type (default: 'wgs84') */
285
type?: 'wgs84' | 'gcj02';
286
/** Use high accuracy mode (default: false) */
287
isHighAccuracy?: boolean;
288
/** Update interval in milliseconds (default: 5000) */
289
interval?: number;
290
}
291
292
type LocationChangeCallback = (location: LocationResult) => void;
293
type LocationErrorCallback = (error: any) => void;
294
```
295
296
**Usage Examples:**
297
298
```typescript
299
import {
300
onLocationChange,
301
offLocationChange,
302
onLocationChangeError,
303
offLocationChangeError,
304
startLocationUpdate,
305
stopLocationUpdate
306
} from "@tarojs/taro-h5";
307
308
// Location tracking setup
309
class LocationTracker {
310
private isTracking = false;
311
private locationHistory: LocationResult[] = [];
312
313
async startTracking() {
314
if (this.isTracking) return;
315
316
// Set up event listeners
317
onLocationChange(this.handleLocationChange.bind(this));
318
onLocationChangeError(this.handleLocationError.bind(this));
319
320
try {
321
// Start location updates
322
await startLocationUpdate({
323
type: 'wgs84',
324
isHighAccuracy: true,
325
interval: 5000 // Update every 5 seconds
326
});
327
328
this.isTracking = true;
329
console.log('Location tracking started');
330
} catch (error) {
331
console.error('Failed to start location tracking:', error);
332
}
333
}
334
335
async stopTracking() {
336
if (!this.isTracking) return;
337
338
try {
339
await stopLocationUpdate();
340
341
// Remove event listeners
342
offLocationChange(this.handleLocationChange.bind(this));
343
offLocationChangeError(this.handleLocationError.bind(this));
344
345
this.isTracking = false;
346
console.log('Location tracking stopped');
347
} catch (error) {
348
console.error('Failed to stop location tracking:', error);
349
}
350
}
351
352
private handleLocationChange(location: LocationResult) {
353
console.log('Location updated:', location);
354
355
// Store location history
356
this.locationHistory.push({
357
...location,
358
timestamp: Date.now()
359
});
360
361
// Keep only last 100 locations
362
if (this.locationHistory.length > 100) {
363
this.locationHistory.shift();
364
}
365
366
// Trigger custom events
367
this.onLocationUpdate(location);
368
}
369
370
private handleLocationError(error: any) {
371
console.error('Location tracking error:', error);
372
this.onLocationError(error);
373
}
374
375
// Override these methods in implementation
376
protected onLocationUpdate(location: LocationResult) {
377
// Custom location update handling
378
}
379
380
protected onLocationError(error: any) {
381
// Custom error handling
382
}
383
384
getLocationHistory(): LocationResult[] {
385
return [...this.locationHistory];
386
}
387
388
getCurrentLocation(): LocationResult | null {
389
return this.locationHistory.length > 0
390
? this.locationHistory[this.locationHistory.length - 1]
391
: null;
392
}
393
}
394
395
// Usage
396
const tracker = new LocationTracker();
397
398
// Override event handlers
399
tracker.onLocationUpdate = (location) => {
400
updateMapMarker(location);
401
calculateDistance(location);
402
};
403
404
tracker.onLocationError = (error) => {
405
showToast({
406
title: 'Location tracking error',
407
icon: 'error'
408
});
409
};
410
411
// Start tracking
412
await tracker.startTracking();
413
414
// Stop tracking after 10 minutes
415
setTimeout(() => {
416
tracker.stopTracking();
417
}, 10 * 60 * 1000);
418
```
419
420
### Advanced Location Patterns
421
422
Complex location scenarios and best practices for location-based applications.
423
424
```typescript
425
// Distance calculation utility
426
function calculateDistance(lat1: number, lon1: number, lat2: number, lon2: number): number {
427
const R = 6371; // Earth's radius in kilometers
428
const dLat = (lat2 - lat1) * Math.PI / 180;
429
const dLon = (lon2 - lon1) * Math.PI / 180;
430
const a =
431
Math.sin(dLat/2) * Math.sin(dLat/2) +
432
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
433
Math.sin(dLon/2) * Math.sin(dLon/2);
434
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
435
return R * c; // Distance in kilometers
436
}
437
438
// Geofencing implementation
439
class GeofenceManager {
440
private geofences: Map<string, Geofence> = new Map();
441
private tracker: LocationTracker;
442
443
constructor(tracker: LocationTracker) {
444
this.tracker = tracker;
445
this.tracker.onLocationUpdate = this.checkGeofences.bind(this);
446
}
447
448
addGeofence(id: string, geofence: Geofence) {
449
this.geofences.set(id, geofence);
450
}
451
452
removeGeofence(id: string) {
453
this.geofences.delete(id);
454
}
455
456
private checkGeofences(location: LocationResult) {
457
for (const [id, geofence] of this.geofences) {
458
const distance = calculateDistance(
459
location.latitude,
460
location.longitude,
461
geofence.latitude,
462
geofence.longitude
463
) * 1000; // Convert to meters
464
465
const isInside = distance <= geofence.radius;
466
const wasInside = geofence.isInside || false;
467
468
if (isInside && !wasInside) {
469
// Entered geofence
470
geofence.isInside = true;
471
geofence.onEnter?.(location, geofence);
472
} else if (!isInside && wasInside) {
473
// Exited geofence
474
geofence.isInside = false;
475
geofence.onExit?.(location, geofence);
476
} else if (isInside) {
477
// Still inside
478
geofence.onStay?.(location, geofence);
479
}
480
}
481
}
482
}
483
484
interface Geofence {
485
latitude: number;
486
longitude: number;
487
radius: number; // meters
488
name?: string;
489
isInside?: boolean;
490
onEnter?: (location: LocationResult, geofence: Geofence) => void;
491
onExit?: (location: LocationResult, geofence: Geofence) => void;
492
onStay?: (location: LocationResult, geofence: Geofence) => void;
493
}
494
495
// Location caching for performance
496
class LocationCache {
497
private cache: LocationResult | null = null;
498
private cacheTime: number = 0;
499
private readonly CACHE_DURATION = 30000; // 30 seconds
500
501
async getLocation(options?: LocationOption): Promise<LocationResult> {
502
const now = Date.now();
503
504
// Return cached location if still valid
505
if (this.cache && (now - this.cacheTime) < this.CACHE_DURATION) {
506
console.log('Returning cached location');
507
return this.cache;
508
}
509
510
try {
511
const location = await getLocation(options || { type: 'wgs84' });
512
513
// Update cache
514
this.cache = location;
515
this.cacheTime = now;
516
517
return location;
518
} catch (error) {
519
// Return cached location as fallback if available
520
if (this.cache) {
521
console.log('Using stale cached location due to error');
522
return this.cache;
523
}
524
throw error;
525
}
526
}
527
528
clearCache() {
529
this.cache = null;
530
this.cacheTime = 0;
531
}
532
}
533
534
// Permission handling utility
535
class LocationPermissionManager {
536
static async requestPermission(): Promise<boolean> {
537
if (!navigator.geolocation) {
538
console.error('Geolocation is not supported');
539
return false;
540
}
541
542
try {
543
// Test location access
544
await new Promise<GeolocationPosition>((resolve, reject) => {
545
navigator.geolocation.getCurrentPosition(resolve, reject, {
546
timeout: 10000,
547
maximumAge: 0
548
});
549
});
550
551
return true;
552
} catch (error: any) {
553
console.error('Location permission denied:', error);
554
555
if (error.code === 1) { // PERMISSION_DENIED
556
await showModal({
557
title: 'Location Permission Required',
558
content: 'This app needs location access to provide location-based features. Please enable location permissions in your browser settings.',
559
showCancel: false,
560
confirmText: 'OK'
561
});
562
}
563
564
return false;
565
}
566
}
567
568
static async checkPermissionStatus(): Promise<'granted' | 'denied' | 'prompt'> {
569
if (!navigator.permissions) {
570
return 'prompt'; // Assume permission is needed
571
}
572
573
try {
574
const permission = await navigator.permissions.query({ name: 'geolocation' });
575
return permission.state;
576
} catch {
577
return 'prompt';
578
}
579
}
580
}
581
582
// Usage examples
583
async function initializeLocationServices() {
584
// Check and request permissions
585
const hasPermission = await LocationPermissionManager.requestPermission();
586
if (!hasPermission) {
587
console.log('Location services unavailable');
588
return;
589
}
590
591
// Initialize location cache
592
const locationCache = new LocationCache();
593
594
// Initialize tracker and geofencing
595
const tracker = new LocationTracker();
596
const geofenceManager = new GeofenceManager(tracker);
597
598
// Add some geofences
599
geofenceManager.addGeofence('home', {
600
latitude: 40.7589,
601
longitude: -73.9851,
602
radius: 100,
603
name: 'Home',
604
onEnter: (location, fence) => {
605
showToast({ title: `Welcome home!`, icon: 'success' });
606
},
607
onExit: (location, fence) => {
608
showToast({ title: `Leaving home`, icon: 'none' });
609
}
610
});
611
612
geofenceManager.addGeofence('office', {
613
latitude: 40.7505,
614
longitude: -73.9934,
615
radius: 50,
616
name: 'Office',
617
onEnter: (location, fence) => {
618
showToast({ title: `Arrived at office`, icon: 'success' });
619
}
620
});
621
622
// Start tracking
623
await tracker.startTracking();
624
625
return { tracker, geofenceManager, locationCache };
626
}
627
```
628
629
## Error Handling
630
631
Location services can fail due to permissions, network issues, or device limitations.
632
633
```typescript
634
// Comprehensive error handling
635
async function safeGetLocation(options?: LocationOption): Promise<LocationResult | null> {
636
try {
637
return await getLocation(options || { type: 'wgs84', timeout: 10000 });
638
} catch (error: any) {
639
console.error('Location error:', error);
640
641
// Handle specific error types
642
if (error.code === 1) { // PERMISSION_DENIED
643
await showModal({
644
title: 'Location Access Denied',
645
content: 'Location permission is required for this feature. Please enable location access in your browser settings.',
646
showCancel: false
647
});
648
} else if (error.code === 2) { // POSITION_UNAVAILABLE
649
await showToast({
650
title: 'Location unavailable',
651
icon: 'error'
652
});
653
} else if (error.code === 3) { // TIMEOUT
654
await showToast({
655
title: 'Location request timed out',
656
icon: 'error'
657
});
658
} else {
659
await showToast({
660
title: 'Failed to get location',
661
icon: 'error'
662
});
663
}
664
665
return null;
666
}
667
}
668
```
669
670
## Types
671
672
```typescript { .api }
673
interface CallbackOptions {
674
success?: (res: any) => void;
675
fail?: (err: any) => void;
676
complete?: (res: any) => void;
677
}
678
679
type CoordinateType = 'wgs84' | 'gcj02';
680
681
interface LocationError {
682
code: number;
683
message: string;
684
}
685
686
// Geolocation error codes
687
declare const LOCATION_ERROR_CODES: {
688
PERMISSION_DENIED: 1;
689
POSITION_UNAVAILABLE: 2;
690
TIMEOUT: 3;
691
};
692
```