@mappedin/blue-dot 6.14.0-beta.0 → 6.16.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +318 -50
- package/lib/esm/chunk-6CKF32RL.js +1 -0
- package/lib/esm/chunk-QGW5474Z.js +1 -0
- package/lib/esm/debug/index.d.ts +3039 -0
- package/lib/esm/debug/index.js +1 -0
- package/lib/esm/index.d.ts +1324 -1
- package/lib/esm/index.js +1 -1
- package/lib/esm/react/index.d.ts +1323 -0
- package/lib/esm/react/index.js +1 -1
- package/lib/rn/blue-dot.d.ts +131 -0
- package/lib/rn/fusion/algorithms/heading-filter.d.ts +101 -0
- package/lib/rn/fusion/algorithms/multi-sensor-ekf.d.ts +115 -0
- package/lib/rn/fusion/algorithms/types.d.ts +33 -0
- package/lib/rn/fusion/anchor-state.d.ts +70 -0
- package/lib/rn/fusion/confidence-to-noise.d.ts +23 -0
- package/lib/rn/fusion/fusion-engine.d.ts +62 -6
- package/lib/rn/fusion/types.d.ts +80 -33
- package/lib/rn/index-rn.js +2 -2
- package/lib/rn/rn/use-blue-dot-events.d.ts +3 -3
- package/lib/rn/rn/use-blue-dot.d.ts +86 -4
- package/lib/rn/sensors/manual/manual-sensor.d.ts +143 -0
- package/lib/rn/sensors/sensor-registry.d.ts +7 -0
- package/lib/rn/sensors/types.d.ts +1 -1
- package/lib/rn/types.d.ts +13 -0
- package/package.json +14 -7
- package/lib/esm/chunk-WFO74ZTR.js +0 -1
package/README.md
CHANGED
|
@@ -33,20 +33,26 @@ blueDot.enable();
|
|
|
33
33
|
// Listening to device position updates from the browser
|
|
34
34
|
blueDot.watchDevicePosition(true);
|
|
35
35
|
|
|
36
|
-
//
|
|
37
|
-
blueDot.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
// Optional
|
|
43
|
-
accuracy,
|
|
44
|
-
// Optional heading in degrees from north
|
|
45
|
-
heading,
|
|
46
|
-
// Optional floor or floor ID
|
|
47
|
-
floorOrFloorId,
|
|
36
|
+
// Report a position from an external source (e.g., custom IPS)
|
|
37
|
+
blueDot.reportPosition({
|
|
38
|
+
latitude: 43.6532,
|
|
39
|
+
longitude: -79.3832,
|
|
40
|
+
confidence: 0.8, // 0-1 confidence score
|
|
41
|
+
heading: 90, // Optional heading in degrees
|
|
42
|
+
floorLevel: 0, // Optional floor level
|
|
48
43
|
});
|
|
49
44
|
|
|
45
|
+
// Force position to a known location (overrides all other sources)
|
|
46
|
+
blueDot.forcePosition(
|
|
47
|
+
{
|
|
48
|
+
latitude: 43.6532,
|
|
49
|
+
longitude: -79.3832,
|
|
50
|
+
heading: 90,
|
|
51
|
+
floorLevel: 0,
|
|
52
|
+
},
|
|
53
|
+
30000, // How long to hold this position in ms
|
|
54
|
+
);
|
|
55
|
+
|
|
50
56
|
// Attach the camera to the BlueDot
|
|
51
57
|
blueDot.follow('position-only');
|
|
52
58
|
```
|
|
@@ -59,7 +65,7 @@ blueDot.follow('position-only');
|
|
|
59
65
|
|
|
60
66
|
```ts
|
|
61
67
|
// Browser will prompt for permission
|
|
62
|
-
|
|
68
|
+
blueDot.watchDevicePosition(true);
|
|
63
69
|
|
|
64
70
|
// Listen for errors (including permission denied)
|
|
65
71
|
blueDot.on('error', error => {
|
|
@@ -115,7 +121,24 @@ Disable and hide the BlueDot. Stops all position tracking.
|
|
|
115
121
|
blueDot.disable();
|
|
116
122
|
```
|
|
117
123
|
|
|
118
|
-
#### `
|
|
124
|
+
#### `getState(): ReadonlyDeep<BlueDotState>`
|
|
125
|
+
|
|
126
|
+
Returns the current BlueDot configuration (radius, colors, timeout, etc.).
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
const state = blueDot.getState();
|
|
130
|
+
console.log(state.radius, state.color);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
#### `updateState(options: BlueDotUpdateState): void`
|
|
134
|
+
|
|
135
|
+
Update BlueDot options after it has been enabled (e.g. colors, timeout, accuracy threshold).
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
blueDot.updateState({ color: '#ff0000', timeout: 60000 });
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### `watchDevicePosition(watch: boolean): void`
|
|
119
142
|
|
|
120
143
|
Start or stop listening to device GPS position.
|
|
121
144
|
|
|
@@ -124,8 +147,8 @@ Start or stop listening to device GPS position.
|
|
|
124
147
|
- Emits `error` events on geolocation errors
|
|
125
148
|
|
|
126
149
|
```ts
|
|
127
|
-
|
|
128
|
-
|
|
150
|
+
blueDot.watchDevicePosition(true); // Start tracking
|
|
151
|
+
blueDot.watchDevicePosition(false); // Stop tracking
|
|
129
152
|
```
|
|
130
153
|
|
|
131
154
|
#### `watchDeviceOrientation(watch: boolean): Promise<void>`
|
|
@@ -143,9 +166,61 @@ button.addEventListener('click', async () => {
|
|
|
143
166
|
});
|
|
144
167
|
```
|
|
145
168
|
|
|
146
|
-
#### `
|
|
169
|
+
#### `reportPosition(options)`
|
|
170
|
+
|
|
171
|
+
Report a position from an external source (e.g., custom Indoor Positioning System). The position is fed into the fusion engine with a confidence score that influences how much weight it receives relative to other sources like GPS.
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
blueDot.reportPosition({
|
|
175
|
+
latitude: 43.6532,
|
|
176
|
+
longitude: -79.3832,
|
|
177
|
+
confidence: 0.8, // 0-1: higher = more influence on fused position
|
|
178
|
+
heading: 90, // Optional: degrees from north
|
|
179
|
+
floorLevel: 0, // Optional: floor level
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Parameters:
|
|
184
|
+
|
|
185
|
+
- `latitude: number` - Latitude coordinate (required)
|
|
186
|
+
- `longitude: number` - Longitude coordinate (required)
|
|
187
|
+
- `confidence?: number` - Confidence score from 0 to 1 (default: 0.5)
|
|
188
|
+
- `accuracy?: number` - Accuracy in meters
|
|
189
|
+
- `heading?: number` - Heading in degrees from north
|
|
190
|
+
- `floorLevel?: number` - Floor level
|
|
191
|
+
- `timestamp?: number` - Timestamp in milliseconds (default: Date.now())
|
|
192
|
+
|
|
193
|
+
#### `forcePosition(position, durationMs?)`
|
|
194
|
+
|
|
195
|
+
Force the BlueDot to a specific position, overriding all other data sources for a specified duration. Use this when you have an authoritative position from a calibration source like Visual Positioning (VPS) or AI Localizer.
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
blueDot.forcePosition(
|
|
199
|
+
{
|
|
200
|
+
latitude: 43.6532,
|
|
201
|
+
longitude: -79.3832,
|
|
202
|
+
heading: 90, // Optional: degrees from north
|
|
203
|
+
floorLevel: 0, // Optional: floor level
|
|
204
|
+
},
|
|
205
|
+
30000, // How long to hold (default: 30 seconds)
|
|
206
|
+
);
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Parameters:
|
|
147
210
|
|
|
148
|
-
|
|
211
|
+
- `position.latitude: number` - Latitude coordinate (required)
|
|
212
|
+
- `position.longitude: number` - Longitude coordinate (required)
|
|
213
|
+
- `position.heading?: number` - Heading in degrees from north
|
|
214
|
+
- `position.floorLevel?: number` - Floor level
|
|
215
|
+
- `durationMs?: number` - Duration in milliseconds (default: 30000)
|
|
216
|
+
|
|
217
|
+
During the forced period, GPS and other position sources are ignored. After expiration, the BlueDot transitions back to using fused position data. Emits `anchor-set` when activated and `anchor-expired` when the duration ends.
|
|
218
|
+
|
|
219
|
+
#### `update(position, options?)` _(deprecated)_
|
|
220
|
+
|
|
221
|
+
> **Deprecated**: Use `reportPosition()` for feeding positions into the fusion engine, or `forcePosition()` to set an authoritative position anchor.
|
|
222
|
+
|
|
223
|
+
Legacy method to manually set or override position properties.
|
|
149
224
|
|
|
150
225
|
```ts
|
|
151
226
|
// Set full position
|
|
@@ -184,11 +259,13 @@ blueDot.follow('position-and-path-direction');
|
|
|
184
259
|
blueDot.follow(false);
|
|
185
260
|
```
|
|
186
261
|
|
|
187
|
-
Camera options:
|
|
262
|
+
Camera options (`FollowCameraOptions`):
|
|
188
263
|
|
|
189
|
-
- `zoomLevel?: number` - Target zoom level
|
|
190
|
-
- `pitch?: number` - Camera pitch angle
|
|
191
|
-
- `
|
|
264
|
+
- `zoomLevel?: number` - Target zoom level (default: 21)
|
|
265
|
+
- `pitch?: number` - Camera pitch angle (default: 45)
|
|
266
|
+
- `bearing?: number` - Camera bearing in degrees (position-only mode only)
|
|
267
|
+
- `duration?: number` - Animation duration in ms (default: 1000)
|
|
268
|
+
- `easing?: 'ease-in' | 'ease-out' | 'ease-in-out' | 'linear'` - Animation easing (default: 'ease-in-out')
|
|
192
269
|
|
|
193
270
|
#### `setPositionProcessor(processor?)`
|
|
194
271
|
|
|
@@ -272,8 +349,8 @@ Fired when BlueDot status changes.
|
|
|
272
349
|
|
|
273
350
|
```ts
|
|
274
351
|
blueDot.on('status-change', event => {
|
|
275
|
-
console.log(event.status); // New status
|
|
276
|
-
console.log(event.
|
|
352
|
+
console.log(event.status); // New status: 'hidden' | 'active' | 'inactive' | 'disabled'
|
|
353
|
+
console.log(event.action); // Action that caused the change: 'timeout' | 'error' | 'position-update' | 'enable' | 'disable' | 'initialize'
|
|
277
354
|
});
|
|
278
355
|
```
|
|
279
356
|
|
|
@@ -303,7 +380,8 @@ Fired when follow mode changes.
|
|
|
303
380
|
|
|
304
381
|
```ts
|
|
305
382
|
blueDot.on('follow-change', event => {
|
|
306
|
-
console.log(event.
|
|
383
|
+
console.log(event.following); // Whether the camera is following the BlueDot
|
|
384
|
+
console.log(event.mode); // Follow mode when following: 'position-only' | 'position-and-heading' | 'position-and-path-direction'
|
|
307
385
|
});
|
|
308
386
|
```
|
|
309
387
|
|
|
@@ -327,10 +405,59 @@ blueDot.on('hover', event => {
|
|
|
327
405
|
});
|
|
328
406
|
```
|
|
329
407
|
|
|
408
|
+
### `anchor-set`
|
|
409
|
+
|
|
410
|
+
Fired when a position anchor is set via `forcePosition()` or a custom sensor.
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
blueDot.on('anchor-set', event => {
|
|
414
|
+
console.log('Anchor set:', event.anchor);
|
|
415
|
+
console.log('Position:', event.anchor.latitude, event.anchor.longitude);
|
|
416
|
+
console.log('From sensor:', event.anchor.sensorId);
|
|
417
|
+
});
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### `anchor-expired`
|
|
421
|
+
|
|
422
|
+
Fired when a position anchor expires after its duration.
|
|
423
|
+
|
|
424
|
+
```ts
|
|
425
|
+
blueDot.on('anchor-expired', event => {
|
|
426
|
+
console.log('Anchor expired:', event.anchor.sensorId);
|
|
427
|
+
// BlueDot will now use fused position data again
|
|
428
|
+
});
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
## Options
|
|
432
|
+
|
|
433
|
+
```ts
|
|
434
|
+
blueDot.on('anchor-set', event => {
|
|
435
|
+
console.log('Anchor set:', event.anchor);
|
|
436
|
+
console.log('Position:', event.anchor.latitude, event.anchor.longitude);
|
|
437
|
+
console.log('From sensor:', event.anchor.sensorId);
|
|
438
|
+
});
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### `anchor-expired`
|
|
442
|
+
|
|
443
|
+
Fired when a position anchor expires after its duration.
|
|
444
|
+
|
|
445
|
+
```ts
|
|
446
|
+
blueDot.on('anchor-expired', event => {
|
|
447
|
+
console.log('Anchor expired:', event.anchor.sensorId);
|
|
448
|
+
// BlueDot will now use fused position data again
|
|
449
|
+
});
|
|
450
|
+
```
|
|
451
|
+
|
|
330
452
|
## Options
|
|
331
453
|
|
|
454
|
+
Options for `enable()` and `updateState()`. All properties are optional. The type is exported as `BlueDotUpdateState` from `@mappedin/blue-dot`.
|
|
455
|
+
|
|
332
456
|
```ts
|
|
333
|
-
|
|
457
|
+
import type { BlueDotUpdateState } from '@mappedin/blue-dot';
|
|
458
|
+
|
|
459
|
+
// BlueDotUpdateState structure (all properties optional)
|
|
460
|
+
interface Options {
|
|
334
461
|
/**
|
|
335
462
|
* The radius of the BlueDot in pixels. The BlueDot will maintain this size clamped to a minimum of 0.35 metres.
|
|
336
463
|
* @default 10
|
|
@@ -399,12 +526,12 @@ export type BlueDotOptions = {
|
|
|
399
526
|
initialState?: 'hidden' | 'inactive';
|
|
400
527
|
/**
|
|
401
528
|
* Whether to prevent position updates outside the map bounds.
|
|
402
|
-
* @default
|
|
529
|
+
* @default true
|
|
403
530
|
*/
|
|
404
531
|
preventOutOfBounds?: boolean;
|
|
405
532
|
/**
|
|
406
|
-
* Maximum accuracy (in meters) to accept. Updates
|
|
407
|
-
* @default
|
|
533
|
+
* Maximum accuracy (in meters) to accept. Updates exceeding this value are dropped.
|
|
534
|
+
* @default 50
|
|
408
535
|
*/
|
|
409
536
|
accuracyThreshold?: number;
|
|
410
537
|
/**
|
|
@@ -412,9 +539,114 @@ export type BlueDotOptions = {
|
|
|
412
539
|
* @default false
|
|
413
540
|
*/
|
|
414
541
|
debug?: boolean;
|
|
415
|
-
}
|
|
542
|
+
}
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
## Custom Sensors
|
|
546
|
+
|
|
547
|
+
You can create custom sensors to provide position data from your own sources (e.g., BLE beacons, Wi-Fi triangulation, visual positioning). Custom sensors extend `BaseSensor` and can publish position updates or set authoritative position anchors.
|
|
548
|
+
|
|
549
|
+
### Creating a Custom Sensor
|
|
550
|
+
|
|
551
|
+
```ts
|
|
552
|
+
import { BaseSensor } from '@mappedin/blue-dot';
|
|
553
|
+
|
|
554
|
+
class MyPositioningSensor extends BaseSensor {
|
|
555
|
+
readonly id = 'my-ips';
|
|
556
|
+
readonly requiresPermission = false;
|
|
557
|
+
|
|
558
|
+
protected async start(): Promise<void> {
|
|
559
|
+
// Start your positioning system
|
|
560
|
+
this.myIps.onPosition((lat, lng, confidence) => {
|
|
561
|
+
// Publish absolute position updates via the internal event system
|
|
562
|
+
this.publish('absolute-update', {
|
|
563
|
+
sensorId: this.id,
|
|
564
|
+
update: {
|
|
565
|
+
latitude: lat,
|
|
566
|
+
longitude: lng,
|
|
567
|
+
confidence, // 0-1
|
|
568
|
+
timestamp: Date.now(),
|
|
569
|
+
},
|
|
570
|
+
});
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
protected stop(): void {
|
|
575
|
+
// Clean up your positioning system
|
|
576
|
+
this.myIps.stop();
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
async checkPermission(): Promise<'granted' | 'denied' | 'prompt' | 'unavailable'> {
|
|
580
|
+
return 'granted';
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
async requestPermission(): Promise<'granted' | 'denied' | 'prompt' | 'unavailable'> {
|
|
584
|
+
return 'granted';
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
### Setting Position Anchors from Custom Sensors
|
|
590
|
+
|
|
591
|
+
Custom sensors can set authoritative position anchors using `this.setAnchor()`. This is useful for calibration sources like Visual Positioning (VPS) or AI localization.
|
|
592
|
+
|
|
593
|
+
```ts
|
|
594
|
+
class MyLocalizerSensor extends BaseSensor {
|
|
595
|
+
readonly id = 'my-localizer';
|
|
596
|
+
readonly requiresPermission = false;
|
|
597
|
+
|
|
598
|
+
async localize(imageData: Blob): Promise<void> {
|
|
599
|
+
const result = await this.callLocalizerApi(imageData);
|
|
600
|
+
|
|
601
|
+
// Set an anchor - this overrides other position sources
|
|
602
|
+
this.setAnchor({
|
|
603
|
+
latitude: result.latitude,
|
|
604
|
+
longitude: result.longitude,
|
|
605
|
+
heading: result.bearing,
|
|
606
|
+
floorLevel: result.floor,
|
|
607
|
+
ttl: 60000, // Anchor valid for 60 seconds
|
|
608
|
+
confidence: 0.95, // High confidence
|
|
609
|
+
anchorOnlyPeriodMs: 5000, // Ignore GPS for first 5 seconds
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
clearLocalization(): void {
|
|
614
|
+
this.clearAnchor();
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// ... other required methods
|
|
618
|
+
}
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### Registering Custom Sensors
|
|
622
|
+
|
|
623
|
+
```ts
|
|
624
|
+
const blueDot = new BlueDot(mapView);
|
|
625
|
+
|
|
626
|
+
// Create and register your sensor
|
|
627
|
+
const mySensor = new MyPositioningSensor();
|
|
628
|
+
blueDot.Sensors.register(mySensor);
|
|
629
|
+
|
|
630
|
+
// Enable the sensor
|
|
631
|
+
mySensor.enable();
|
|
632
|
+
|
|
633
|
+
// Access built-in sensors via .get()
|
|
634
|
+
blueDot.Sensors.get('geolocation').enable();
|
|
635
|
+
blueDot.Sensors.get('deviceorientation').enable();
|
|
416
636
|
```
|
|
417
637
|
|
|
638
|
+
### Anchor Options
|
|
639
|
+
|
|
640
|
+
When calling `setAnchor()`, you can configure:
|
|
641
|
+
|
|
642
|
+
- `latitude: number` - Latitude coordinate (required)
|
|
643
|
+
- `longitude: number` - Longitude coordinate (required)
|
|
644
|
+
- `heading?: number` - Heading in degrees from north
|
|
645
|
+
- `floorLevel?: number` - Floor level
|
|
646
|
+
- `ttl?: number` - Time-to-live in milliseconds (default: 30000)
|
|
647
|
+
- `confidence?: number` - Confidence score 0-1 (default: 1.0)
|
|
648
|
+
- `anchorOnlyPeriodMs?: number` - Duration to ignore other sources (default: 5000)
|
|
649
|
+
|
|
418
650
|
## React Native
|
|
419
651
|
|
|
420
652
|
```tsx
|
|
@@ -442,15 +674,17 @@ function BlueDotDisplay() {
|
|
|
442
674
|
const {
|
|
443
675
|
isReady,
|
|
444
676
|
isEnabled,
|
|
445
|
-
|
|
446
|
-
|
|
677
|
+
status,
|
|
678
|
+
coordinate,
|
|
447
679
|
floor,
|
|
448
680
|
isFollowing,
|
|
449
681
|
accuracy,
|
|
450
682
|
heading,
|
|
451
683
|
enable,
|
|
452
684
|
disable,
|
|
453
|
-
update,
|
|
685
|
+
update, // Deprecated: use reportPosition or forcePosition
|
|
686
|
+
reportPosition,
|
|
687
|
+
forcePosition,
|
|
454
688
|
follow,
|
|
455
689
|
} = useBlueDot();
|
|
456
690
|
|
|
@@ -462,11 +696,11 @@ function BlueDotDisplay() {
|
|
|
462
696
|
}, []),
|
|
463
697
|
);
|
|
464
698
|
|
|
465
|
-
// Listen for
|
|
699
|
+
// Listen for status changes
|
|
466
700
|
useBlueDotEvent(
|
|
467
|
-
'
|
|
701
|
+
'status-change',
|
|
468
702
|
useCallback(event => {
|
|
469
|
-
console.log('
|
|
703
|
+
console.log('Status changed:', event.status);
|
|
470
704
|
}, []),
|
|
471
705
|
);
|
|
472
706
|
|
|
@@ -478,6 +712,21 @@ function BlueDotDisplay() {
|
|
|
478
712
|
}, []),
|
|
479
713
|
);
|
|
480
714
|
|
|
715
|
+
// Listen for anchor events (from forcePosition or custom sensors)
|
|
716
|
+
useBlueDotEvent(
|
|
717
|
+
'anchor-set',
|
|
718
|
+
useCallback(event => {
|
|
719
|
+
console.log('Anchor set from:', event.anchor.sensorId);
|
|
720
|
+
}, []),
|
|
721
|
+
);
|
|
722
|
+
|
|
723
|
+
useBlueDotEvent(
|
|
724
|
+
'anchor-expired',
|
|
725
|
+
useCallback(event => {
|
|
726
|
+
console.log('Anchor expired:', event.anchor.sensorId);
|
|
727
|
+
}, []),
|
|
728
|
+
);
|
|
729
|
+
|
|
481
730
|
useEffect(() => {
|
|
482
731
|
if (isReady && !isEnabled) {
|
|
483
732
|
// All methods are async - use await or .then()
|
|
@@ -489,15 +738,14 @@ function BlueDotDisplay() {
|
|
|
489
738
|
}
|
|
490
739
|
}, [isReady, isEnabled, enable]);
|
|
491
740
|
|
|
492
|
-
const
|
|
741
|
+
const handleReportPosition = useCallback(async () => {
|
|
493
742
|
try {
|
|
494
|
-
//
|
|
495
|
-
await
|
|
743
|
+
// Report position from external IPS
|
|
744
|
+
await reportPosition({
|
|
496
745
|
latitude: 43.6532,
|
|
497
746
|
longitude: -79.3832,
|
|
498
|
-
|
|
747
|
+
confidence: 0.8,
|
|
499
748
|
heading: 90,
|
|
500
|
-
floorOrFloorId: floor,
|
|
501
749
|
});
|
|
502
750
|
|
|
503
751
|
// Enable follow mode
|
|
@@ -505,25 +753,45 @@ function BlueDotDisplay() {
|
|
|
505
753
|
zoomLevel: 19,
|
|
506
754
|
});
|
|
507
755
|
} catch (error) {
|
|
508
|
-
console.error('Failed to
|
|
756
|
+
console.error('Failed to report position:', error);
|
|
509
757
|
}
|
|
510
|
-
}, [
|
|
758
|
+
}, [reportPosition, follow]);
|
|
759
|
+
|
|
760
|
+
const handleForcePosition = useCallback(async () => {
|
|
761
|
+
try {
|
|
762
|
+
// Force position from calibration source
|
|
763
|
+
await forcePosition(
|
|
764
|
+
{
|
|
765
|
+
latitude: 43.6532,
|
|
766
|
+
longitude: -79.3832,
|
|
767
|
+
heading: 90,
|
|
768
|
+
floorLevel: 0,
|
|
769
|
+
},
|
|
770
|
+
30000,
|
|
771
|
+
);
|
|
772
|
+
} catch (error) {
|
|
773
|
+
console.error('Failed to force position:', error);
|
|
774
|
+
}
|
|
775
|
+
}, [forcePosition]);
|
|
511
776
|
|
|
512
777
|
return (
|
|
513
778
|
<View>
|
|
514
779
|
<Text>Is Ready: {isReady ? 'Yes' : 'No'}</Text>
|
|
515
780
|
<Text>Is Enabled: {isEnabled ? 'Yes' : 'No'}</Text>
|
|
516
|
-
<Text>
|
|
781
|
+
<Text>Status: {status}</Text>
|
|
517
782
|
<Text>Following: {isFollowing ? 'Yes' : 'No'}</Text>
|
|
518
|
-
{
|
|
783
|
+
{coordinate && (
|
|
519
784
|
<Text>
|
|
520
|
-
Position: {
|
|
785
|
+
Position: {coordinate.latitude.toFixed(4)}, {coordinate.longitude.toFixed(4)}
|
|
521
786
|
</Text>
|
|
522
787
|
)}
|
|
523
788
|
{accuracy && <Text>Accuracy: {accuracy.toFixed(1)}m</Text>}
|
|
524
789
|
{heading && <Text>Heading: {heading.toFixed(0)}°</Text>}
|
|
525
|
-
<TouchableOpacity onPress={
|
|
526
|
-
<Text>
|
|
790
|
+
<TouchableOpacity onPress={handleReportPosition}>
|
|
791
|
+
<Text>Report Position & Follow</Text>
|
|
792
|
+
</TouchableOpacity>
|
|
793
|
+
<TouchableOpacity onPress={handleForcePosition}>
|
|
794
|
+
<Text>Force Position (Calibration)</Text>
|
|
527
795
|
</TouchableOpacity>
|
|
528
796
|
</View>
|
|
529
797
|
);
|
|
@@ -532,6 +800,6 @@ function BlueDotDisplay() {
|
|
|
532
800
|
|
|
533
801
|
**Key Differences from Vanilla JS:**
|
|
534
802
|
|
|
535
|
-
- **All methods are async**: `enable()`, `disable()`, `
|
|
803
|
+
- **All methods are async**: `enable()`, `disable()`, `reportPosition()`, `forcePosition()`, and `follow()` return Promises
|
|
536
804
|
- **Rich state**: Hook returns `isReady`, `state`, `position`, `floor`, `isFollowing`, `accuracy`, `heading` for real-time updates
|
|
537
|
-
- **Separate event hook**: Use `useBlueDotEvent` for listening to position-update, state-change,
|
|
805
|
+
- **Separate event hook**: Use `useBlueDotEvent` for listening to position-update, state-change, follow-change, anchor-set, and anchor-expired events
|