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-glQuick 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.
getMapOptions() (Recommended)
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
| Parameter | Type | Required | Description |
|---|---|---|---|
container | string/HTMLElement | Yes | Map container element or ID |
style | string | No | Map style name (default: default-light-standard) |
center | array | No | Center coordinates [lng, lat] (default: [77.61, 12.93]) |
zoom | number | No | Zoom 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);
});Navigation Controls
// 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 loops4. 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
- Explore Examples for complete working demos
- Check Places API for adding points of interest
- Learn about Routing API for drawing routes
- Visit MapLibre GL Documentation for advanced features