Skip to content

MSI Navigation & Entities

Turn-by-turn navigation and real-time entity tracking on the map.

Navigation & Entities Overview

This API enables:

  • Turn-by-turn navigation with voice guidance
  • Real-time position updates during navigation
  • Fleet tracking and nearby entity management
  • Navigation events and lifecycle management
  • External navigation data casting

Complete navigation lifecycle from mounting to dismissal.

mountNavigation()

Prepare a route for navigation (required before starting).

1

Mount Navigation

Prepare the route and UI

typescript
await controls.mountNavigation({
  route: routeId,              // Route to navigate
  simulateLocation: false,     // Use real GPS (false) or simulation (true)
  voiceGuidance: true,        // Enable voice instructions
  speedLimit: true,           // Show speed limit warnings
  alternatives: true          // Show alternative routes during nav
})

console.log('Navigation mounted and ready')

Parameters:

typescript
{
  route?: string              // Route ID (uses current if omitted)
  simulateLocation?: boolean  // Simulate movement (for testing)
  voiceGuidance?: boolean     // Turn-by-turn voice
  speedLimit?: boolean        // Speed limit display
  alternatives?: boolean      // Alternative route suggestions
  units?: 'metric' | 'imperial'
}

loadNavigation()

Start the navigation session.

2

Load Navigation

Begin turn-by-turn guidance

typescript
await controls.loadNavigation()

console.log('Navigation started')
// User will now see turn-by-turn instructions

This displays the navigation UI with:

  • Current instruction
  • Distance to next turn
  • Estimated time of arrival
  • Remaining distance

setInitialNavigationPosition()

Set starting position for navigation (useful when user is not at route origin).

3

Set Starting Position

Begin from specific location

typescript
await controls.setInitialNavigationPosition({
  lng: -74.0060,
  lat: 40.7128
}, {
  snapToRoute: true,          // Snap to nearest route point
  heading: 45                 // Initial heading (degrees)
})

Provide real-time position updates during navigation.

4

Real-time Position Updates

Update position as user moves

typescript
// Get location updates from GPS
navigator.geolocation.watchPosition(async (position) => {
  await controls.navigate({
    lng: position.coords.longitude,
    lat: position.coords.latitude,
    heading: position.coords.heading,
    speed: position.coords.speed,
    accuracy: position.coords.accuracy
  })
}, {
  enableHighAccuracy: true,
  maximumAge: 0
})

Navigation State Updates:

typescript
controls.on('navigation:instruction', (instruction) => {
  console.log('Next:', instruction.text)
  console.log('Distance:', instruction.distance, 'meters')
  console.log('Duration:', instruction.duration, 'seconds')
})

controls.on('navigation:progress', (progress) => {
  console.log('Completed:', progress.percentage, '%')
  console.log('Remaining:', progress.distanceRemaining, 'meters')
  console.log('ETA:', progress.eta)
})

casting()

Feed external navigation data (e.g., from Google Maps, Apple Maps).

5

Cast External Navigation

Use navigation from other sources

typescript
// Receive navigation updates from external source
externalNavigationService.on('update', async (navData) => {
  await controls.casting({
    position: {
      lng: navData.longitude,
      lat: navData.latitude,
      heading: navData.bearing
    },
    instruction: {
      text: navData.currentInstruction,
      distance: navData.distanceToNextManeuver,
      maneuver: navData.maneuverType
    },
    route: {
      distanceRemaining: navData.remainingDistance,
      durationRemaining: navData.remainingTime,
      eta: navData.estimatedArrival
    }
  })
})

Use Cases:

  • Integrate with third-party navigation
  • Display navigation from native apps
  • Sync with external routing services

dismissNavigation()

End the navigation session.

6

Dismiss Navigation

Stop navigation and hide UI

typescript
await controls.dismissNavigation()

console.log('Navigation ended')

This removes the navigation UI but keeps the route visible.

unmountNavigation()

Complete cleanup of navigation session.

7

Unmount Navigation

Full navigation cleanup

typescript
await controls.unmountNavigation()

console.log('Navigation fully unmounted')

This removes all navigation state and UI elements.

Listen to navigation lifecycle and state changes.

typescript
controls.on('navigation:started', (data) => {
  console.log('Navigation started:', data)
  showNavigationUI()
})

controls.on('navigation:stopped', () => {
  console.log('Navigation stopped')
  hideNavigationUI()
})

controls.on('navigation:paused', () => {
  console.log('Navigation paused')
})

controls.on('navigation:resumed', () => {
  console.log('Navigation resumed')
})
typescript
controls.on('navigation:instruction', (instruction) => {
  // Next maneuver instruction
  console.log('Instruction:', instruction.text)
  console.log('Distance:', instruction.distance)
  
  // Speak instruction
  if (voiceEnabled) {
    speak(instruction.text)
  }
})

controls.on('navigation:maneuver', (maneuver) => {
  // Upcoming maneuver details
  console.log('Maneuver type:', maneuver.type)
  console.log('Modifier:', maneuver.modifier)
  console.log('In:', maneuver.distance, 'meters')
})

controls.on('navigation:progress', (progress) => {
  // Overall progress
  console.log('Progress:', progress.percentage, '%')
  console.log('Distance remaining:', progress.distanceRemaining)
  console.log('Time remaining:', progress.durationRemaining)
  console.log('ETA:', progress.eta)
  
  updateProgressBar(progress.percentage)
  updateETA(progress.eta)
})
typescript
controls.on('navigation:rerouting', (reason) => {
  console.log('Rerouting because:', reason)
  showRerouteNotification()
})

controls.on('navigation:reroute', (newRoute) => {
  console.log('New route calculated:', newRoute)
  updateRoute(newRoute)
})

controls.on('navigation:offroute', (deviation) => {
  console.log('Off route by:', deviation, 'meters')
  showOffRouteWarning()
})

controls.on('navigation:nearby', (data) => {
  console.log('Approaching waypoint:', data.waypoint)
  console.log('Distance:', data.distance)
})

controls.on('navigation:arrived', (waypoint) => {
  console.log('Arrived at:', waypoint)
  playArrivalSound()
})

controls.on('navigation:complete', () => {
  console.log('Journey complete!')
  showCompletionScreen()
})

Speed & Traffic Events

typescript
controls.on('navigation:speeding', (data) => {
  console.log('Speed limit:', data.limit, 'km/h')
  console.log('Current speed:', data.current, 'km/h')
  showSpeedWarning()
})

controls.on('navigation:traffic', (traffic) => {
  console.log('Traffic level:', traffic.severity)
  console.log('Delay:', traffic.delay, 'seconds')
  
  if (traffic.severity === 'high') {
    suggestAlternativeRoute()
  }
})

Nearby Entities

Display and manage multiple entities (vehicles, drivers, points of interest) on the map.

showNearby()

Display multiple entities at once.

1

Show Multiple Entities

Display fleet or POIs

typescript
await controls.showNearby([
  {
    id: 'vehicle-1',
    type: 'vehicle',
    grade: 'primary',
    position: { lng: -74.0060, lat: 40.7128 },
    label: 'Truck 101',
    heading: 45,
    metadata: {
      driver: 'John Doe',
      status: 'available'
    }
  },
  {
    id: 'vehicle-2',
    type: 'vehicle',
    grade: 'secondary',
    position: { lng: -73.9951, lat: 40.7489 },
    label: 'Van 202',
    heading: 180,
    metadata: {
      driver: 'Jane Smith',
      status: 'busy'
    }
  },
  {
    id: 'warehouse-1',
    type: 'warehouse',
    grade: 'primary',
    position: { lng: -74.0100, lat: 40.7100 },
    label: 'Main Warehouse',
    icon: 'warehouse'
  }
])

Entity Types:

  • vehicle - Cars, trucks, vans
  • driver - Delivery personnel
  • warehouse - Distribution centers
  • hub - Collection points
  • customer - Delivery locations
  • poi - Points of interest
  • custom - Custom entity types

Entity Grades:

  • primary - Main/active entities (larger, more prominent)
  • secondary - Supporting entities (smaller, less prominent)
  • tertiary - Background entities (minimal display)

addNearbyEntity()

Add a single entity to the map.

2

Add Single Entity

Add one entity

typescript
const entityId = await controls.addNearbyEntity({
  id: 'driver-123',
  type: 'driver',
  grade: 'primary',
  position: { lng: -74.0060, lat: 40.7128 },
  label: 'Driver: Mike',
  sublabel: 'En route',
  heading: 90,
  icon: 'delivery-person',
  color: '#0ea5e9',
  
  // Interactive
  clickable: true,
  onClick: (entity) => {
    showDriverDetails(entity)
  }
})

console.log('Entity added:', entityId)

moveNearbyEntity()

Update an entity's position (for live tracking).

3

Move Entity

Update position in real-time

typescript
// Update vehicle position from GPS/API
socket.on('vehicle:location', async (update) => {
  await controls.moveNearbyEntity(update.vehicleId, {
    position: {
      lng: update.longitude,
      lat: update.latitude
    },
    heading: update.bearing,
    speed: update.speed,
    
    // Optional: smooth animation
    animate: true,
    duration: 1000
  })
})

updateNearbyEntity()

Update entity properties (label, color, metadata).

typescript
await controls.updateNearbyEntity('vehicle-1', {
  label: 'Truck 101 - Delivering',
  color: '#10b981',
  metadata: {
    status: 'busy',
    currentOrder: 'ORD-123'
  }
})

removeNearbyEntity()

Remove a single entity from the map.

typescript
await controls.removeNearbyEntity('vehicle-1')

removeNearby()

Remove all nearby entities.

typescript
await controls.removeNearby()

getNearbyEntities()

Get all current entities on the map.

typescript
const entities = await controls.getNearbyEntities()

console.log('Active entities:', entities.length)

entities.forEach(entity => {
  console.log(`${entity.label} at ${entity.position.lat}, ${entity.position.lng}`)
})

Event Listeners

Manage event subscriptions.

on()

Subscribe to map and navigation events.

typescript
const handler = (data) => {
  console.log('Event data:', data)
}

controls.on('navigation:started', handler)
controls.on('entity:clicked', handler)
controls.on('route:created', handler)

Available Events:

  • Navigation: navigation:* (started, stopped, instruction, progress, etc.)
  • Route: route:* (created, updated, cleared)
  • Entity: entity:* (added, moved, removed, clicked)
  • Map: map:* (clicked, moved, zoomed)
  • Location: location:* (updated, error)

off()

Unsubscribe from specific event.

typescript
controls.off('navigation:started', handler)

removeListeners()

Remove all event listeners (cleanup).

typescript
controls.removeListeners()

once()

Listen to event only once.

typescript
controls.once('navigation:complete', () => {
  console.log('Journey finished - this will only run once')
  showCompletionScreen()
})

Complete Examples

Full Navigation Flow

typescript
import De from '@de./sdk'

const msi = new De.MSI({
  element: 'map',
  accessToken: token
})

const { controls } = await msi.load()

// Create route
const route = await controls.setRoute({
  origin: pickupLocation,
  destination: deliveryLocation,
  options: {
    profile: 'driving-traffic'
  }
})

// Setup navigation
await controls.mountNavigation({
  voiceGuidance: true,
  speedLimit: true
})

// Listen to events
controls.on('navigation:instruction', (instruction) => {
  updateInstructionUI(instruction.text)
  speakInstruction(instruction.text)
})

controls.on('navigation:progress', (progress) => {
  updateProgressBar(progress.percentage)
  updateETA(progress.eta)
})

controls.on('navigation:arrived', async () => {
  await controls.dismissNavigation()
  showArrivalScreen()
})

// Start navigation
await controls.loadNavigation()

// Track real-time position
navigator.geolocation.watchPosition(async (pos) => {
  await controls.navigate({
    lng: pos.coords.longitude,
    lat: pos.coords.latitude,
    heading: pos.coords.heading,
    speed: pos.coords.speed
  })
}, {
  enableHighAccuracy: true,
  maximumAge: 0
})

Fleet Tracking Dashboard

typescript
class FleetTracker {
  private controls: MSIControls
  private vehicles = new Map()
  
  constructor(controls: MSIControls) {
    this.controls = controls
  }
  
  async initialize(vehicleList: Vehicle[]) {
    // Display all vehicles
    await this.controls.showNearby(
      vehicleList.map(v => ({
        id: v.id,
        type: 'vehicle',
        grade: v.status === 'active' ? 'primary' : 'secondary',
        position: v.location,
        label: v.name,
        heading: v.heading,
        metadata: v
      }))
    )
    
    vehicleList.forEach(v => this.vehicles.set(v.id, v))
  }
  
  async updateVehicle(vehicleId: string, update: LocationUpdate) {
    await this.controls.moveNearbyEntity(vehicleId, {
      position: update.location,
      heading: update.heading,
      animate: true,
      duration: 1000
    })
    
    const vehicle = this.vehicles.get(vehicleId)
    if (vehicle) {
      vehicle.location = update.location
      vehicle.heading = update.heading
    }
  }
  
  async setVehicleStatus(vehicleId: string, status: string) {
    const color = {
      'available': '#10b981',
      'busy': '#0ea5e9',
      'offline': '#6b7280'
    }[status]
    
    await this.controls.updateNearbyEntity(vehicleId, {
      color,
      metadata: { status }
    })
  }
  
  getVehiclesInArea(bounds: Bounds): Vehicle[] {
    return Array.from(this.vehicles.values()).filter(v =>
      this.isInBounds(v.location, bounds)
    )
  }
  
  private isInBounds(location: Location, bounds: Bounds): boolean {
    return (
      location.lng >= bounds.southwest.lng &&
      location.lng <= bounds.northeast.lng &&
      location.lat >= bounds.southwest.lat &&
      location.lat <= bounds.northeast.lat
    )
  }
}

// Usage
const fleet = new FleetTracker(controls)

await fleet.initialize(vehicles)

// Real-time updates
socket.on('vehicle:location', (update) => {
  fleet.updateVehicle(update.vehicleId, update)
})

socket.on('vehicle:status', (update) => {
  fleet.setVehicleStatus(update.vehicleId, update.status)
})
typescript
async function startDeliveryRoute(stops: DeliveryStop[]) {
  // Create multi-stop route
  const route = await controls.setRoute({
    origin: depot,
    waypoints: stops.map(s => ({
      ...s.location,
      id: s.orderId
    })),
    destination: depot,
    options: {
      profile: 'driving-traffic',
      optimizeWaypoints: true
    }
  })
  
  let currentStopIndex = 0
  
  // Mount navigation
  await controls.mountNavigation({
    voiceGuidance: true
  })
  
  // Handle waypoint arrival
  controls.on('navigation:arrived', async (waypoint) => {
    const stop = stops[currentStopIndex]
    
    // Mark stop as arrived
    await controls.updateWaypointCaption(waypoint.id, {
      status: 'arrived',
      color: '#10b981'
    })
    
    // Show delivery UI
    showDeliveryScreen(stop)
    
    // Pause navigation
    await controls.dismissNavigation()
    
    // Wait for delivery completion
    await waitForDeliveryComplete(stop)
    
    // Mark as complete
    await controls.updateWaypointCaption(waypoint.id, {
      status: 'completed'
    })
    
    currentStopIndex++
    
    // Continue to next stop or complete
    if (currentStopIndex < stops.length) {
      await controls.loadNavigation()
    } else {
      console.log('All deliveries complete!')
      await controls.unmountNavigation()
      showCompletionScreen()
    }
  })
  
  // Start navigation
  await controls.loadNavigation()
}

Type Definitions

typescript
interface NavigationOptions {
  route?: string
  simulateLocation?: boolean
  voiceGuidance?: boolean
  speedLimit?: boolean
  alternatives?: boolean
  units?: 'metric' | 'imperial'
}

interface NavigationInstruction {
  text: string
  distance: number
  duration: number
  maneuver: {
    type: string
    modifier?: string
    location: Location
  }
}

interface NavigationProgress {
  percentage: number
  distanceRemaining: number
  durationRemaining: number
  distanceTraveled: number
  eta: string
}

interface NearbyEntity {
  id: string
  type: 'vehicle' | 'driver' | 'warehouse' | 'hub' | 'customer' | 'poi' | 'custom'
  grade: 'primary' | 'secondary' | 'tertiary'
  position: Location
  label?: string
  sublabel?: string
  heading?: number
  icon?: string
  color?: string
  clickable?: boolean
  onClick?: (entity: NearbyEntity) => void
  metadata?: any
}

Next Steps