Skip to main content

Follow Position

|

This example demonstrates how to track and follow the user's real-time location on the map with smooth camera animations.

Live Demo

Overview

The example highlights the following features:

  • Requesting location permissions
  • Setting up live position tracking
  • Following user's position with camera
  • Smooth camera animations

Code Implementation

Initialize Map

index.ts
import {
GemKit,
GemMap,
PositionService,
GemAnimation,
AnimationType
} from '@magiclane/maps-sdk';
import { GEMKIT_TOKEN } from './token';
let map: GemMap | null = null;
let hasLiveDataSource = false;

// UI Elements
let followPositionBtn: HTMLButtonElement;

async function onMapCreated(gemMap: GemMap) {
map = gemMap;
}

window.addEventListener('DOMContentLoaded', async () => {
const gemKit = await GemKit.initialize(GEMKIT_TOKEN);
await PositionService.instance;

const container = document.getElementById('map-container');
if (!container) throw new Error('Map container not found');

const viewId = 2;
const wrapper = gemKit.createView(viewId, onMapCreated);
if (wrapper) container.appendChild(wrapper);
});

Follow Position Function

index.ts
async function onFollowPositionButtonPressed() {
// On web, the SDK handles location permission
const permission = await PositionService.requestLocationPermission();
if (!permission) {
showMessage('Location permission denied.');
return;
}

// Set live data source only once
if (!hasLiveDataSource) {
PositionService.instance.setLiveDataSource();
hasLiveDataSource = true;
}

// Optionally, set an animation
const animation = new GemAnimation({ type: AnimationType.linear });

// Start following position
map?.startFollowingPosition({ animation });
showMessage('Following position...');
}

Create Follow Button

index.ts
// Follow Position button
followPositionBtn = document.createElement('button');
followPositionBtn.textContent = 'Follow Position';
followPositionBtn.style.cssText = `
position: fixed; top: 20px; right: 20px; padding: 12px 20px;
background: #673ab7; color: #fff; border: none; border-radius: 8px;
font-size: 1em; font-weight: 500; cursor: pointer; z-index: 2000;
display: flex; align-items: center; gap: 8px;
`;
followPositionBtn.innerHTML = `
<span style="font-size: 18px;">📡</span>
<span>Follow Position</span>
`;
followPositionBtn.onclick = () => onFollowPositionButtonPressed();
document.body.appendChild(followPositionBtn);

Utility Function

index.ts
// Utility: show a temporary message
function showMessage(message: string, duration = 3000) {
let msgDiv = document.getElementById('status-msg');
if (!msgDiv) {
msgDiv = document.createElement('div');
msgDiv.id = 'status-msg';
msgDiv.style.cssText = `
position: fixed; top: 20px; left: 50%; transform: translateX(-50%);
background: #333; color: #fff; padding: 12px 20px; border-radius: 8px;
z-index: 2000; font-size: 1em;
`;
document.body.appendChild(msgDiv);
}
if (message === '') {
msgDiv.style.display = 'none';
msgDiv.textContent = '';
} else {
msgDiv.textContent = message;
msgDiv.style.display = 'block';
setTimeout(() => {
msgDiv.style.display = 'none';
msgDiv.textContent = '';
}, duration);
}
}

Key Features

  • Location Permission: Automatically requests browser location permission
  • Live Data Source: Sets up continuous position updates from device GPS
  • Camera Animation: Smooth transitions when following position
  • Single Initialization: Live data source is set only once for efficiency

Browser Permissions

The browser will prompt for location permission when you click "Follow Position":

  • Allow: Map will track and follow your real-time location
  • Deny: Feature will not work (message displayed)
HTTPS Required

Most browsers require HTTPS to access location services. Make sure your app is served over HTTPS in production.

Animation Types

The SDK supports the following animation types:

  • AnimationType.none: No animation (instant movement)
  • AnimationType.linear: Smooth linear movement

You can also set a custom duration in milliseconds when creating the animation:

const animation = new GemAnimation({ 
type: AnimationType.linear,
duration: 2000 // 2 seconds
});

Next Steps