import type { Floor, MapView, Model } from '@mappedin/mappedin-js'; import { Coordinate } from '@mappedin/mappedin-js'; import type { BrowserPermissionState } from '@packages/internal/common/browser'; import type { MapViewExtension } from '@packages/internal/common/extensions'; import type { BlueDotEventPayloads, BlueDotState, BlueDotPositionProcessor, BlueDotPositionUpdate, BlueDotUpdateOptions, FollowCameraOptions, GeolocationPositionExtended, BlueDotUpdateState } from './types'; import type { ReadonlyDeep } from 'type-fest'; import { FollowMode } from './follow/types'; import { BlueDotStatus } from './status/types'; import { SensorRegistry } from './sensors/sensor-registry'; import { FusionEngine } from './fusion/fusion-engine'; import type { ManualPositionOptions } from './sensors/manual/manual-sensor'; /** * Show a Blue Dot indicating the device's position on the map. * * @example * ```ts * import { show3dMap } from '@mappedin/mappedin-js'; * import { BlueDot } from '@mappedin/blue-dot'; * * const mapView = await show3dMap(...); * * // Enable BlueDot * const blueDot = new BlueDot(mapView).enable(); * * // Option 1: Listen for position updates from the device * blueDot.on('position-update', (position) => { * console.log('User position:', position); * }); * * // Option 2: Update position manually * blueDot.update({ latitude, longitude, accuracy, floorOrFloorId }); * * ``` */ export declare class BlueDot implements MapViewExtension { #private; /** * Create a new {@link BlueDot} instance. */ constructor(mapView: MapView); /** Sensors API */ get Sensors(): SensorRegistry; /** * Fusion engine API. * @internal Used by debug tools for runtime tuning and inspection. */ get Fusion(): FusionEngine; /** * Get the current position anchor if one is set and not expired. * Anchors provide absolute ground truth positions from calibration sources (VPS, AI Localizer). */ get anchor(): Readonly | undefined; /** * Get the current accumulated displacement from the anchor in meters. * Returns { dx: 0, dy: 0 } if no anchor is set or no movement has occurred. */ get displacement(): Readonly; /** * Get the Model for the BlueDot core element. */ get dotModel(): Model | undefined; /** * Get the Model for the accuracy ring. */ get accuracyRingModel(): Model | undefined; /** * Get the Model for the heading cone. */ get headingConeModel(): Model | undefined; /** * Whether the BlueDot is currently enabled. */ get isEnabled(): boolean; /** * The current state of the BlueDot. Can be 'hidden', 'active', 'inactive', or 'disabled'. * Listen for state changes using the 'status-change' event. * * @example * mapView.BlueDot.on('status-change', ({ status }) => { * if (status === 'active') { * // BlueDot is visible and tracking * } * }); */ get status(): BlueDotStatus; /** * Whether the BlueDot is currently following the user (camera follow mode). */ get isFollowing(): boolean; /** * The direction the user is facing in degrees from north clockwise. * @see https://developer.mozilla.org/en-US/docs/Web/API/GeolocationCoordinates/heading */ get heading(): GeolocationPosition['coords']['heading'] | undefined; /** * The accuracy of the current position in metres. */ get accuracy(): GeolocationPosition['coords']['accuracy'] | undefined; /** * The coordinate of the current position. */ get coordinate(): Coordinate | undefined; /** * Returns the current Blue Dot state. */ getState(): ReadonlyDeep; /** * The floor the Blue Dot is currently on. If undefined, the Blue Dot will appear on every floor. */ get floor(): Floor | undefined; /** * Force the Blue Dot to a specific position for a duration, overriding all other sensors. * * This sets a high-confidence anchor that completely dominates the fusion engine * for the specified duration. GPS, compass, and other sensors are ignored while * the forced position is active. After the duration expires, normal sensor fusion resumes. * * Use this when you have an authoritative position from an external system * (e.g., VPS, QR code scan, manual user correction) that should override everything else. * * @param position - The position to force * @param durationMs - How long to maintain this position in milliseconds (default: 30 seconds) * * @example Force position from VPS scan * ```ts * blueDot.forcePosition({ * latitude: 43.4723, * longitude: -80.5449, * heading: 90, * floorLevel: 2, * }, 30000); // 30 seconds * ``` * * @example Force position indefinitely (call again with different position or let it expire) * ```ts * blueDot.forcePosition({ * latitude: 43.4723, * longitude: -80.5449, * }, Infinity); * ``` */ forcePosition(position: { latitude: number; longitude: number; heading?: number; floorLevel?: number; }, durationMs?: number): void; /** * Report a position to the fusion engine with a confidence score. * * Unlike {@link forcePosition}, this does NOT override other sensors. Instead, * the reported position is weighted by confidence and combined with GPS, compass, * and other active sensors through the fusion engine. * * Use this for integrating external positioning systems (IPS, beacons, WiFi RTT) * that should contribute to but not dominate the fused position. * * @param options - Position data with confidence score * * @example Simple IPS integration * ```ts * // Low confidence - will blend with GPS * blueDot.reportPosition({ * latitude: 43.4723, * longitude: -80.5449, * accuracy: 10, * confidence: 0.3, * }); * ``` * * @example High confidence beacon * ```ts * // High confidence - will dominate over GPS * blueDot.reportPosition({ * latitude: 43.4723, * longitude: -80.5449, * accuracy: 2, * confidence: 0.95, * }); * ``` */ reportPosition(options: ManualPositionOptions): void; /** * Enable a sensor by ID and request permissions if needed. * @param sensorId - The ID of the sensor to enable * @returns The permission state after enabling */ __enableSensor(sensorId: string): Promise; /** * Disable a sensor by ID. * @param sensorId - The ID of the sensor to disable */ __disableSensor(sensorId: string): void; /** * Check the current permission state for a sensor. * @param sensorId - The ID of the sensor to check * @returns The current permission state */ __checkSensorPermission(sensorId: string): Promise; /** * Request permission for a sensor. Must be called in response to a user gesture. * @param sensorId - The ID of the sensor * @returns The permission state after requesting */ __requestSensorPermission(sensorId: string): Promise; /** * Check if a sensor is currently enabled. * @param sensorId - The ID of the sensor to check * @returns Whether the sensor is enabled */ __isSensorEnabled(sensorId: string): boolean; /** * Enable the Blue Dot. It will be hidden until a position is received either from the browser or by calling {@link BlueDot.update}. * @param options - The options to setup the Blue Dot (see {@link BlueDotUpdateState}). * * @example Enable with default options * ```ts * const blueDot = new BlueDot(mapView); * blueDot.enable(); * ``` * @example Enable with custom color and accuracy ring * ```ts * const blueDot = new BlueDot(mapView); * blueDot.enable({ color: '#00ff00', accuracyRing: { color: '#00ff00', opacity: 0.2 } }); * ``` * * @see See the [BlueDot Guide](https://developer.mappedin.com/web-sdk/blue-dot) for more information. */ enable: (options?: BlueDotUpdateState) => void; /** * Disable the Blue Dot. It will be hidden and no longer update. * * The status transition to 'disabled' occurs after all cleanup operations complete. * This ensures that any 'status-change' event listeners see the BlueDot in a fully * cleaned up state with all resources released. */ disable: () => void; /** * Subscribe to a BlueDot event. * @param eventName The name of the event to listen for. * @param fn The function to call when the event is emitted. */ on: (eventName: BlueDotEventName, fn: (payload: BlueDotEventPayloads[BlueDotEventName] extends { data: null; } ? BlueDotEventPayloads[BlueDotEventName]["data"] : BlueDotEventPayloads[BlueDotEventName]) => void) => () => void; /** * Unsubscribe from a BlueDot event. * @param eventName The name of the event to unsubscribe from. * @param fn The function to unsubscribe from the event. */ off: (eventName: BlueDotEventName, fn: (payload: BlueDotEventPayloads[BlueDotEventName] extends { data: null; } ? BlueDotEventPayloads[BlueDotEventName]["data"] : BlueDotEventPayloads[BlueDotEventName]) => void) => void; /** * Update the BlueDot state after it has been enabled. * This allows overriding previously set values like colors, and other options. * @param options - The options to update * * @example Update color and accuracy ring * ```ts * const blueDot = new BlueDot(mapView); * blueDot.updateState({ * color: '#ff0000', * accuracyRing: { color: '#ff0000', opacity: 0.5 } * }); * ``` */ updateState: (options: BlueDotUpdateState) => void; /** * Enable or disable the devices's geolocation listener to automatically position the Blue Dot. * If enabled, the device will request permission to access the user's precise location. * * @remarks This will emit a 'position-update' event every time a new position is received. * @deprecated Use the {@link BlueDot.Sensors} API and fusion engine for position updates instead. * * @param watch - Whether to enable or disable the listener. */ watchDevicePosition: (watch: boolean) => void; /** * Enable or disable the device orientation listener to automatically update the Blue Dot's heading. * This must be enabled in response to a user action such as a tap or click and cannot be enabled automatically. * * @remarks This will emit a 'device-orientation-update' event every time the device's orientation changes. * Device orientation changes will not emit a 'position-update' event. * @deprecated Use the {@link BlueDot.Sensors} API and fusion engine for heading updates instead. * * @see https://www.w3.org/TR/orientation-event/#dom-deviceorientationevent-requestpermission * * @param watch - Whether to enable or disable the listener. * * @example Enable device orientation listener * ```ts * const blueDot = new BlueDot(mapView); * // Enable device orientation on button click * button.addEventListener('click', () => { * blueDot.watchDeviceOrientation(true); * }); * ``` */ watchDeviceOrientation: (watch: boolean) => Promise; /** * Set the Blue Dot position to specific coordinates or override some properties of the device geolocation. * * @deprecated Use {@link forcePosition} to set an authoritative position that overrides all sensors, * or {@link reportPosition} to feed a confidence-weighted position into the fusion engine. * * @remarks If `floorLevel` is provided with {@link GeolocationPositionExtended}, the floor will be resolved asynchronously and the position will not be applied until this is completed. * * @param position - The position to set. Use {@link BlueDotPositionUpdate} for manual positioning, * a GeolocationPosition object, or undefined to clear the manual position. * @param options - Optional update options (silent, animate). * * @example Set position with floor * ```ts * blueDot.update({ * latitude: 43.123, * longitude: -79.456, * accuracy: 5, * floorOrFloorId: floor * }); * ``` * @example Clear manual position properties and return to device geolocation * ```ts * blueDot.update(undefined); * ``` */ update: (position: GeolocationPositionExtended | BlueDotPositionUpdate | undefined, options?: BlueDotUpdateOptions) => void; /** * Set the camera to follow the BlueDot in various modes. User interaction will cancel following automatically. * @param mode The follow mode ('position-only', 'position-and-heading', 'position-and-path-direction', or false to disable). * @param cameraOptions Optional camera options (zoom, pitch, etc.). * * @example * mapView.BlueDot.follow('position-and-heading', { zoomLevel: 21, pitch: 45 }); */ follow: (mode: FollowMode, cameraOptions?: FollowCameraOptions) => void; /** * Set a position processor callback that allows intercepting and modifying device/geolocation position updates before they are applied. * * **Note**: This processor only applies to automatic position updates from device geolocation. * Manual position updates via `update()` method bypass the processor and are applied directly. * * @param processor - A callback function that receives current state and incoming update. Return undefined to discard the update, or return a modified update object. * * @example Discard inaccurate positions * ```ts * blueDot.setPositionProcessor((current, incoming) => { * if (incoming.accuracy && incoming.accuracy > 50) { * return undefined; // Discard update * } * return incoming; // Accept update * }); * ``` * * @example Modify incoming positions * ```ts * blueDot.setPositionProcessor((current, incoming) => { * // Apply custom smoothing or validation logic * return { * ...incoming, * accuracy: Math.min(incoming.accuracy || 100, 10) // Cap accuracy * }; * }); * ``` */ setPositionProcessor(processor?: BlueDotPositionProcessor): void; destroy: () => void; }