Skip to main content

Follow Position

Last updated: January 27, 2026 | 3 minutes read

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

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

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

// 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

// 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)

:::tip 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