MSI Controls API
Promise-based direct control API for precise map operations.
Controls vs Handles
Controls provide granular, promise-based operations for precise control over individual map functions. Use controls when you need:
- Single, discrete operations
- Direct control over map state
- Promise-based async/await patterns
- Fine-grained customization
Handles provide stream-based workflows for common patterns. Learn about Handles →
Getting Controls
import De from '@de./sdk'
const msi = new De.MSI({
element: 'map',
accessToken: 'your-token'
})
const { controls, handles } = await msi.load()
// Now use controls for direct operations
await controls.getCurrentLocation()Location Services
getCurrentLocation()
Get the user's current GPS location.
Get Current Location
Request user's current position
const location = await controls.getCurrentLocation()
console.log('Location:', location)
// {
// lng: -74.0060,
// lat: 40.7128,
// accuracy: 10,
// heading: 45,
// speed: 0
// }Returns: Promise<Location>
Throws:
PERMISSION_DENIED- User denied location accessPOSITION_UNAVAILABLE- Location unavailableTIMEOUT- Request timed out
pinCurrentLocation()
Get current location and add a pin marker on the map.
Pin Current Location
Show user location with marker
const location = await controls.pinCurrentLocation({
label: 'You are here',
draggable: false,
color: 'blue'
})
console.log('Pinned at:', location)Parameters:
{
label?: string // Marker label
sublabel?: string // Secondary text
draggable?: boolean // Allow marker drag
color?: string // Marker color
icon?: string // Custom icon
}Returns: Promise<Location>
trackLiveLocation()
Continuously track user's location with updates.
Track Live Location
Monitor position changes
const unsubscribe = await controls.trackLiveLocation({
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
}, (location) => {
console.log('Location updated:', location)
updateMap(location)
})
// Stop tracking when done
unsubscribe()Parameters:
// Options
{
enableHighAccuracy?: boolean // High accuracy mode
timeout?: number // Timeout in ms
maximumAge?: number // Max cache age in ms
}
// Callback
(location: Location) => voidReturns: Promise<() => void> - Unsubscribe function
setLiveLocationOptions()
Configure live location tracking behavior.
await controls.setLiveLocationOptions({
updateInterval: 1000, // Update every 1 second
distanceFilter: 10, // Minimum 10m movement
showTrail: true, // Show location trail
trailColor: '#0ea5e9', // Trail color
smoothing: true // Smooth position updates
})Map Styling
setMapStyle()
Change the map's visual style.
Set Map Style
Apply different map themes
// Predefined styles
await controls.setMapStyle('streets')
await controls.setMapStyle('satellite')
await controls.setMapStyle('dark')
await controls.setMapStyle('light')
// Custom style URL
await controls.setMapStyle('mapbox://styles/username/style-id')Available Styles:
streets- Standard street mapsatellite- Satellite imageryhybrid- Satellite with labelsdark- Dark themelight- Light themeoutdoors- Terrain and trailsnavigation-day- Optimized for daytime navigationnavigation-night- Optimized for nighttime navigation
Layer Controls
Control map layer visibility.
// Toggle traffic layer
await controls.setLayerVisibility('traffic', true)
// Toggle transit layer
await controls.setLayerVisibility('transit', true)
// Toggle 3D buildings
await controls.setLayerVisibility('buildings-3d', true)
// Custom layers
await controls.addLayer({
id: 'custom-markers',
type: 'symbol',
source: 'markers-data',
layout: {
'icon-image': 'marker-icon',
'icon-size': 1.5
}
})Map Controls
Show/hide map UI controls.
// Navigation controls (zoom, rotate)
await controls.showControl('navigation', true)
// Geolocate button
await controls.showControl('geolocate', true)
// Scale bar
await controls.showControl('scale', true)
// Fullscreen button
await controls.showControl('fullscreen', true)Search & Geocoding
searchQuery()
Search for places by text query.
Search Places
Find locations by name or address
const results = await controls.searchQuery('Central Park, New York', {
limit: 5,
types: ['poi', 'address'],
proximity: { lng: -74.0060, lat: 40.7128 },
bbox: [-74.1, 40.6, -73.9, 40.8]
})
console.log('Search results:', results)
// [
// {
// id: 'poi.123',
// name: 'Central Park',
// address: 'New York, NY 10024',
// coordinates: { lng: -73.9654, lat: 40.7829 },
// relevance: 0.95
// },
// ...
// ]Parameters:
{
query: string // Search query
limit?: number // Max results (default: 10)
types?: string[] // Filter by type
proximity?: Location // Bias near location
bbox?: [number, number, number, number] // Bounding box
language?: string // Result language
country?: string[] // Filter by country codes
}Returns: Promise<SearchResult[]>
searchSelect()
Select a search result and display on map.
Select Search Result
Show selected place on map
const results = await controls.searchQuery('Times Square')
// Select first result
const selected = await controls.searchSelect(results[0], {
zoom: 15,
addMarker: true,
markerOptions: {
label: results[0].name,
color: 'red'
}
})
console.log('Selected:', selected)Parameters:
{
result: SearchResult // Result to select
zoom?: number // Zoom level
addMarker?: boolean // Add marker
markerOptions?: MarkerOptions // Marker styling
}resolvePlace()
Forward geocoding - convert address to coordinates.
Forward Geocoding
Address to coordinates
const location = await controls.resolvePlace(
'1600 Amphitheatre Parkway, Mountain View, CA'
)
console.log('Coordinates:', location)
// {
// lng: -122.0840,
// lat: 37.4220,
// address: '1600 Amphitheatre Parkway, Mountain View, CA 94043',
// formatted: 'Google Headquarters'
// }Parameters: address: string
Returns: Promise<ResolvedLocation>
resolveCoordinates()
Reverse geocoding - convert coordinates to address.
Reverse Geocoding
Coordinates to address
const address = await controls.resolveCoordinates({
lng: -73.9855,
lat: 40.7580
})
console.log('Address:', address)
// {
place: 'Times Square',
street: 'Broadway',
city: 'New York',
state: 'NY',
country: 'United States',
postalCode: '10036',
formatted: 'Times Square, Broadway, New York, NY 10036, USA'
}Parameters: coordinates: Location
Returns: Promise<Address>
Drag & Pick Location
Interactive location picker for user selection.
enableDragPickLocation()
Enable drag-to-pick mode.
Enable Location Picker
Let users pick a location by dragging
const pickedLocation = await controls.enableDragPickLocation({
initialPosition: { lng: -74.0060, lat: 40.7128 },
onDrag: (location) => {
console.log('Dragging:', location)
},
content: {
title: 'Select Location',
subtitle: 'Drag the map to select',
confirmText: 'Confirm',
cancelText: 'Cancel'
}
})
if (pickedLocation) {
console.log('User picked:', pickedLocation)
} else {
console.log('User cancelled')
}Parameters:
{
initialPosition?: Location // Starting position
onDrag?: (location: Location) => void // Drag callback
content?: {
title?: string // Picker title
subtitle?: string // Instructions
confirmText?: string // Confirm button
cancelText?: string // Cancel button
}
}Returns: Promise<Location | null>
disableDragPickLocation()
Disable picker mode and return to normal map.
await controls.disableDragPickLocation()setDragPickContent()
Customize picker UI during active session.
await controls.setDragPickContent({
title: 'Delivery Address',
subtitle: 'Move the pin to your exact location',
confirmText: 'Use This Location'
})Advanced Location Features
Get Precise Location
Enhanced location with multiple attempts for better accuracy.
async function getPreciseLocation() {
const locations = []
for (let i = 0; i < 3; i++) {
const loc = await controls.getCurrentLocation()
locations.push(loc)
await new Promise(resolve => setTimeout(resolve, 1000))
}
// Return most accurate
return locations.reduce((best, current) =>
current.accuracy < best.accuracy ? current : best
)
}
const preciseLocation = await getPreciseLocation()Location Distance Calculation
import { utils } from '@de./sdk'
const loc1 = await controls.getCurrentLocation()
const loc2 = { lng: -73.9855, lat: 40.7580 }
const distance = utils.calculateDistance(loc1, loc2)
console.log(`Distance: ${distance.toFixed(2)} meters`)Continuous Address Updates
const unsubscribe = await controls.trackLiveLocation({
enableHighAccuracy: true
}, async (location) => {
// Get address for current location
const address = await controls.resolveCoordinates(location)
console.log('Current address:', address.formatted)
updateUI({
location,
address: address.formatted
})
})Search with Autocomplete
Build a search UI with autocomplete.
let searchTimeout: any
async function handleSearchInput(query: string) {
// Debounce search
clearTimeout(searchTimeout)
searchTimeout = setTimeout(async () => {
if (query.length < 3) return
const results = await controls.searchQuery(query, {
limit: 5,
types: ['address', 'poi']
})
displaySearchResults(results)
}, 300)
}
async function selectResult(result: SearchResult) {
await controls.searchSelect(result, {
zoom: 16,
addMarker: true,
markerOptions: {
label: result.name
}
})
}Map Bounds & Viewport
fitBounds()
Adjust map to show specific bounds.
await controls.fitBounds({
southwest: { lng: -74.1, lat: 40.6 },
northeast: { lng: -73.9, lat: 40.8 }
}, {
padding: 50, // Padding in pixels
maxZoom: 15, // Maximum zoom level
animate: true, // Smooth animation
duration: 1000 // Animation duration (ms)
})getBounds()
Get current map viewport bounds.
const bounds = await controls.getBounds()
console.log('Visible area:', bounds)
// {
// southwest: { lng: -74.05, lat: 40.70 },
// northeast: { lng: -74.00, lat: 40.75 }
// }setCenter()
Move map to specific coordinates.
await controls.setCenter(
{ lng: -73.9855, lat: 40.7580 },
{
zoom: 14,
animate: true,
duration: 2000
}
)setZoom()
Set map zoom level.
await controls.setZoom(15, {
animate: true,
duration: 1000
})Error Handling
try {
const location = await controls.getCurrentLocation()
} catch (error) {
switch (error.code) {
case 'PERMISSION_DENIED':
alert('Please enable location access')
break
case 'POSITION_UNAVAILABLE':
alert('Location unavailable. Check GPS/network.')
break
case 'TIMEOUT':
alert('Location request timed out. Try again.')
break
default:
console.error('Location error:', error)
}
}Performance Tips
Best Practices
- Cache search results to avoid duplicate requests
- Debounce search input (300-500ms)
- Use appropriate accuracy for use case
- Clean up location tracking when not needed
- Limit search result count
Avoid
- Tracking location continuously if not needed
- Requesting high accuracy unnecessarily
- Creating new markers for every location update
- Searching on every keystroke
- Ignoring error states
Complete Examples
Location-based Search
import De from '@de./sdk'
const msi = new De.MSI({
element: 'map',
accessToken: token
})
const { controls } = await msi.load()
// Get user location
const userLocation = await controls.getCurrentLocation()
// Search nearby restaurants
const restaurants = await controls.searchQuery('restaurants', {
proximity: userLocation,
types: ['poi'],
limit: 10
})
// Display results
restaurants.forEach(async (restaurant, index) => {
await controls.addMarker({
position: restaurant.coordinates,
label: restaurant.name,
onClick: () => {
showRestaurantDetails(restaurant)
}
})
})
// Fit map to show all results
const bounds = calculateBounds([
userLocation,
...restaurants.map(r => r.coordinates)
])
await controls.fitBounds(bounds)Address Autocomplete Component
class AddressAutocomplete {
private controls: MSIControls
private timeout: any
constructor(controls: MSIControls) {
this.controls = controls
}
async search(query: string): Promise<SearchResult[]> {
clearTimeout(this.timeout)
return new Promise((resolve) => {
this.timeout = setTimeout(async () => {
if (query.length < 3) {
resolve([])
return
}
const results = await this.controls.searchQuery(query, {
types: ['address'],
limit: 5
})
resolve(results)
}, 300)
})
}
async select(result: SearchResult) {
await this.controls.searchSelect(result, {
zoom: 16,
addMarker: true
})
return result
}
}
// Usage
const autocomplete = new AddressAutocomplete(controls)
const results = await autocomplete.search('123 Main')
await autocomplete.select(results[0])Type Definitions
interface Location {
lng: number
lat: number
accuracy?: number
heading?: number
speed?: number
altitude?: number
}
interface SearchResult {
id: string
name: string
address: string
coordinates: Location
type: string
relevance: number
bbox?: [number, number, number, number]
}
interface Address {
place?: string
street?: string
city: string
state: string
country: string
postalCode?: string
formatted: string
}
interface Bounds {
southwest: Location
northeast: Location
}
