Ola Map SDK

Map Display

Complete guide to displaying interactive maps with MapLibre GL and Ola Maps

Map Display with MapLibre GL

Learn how to display interactive maps using the Ola Maps SDK with MapLibre GL JS, a free and open-source mapping library.

Prerequisites

Install MapLibre GL:

npm install maplibre-gl

Quick Start

The easiest way to get started is using the getMapOptions() helper method.

Basic Map Setup

import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import OlaMapsClient from 'ola-map-sdk';

// Initialize the client
const client = new OlaMapsClient('YOUR_API_KEY');

// Create map with one-liner options
const map = new maplibregl.Map(client.getMapOptions({
    container: 'map',        // DOM element ID
    center: [77.61, 12.93],  // [lng, lat]
    zoom: 14,
    style: 'default-light-standard'
}));

HTML Structure

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Ola Maps Example</title>
    <script src='https://unpkg.com/maplibre-gl@^4.0.0/dist/maplibre-gl.js'></script>
    <link href='https://unpkg.com/maplibre-gl@^4.0.0/dist/maplibre-gl.css' rel='stylesheet' />
    <style>
        #map { 
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }
    </style>
</head>
<body>
    <div id="map"></div>
    <script>
        const client = new OlaMapsClient('YOUR_API_KEY');
        
        const map = new maplibregl.Map(client.getMapOptions({
            container: 'map',
            center: [77.61, 12.93],
            zoom: 14
        }));
    </script>
</body>
</html>

SDK Helper Methods

The Ola Maps SDK provides three helper methods for MapLibre integration.

Creates a complete options object for initializing a MapLibre map.

const options = client.getMapOptions({
    container: 'map',
    style: 'default-light-standard',
    center: [77.61, 12.93],
    zoom: 14
});

const map = new maplibregl.Map(options);

Parameters

ParameterTypeRequiredDescription
containerstring/HTMLElementYesMap container element or ID
stylestringNoMap style name (default: default-light-standard)
centerarrayNoCenter coordinates [lng, lat] (default: [77.61, 12.93])
zoomnumberNoZoom level (default: 14)

Returns

Complete MapLibre GL map options object with:

  • Style URL with API key authentication
  • Transform request function for tile authentication
  • Default center and zoom

getStyleURL()

Get the full style URL for use with MapLibre.

const styleUrl = client.getStyleURL('default-light-standard');
// Returns: "https://api.olamaps.io/tiles/vector/v1/styles/default-light-standard/style.json"

getTransformRequest()

Get a pre-configured transform request function for authenticating tile requests.

const transformRequest = client.getTransformRequest();

const map = new maplibregl.Map({
    container: 'map',
    style: 'https://api.olamaps.io/tiles/vector/v1/styles/default-light-standard/style.json',
    center: [77.61, 12.93],
    zoom: 14,
    transformRequest: transformRequest
});

Manual Configuration

If you prefer not to use the helper methods, you can configure manually.

Manual Setup

const map = new maplibregl.Map({
    container: 'map',
    style: `https://api.olamaps.io/tiles/vector/v1/styles/default-light-standard/style.json?api_key=${API_KEY}`,
    center: [77.61, 12.93],
    zoom: 14,
    transformRequest: (url, resourceType) => {
        if (resourceType === 'Tile') {
            return `${url}${url.includes('?') ? '&' : '?'}api_key=${API_KEY}`;
        }
        return { url };
    }
});

Map Styles

Ola Maps offers various pre-designed styles. Here are the most popular ones:

Light Themes

// Default Light
const map = new maplibregl.Map(client.getMapOptions({
    container: 'map',
    style: 'default-light-standard'
}));

// Ultra Light
const map = new maplibregl.Map(client.getMapOptions({
    container: 'map',
    style: 'default-ultra-light-standard'
}));

Dark Themes

// Default Dark
const map = new maplibregl.Map(client.getMapOptions({
    container: 'map',
    style: 'default-dark-standard'
}));

// Eclipse Dark
const map = new maplibregl.Map(client.getMapOptions({
    container: 'map',
    style: 'eclipse-dark-standard'
}));

Special Themes

// Vintage
const map = new maplibregl.Map(client.getMapOptions({
    container: 'map',
    style: 'vintage-light'
}));

// Earth
const map = new maplibregl.Map(client.getMapOptions({
    container: 'map',
    style: 'default-earth-standard'
}));

// OSM Bright
const map = new maplibregl.Map(client.getMapOptions({
    container: 'map',
    style: 'osm-bright'
}));

Interactive Examples

Adding Markers

const map = new maplibregl.Map(client.getMapOptions({
    container: 'map',
    center: [77.61, 12.93],
    zoom: 14
}));

// Add a simple marker
new maplibregl.Marker()
    .setLngLat([77.61, 12.93])
    .addTo(map);

// Add marker with popup
new maplibregl.Marker({ color: 'red' })
    .setLngLat([77.61, 12.93])
    .setPopup(
        new maplibregl.Popup().setHTML('<h3>Bangalore</h3><p>Karnataka, India</p>')
    )
    .addTo(map);

// Custom marker with HTML
const el = document.createElement('div');
el.className = 'custom-marker';
el.style.width = '20px';
el.style.height = '20px';
el.style.backgroundColor = 'blue';
el.style.borderRadius = '50%';

new maplibregl.Marker(el)
    .setLngLat([77.62, 12.94])
    .addTo(map);

Drawing Shapes

Add a Polygon

map.on('load', () => {
    map.addSource('area', {
        type: 'geojson',
        data: {
            type: 'Feature',
            geometry: {
                type: 'Polygon',
                coordinates: [[
                    [77.60, 12.92],
                    [77.62, 12.92],
                    [77.62, 12.94],
                    [77.60, 12.94],
                    [77.60, 12.92]
                ]]
            }
        }
    });
    
    map.addLayer({
        id: 'area-fill',
        type: 'fill',
        source: 'area',
        paint: {
            'fill-color': '#0080ff',
            'fill-opacity': 0.3
        }
    });
    
    map.addLayer({
        id: 'area-outline',
        type: 'line',
        source: 'area',
        paint: {
            'line-color': '#0080ff',
            'line-width': 2
        }
    });
});

Add a Circle

map.on('load', () => {
    map.addSource('circle-point', {
        type: 'geojson',
        data: {
            type: 'FeatureCollection',
            features: [{
                type: 'Feature',
                geometry: {
                    type: 'Point',
                    coordinates: [77.61, 12.93]
                }
            }]
        }
    });
    
    map.addLayer({
        id: 'circle-layer',
        type: 'circle',
        source: 'circle-point',
        paint: {
            'circle-radius': 10,
            'circle-color': '#0080ff',
            'circle-stroke-width': 2,
            'circle-stroke-color': '#ffffff'
        }
    });
});

Draw a Route Line

async function drawRoute(origin, destination) {
    const route = await client.routing.getDirections(origin, destination);
    
    const routeCoordinates = route.routes[0].geometry.coordinates;
    
    map.addSource('route', {
        type: 'geojson',
        data: {
            type: 'Feature',
            properties: {},
            geometry: {
                type: 'LineString',
                coordinates: routeCoordinates
            }
        }
    });
    
    map.addLayer({
        id: 'route',
        type: 'line',
        source: 'route',
        layout: {
            'line-join': 'round',
            'line-cap': 'round'
        },
        paint: {
            'line-color': '#3887be',
            'line-width': 5,
            'line-opacity': 0.8
        }
    });
    
    // Fit map to show entire route
    const bounds = new maplibregl.LngLatBounds();
    routeCoordinates.forEach(coord => bounds.extend(coord));
    map.fitBounds(bounds, { padding: 50 });
}

// Usage
drawRoute(
    { lat: 12.993103, lon: 77.543326 },
    { lat: 12.972006, lon: 77.580085 }
);

User Location

// Add geolocate control
const geolocate = new maplibregl.GeolocateControl({
    positionOptions: {
        enableHighAccuracy: true
    },
    trackUserLocation: true,
    showUserHeading: true
});

map.addControl(geolocate);

// Automatically center on user's location
geolocate.on('geolocate', (position) => {
    console.log('User location:', position.coords);
});
// Add navigation controls
map.addControl(new maplibregl.NavigationControl());

// Add scale control
map.addControl(new maplibregl.ScaleControl({
    maxWidth: 80,
    unit: 'metric'
}));

// Add fullscreen control
map.addControl(new maplibregl.FullscreenControl());

Interactive Popups

map.on('click', (e) => {
    const coordinates = e.lngLat;
    
    new maplibregl.Popup()
        .setLngLat(coordinates)
        .setHTML(`
            <h3>Location Details</h3>
            <p>Latitude: ${coordinates.lat.toFixed(4)}</p>
            <p>Longitude: ${coordinates.lng.toFixed(4)}</p>
        `)
        .addTo(map);
});

// Change cursor on hover
map.on('mouseenter', 'my-layer', () => {
    map.getCanvas().style.cursor = 'pointer';
});

map.on('mouseleave', 'my-layer', () => {
    map.getCanvas().style.cursor = '';
});

Switching Styles

Allow users to change map styles dynamically.

Style Switcher Component

class MapStyleSwitcher {
    constructor(map, client) {
        this.map = map;
        this.client = client;
        this.styles = [
            { name: 'default-light-standard', label: 'Light' },
            { name: 'default-dark-standard', label: 'Dark' },
            { name: 'eclipse-light-standard', label: 'Eclipse' },
            { name: 'vintage-light', label: 'Vintage' },
            { name: 'default-earth-standard', label: 'Earth' }
        ];
    }
    
    createSwitcher() {
        const container = document.createElement('div');
        container.className = 'style-switcher';
        container.style.cssText = `
            position: absolute;
            top: 10px;
            right: 10px;
            background: white;
            padding: 10px;
            border-radius: 5px;
            box-shadow: 0 0 10px rgba(0,0,0,0.2);
            z-index: 1000;
        `;
        
        this.styles.forEach(style => {
            const button = document.createElement('button');
            button.textContent = style.label;
            button.style.cssText = `
                display: block;
                width: 100%;
                margin: 5px 0;
                padding: 8px;
                cursor: pointer;
                border: none;
                background: #f0f0f0;
                border-radius: 3px;
            `;
            
            button.onclick = () => {
                this.setStyle(style.name);
            };
            
            container.appendChild(button);
        });
        
        return container;
    }
    
    setStyle(styleName) {
        const styleUrl = this.client.getStyleURL(styleName);
        this.map.setStyle(styleUrl);
    }
}

// Usage
const map = new maplibregl.Map(client.getMapOptions({
    container: 'map'
}));

map.on('load', () => {
    const switcher = new MapStyleSwitcher(map, client);
    map.getContainer().appendChild(switcher.createSwitcher());
});

Real-World Applications

Store Locator

async function createStoreLocator(stores) {
    const map = new maplibregl.Map(client.getMapOptions({
        container: 'map',
        center: [stores[0].lng, stores[0].lat],
        zoom: 12
    }));
    
    // Add markers for each store
    stores.forEach(store => {
        const el = document.createElement('div');
        el.className = 'store-marker';
        el.innerHTML = '🏪';
        el.style.fontSize = '24px';
        
        new maplibregl.Marker(el)
            .setLngLat([store.lng, store.lat])
            .setPopup(
                new maplibregl.Popup()
                    .setHTML(`
                        <h3>${store.name}</h3>
                        <p>${store.address}</p>
                        <p>Open: ${store.hours}</p>
                    `)
            )
            .addTo(map);
    });
    
    // Add search functionality
    const searchInput = document.getElementById('store-search');
    searchInput.addEventListener('input', async (e) => {
        const query = e.target.value;
        if (query.length < 3) return;
        
        const results = await client.places.autocomplete(query, {
            location: '12.9716,77.5946',
            radius: 10000
        });
        
        // Display search results...
    });
}

Delivery Tracking

class DeliveryTracker {
    constructor(map, client) {
        this.map = map;
        this.client = client;
        this.deliveryMarkers = new Map();
    }
    
    async trackDelivery(deliveryId, route) {
        // Draw route
        await this.drawDeliveryRoute(route);
        
        // Simulate delivery progress
        let currentPoint = 0;
        const interval = setInterval(() => {
            if (currentPoint >= route.length) {
                clearInterval(interval);
                return;
            }
            
            const point = route[currentPoint];
            this.updateDeliveryPosition(deliveryId, point);
            currentPoint++;
        }, 1000);
    }
    
    updateDeliveryPosition(deliveryId, position) {
        if (this.deliveryMarkers.has(deliveryId)) {
            // Update existing marker
            const marker = this.deliveryMarkers.get(deliveryId);
            marker.setLngLat([position.lng, position.lat]);
        } else {
            // Create new marker
            const el = document.createElement('div');
            el.className = 'delivery-truck';
            el.innerHTML = '🚚';
            el.style.fontSize = '30px';
            
            const marker = new maplibregl.Marker(el)
                .setLngLat([position.lng, position.lat])
                .addTo(this.map);
            
            this.deliveryMarkers.set(deliveryId, marker);
        }
        
        // Center map on delivery
        this.map.easeTo({
            center: [position.lng, position.lat],
            duration: 1000
        });
    }
    
    async drawDeliveryRoute(route) {
        const coordinates = route.map(p => [p.lng, p.lat]);
        
        if (this.map.getSource('delivery-route')) {
            this.map.getSource('delivery-route').setData({
                type: 'Feature',
                geometry: {
                    type: 'LineString',
                    coordinates: coordinates
                }
            });
        } else {
            this.map.addSource('delivery-route', {
                type: 'geojson',
                data: {
                    type: 'Feature',
                    geometry: {
                        type: 'LineString',
                        coordinates: coordinates
                    }
                }
            });
            
            this.map.addLayer({
                id: 'delivery-route',
                type: 'line',
                source: 'delivery-route',
                paint: {
                    'line-color': '#4CAF50',
                    'line-width': 4,
                    'line-dasharray': [2, 1]
                }
            });
        }
    }
}

Best Practices

1. Lazy Load Map

// Only load map when needed
let map = null;

function initializeMap() {
    if (!map) {
        map = new maplibregl.Map(client.getMapOptions({
            container: 'map',
            center: [77.61, 12.93],
            zoom: 14
        }));
    }
    return map;
}

2. Handle Map Resize

// Resize map when container changes
window.addEventListener('resize', () => {
    if (map) {
        map.resize();
    }
});

// Or use ResizeObserver
const resizeObserver = new ResizeObserver(() => {
    map.resize();
});

resizeObserver.observe(document.getElementById('map'));

3. Optimize Performance

// Remove layers/sources when not needed
map.on('style.load', () => {
    if (map.getSource('temp-data')) {
        map.removeLayer('temp-layer');
        map.removeSource('temp-data');
    }
});

// Use canvas.toDataURL() sparingly
// Don't call it in animation loops

4. Error Handling

try {
    const map = new maplibregl.Map(client.getMapOptions({
        container: 'map'
    }));
    
    map.on('error', (e) => {
        console.error('Map error:', e.error);
    });
} catch (error) {
    console.error('Failed to initialize map:', error);
}

CSS Styling

Customize map appearance:

/* Custom marker styling */
.store-marker {
    cursor: pointer;
    transition: transform 0.2s;
}

.store-marker:hover {
    transform: scale(1.2);
}

/* Popup styling */
.maplibregl-popup-content {
    padding: 15px;
    border-radius: 8px;
    box-shadow: 0 2px 10px rgba(0,0,0,0.2);
}

.maplibregl-popup-content h3 {
    margin: 0 0 10px 0;
    color: #333;
}

/* Control customization */
.maplibregl-ctrl-group {
    border-radius: 5px;
    overflow: hidden;
}

Next Steps

On this page