Skip to main content

Route Profile

|

In this guide you will learn how to display a map, calculate routes between multiple points, and show a detailed route profile with elevation data and terrain analysis.

How it Works

This example demonstrates the following key features:

  • Calculates routes and renders them on the map
  • Displays elevation profile with interactive charts
  • Shows terrain analysis including slopes and climbs
  • Provides road and surface type information
  • Allows filtering and highlighting specific route attributes

Live Demo

Try the interactive demo below. Click "Build Route" to see the elevation profile and route analysis:

Code Implementation

Building Route with Profile Data

Calculate a route and generate terrain profile data:

index.ts
async function onBuildRouteButtonPressed() {
console.log('Build route button pressed');
showMessage('Calculating terrain route...');

try {
// Define the departure (Swiss Alps - start point)
const departureLandmark = Landmark.withCoordinates(
Coordinates.fromLatLong(46.59344, 7.91069)
);

// Define the destination (Swiss Alps - end point)
const destinationLandmark = Landmark.withCoordinates(
Coordinates.fromLatLong(46.55945, 7.89293)
);

// Define the route preferences with terrain profile enabled
const routePreferences = new RoutePreferences({
buildTerrainProfile: new BuildTerrainProfile({ enable: true }),
transportMode: RouteTransportMode.pedestrian
});

const routes = await calculateRoute([departureLandmark, destinationLandmark], routePreferences);

if (routes && routes.length > 0) {
showMessage('Route calculated successfully!');

const routesMap = map?.preferences.routes;

for (const route of routes) {
const routeRenderSettings = new RouteRenderSettings({options: new Set([
RouteRenderOptions.showTraffic,
RouteRenderOptions.showHighlights,
])});
const isMainRoute = route === routes[0];
routesMap?.add(route, isMainRoute, {
routeRenderSettings: routeRenderSettings
});
}

if (routesMap) {
routesMap.mainRoute = routes[0];
}

focusedRoute = routes[0];
centerOnRoute([focusedRoute]);
createRouteProfilePanel(focusedRoute);
updateUI();

} else {
showMessage('Route calculation failed.');
}
} catch (error) {
console.error('Error in onBuildRouteButtonPressed:', error);
showMessage('Route calculation error.');
}
}

Building Terrain Profile

Generate and display elevation and terrain data:

index.ts
function createElevationSection(route: Route): HTMLElement {
const section = document.createElement('div');
section.style.cssText = `
background: white; padding: 20px; border-radius: 12px; margin-bottom: 20px;
box-shadow: 0 4px 12px rgba(0,0,0,0.05); border: 1px solid #f0f0f0;
`;

const title = document.createElement('h3');
title.textContent = 'Elevation Profile';
title.style.cssText = 'margin: 0 0 16px 0; color: #333; font-size: 15px; font-weight:600;';
section.appendChild(title);

const samples = getElevationSamples(route);
if (samples.length > 0) {
section.appendChild(createSimpleElevationChart(samples, route));
} else {
section.innerHTML += '<div style="color:#999;font-style:italic;">No data</div>';
}
return section;
}

Displaying Terrain Statistics

Show elevation gain, loss, and slope information:

index.ts
function createInteractiveSliderSection(title: string, type: string, route: Route): HTMLElement {
const section = document.createElement('div');
section.style.cssText = `
background: white; padding: 20px; border-radius: 12px; margin-bottom: 20px;
box-shadow: 0 4px 12px rgba(0,0,0,0.05); border: 1px solid #f0f0f0;
`;

const titleEl = document.createElement('h3');
titleEl.textContent = title;
titleEl.style.cssText = 'margin: 0 0 16px 0; color: #333; font-size: 15px; font-weight:600;';
section.appendChild(titleEl);

const mockSections = createMockSections(type);

const barContainer = document.createElement('div');
barContainer.style.cssText = `
position: relative; height: 32px; border-radius: 6px; overflow: hidden;
margin-bottom: 16px; background: #f5f5f5; display: flex;
`;

mockSections.forEach((sec) => {
const seg = document.createElement('div');
seg.style.width = `${sec.percent * 100}%`;
seg.style.backgroundColor = sec.color;
seg.title = `${sec.name}`;
barContainer.appendChild(seg);
});

// Slider Controls
const sliderContainer = document.createElement('div');
sliderContainer.style.cssText = 'position: relative; margin-top: -32px; z-index: 5; height:32px;';

const slider = document.createElement('input');
slider.type = 'range';
slider.min = '0';
const totalDistance = route.getTimeDistance().unrestrictedDistanceM + route.getTimeDistance().restrictedDistanceM;
slider.max = totalDistance.toString();
slider.value = '0';
slider.style.cssText = `
width: 100%; height: 32px; cursor: pointer; position:absolute; top:0; left:0;
background: transparent; -webkit-appearance: none; appearance: none; outline: none; margin:0;
`;

// Inject style for slider thumb
const styleId = `slider-${type.replace(/\s/g,'')}-${Date.now()}`;
const style = document.createElement('style');
style.textContent = `
#${styleId}::-webkit-slider-thumb {
-webkit-appearance: none; width: 4px; height: 32px; background: #212121;
border: 1px solid white; box-shadow: 0 0 4px rgba(0,0,0,0.5); cursor: pointer;
}
#${styleId}::-moz-range-thumb {
width: 4px; height: 32px; background: #212121; border: 1px solid white; cursor: pointer;
}
`;
document.head.appendChild(style);
slider.id = styleId;

sliderContainer.appendChild(slider);
section.appendChild(barContainer);
section.appendChild(sliderContainer);

const info = document.createElement('div');
info.style.cssText = 'font-size: 13px; color: #666; margin-top:8px; display:flex; justify-content:space-between;';
const infoText = document.createElement('span');
infoText.textContent = 'Drag to analyze';
info.appendChild(infoText);
section.appendChild(info);

// Logic
const updateAnalysis = (val: number) => {
const sec = findSectionAtDistance(val, totalDistance, mockSections);
infoText.innerHTML = `<strong>${sec.name}</strong> at ${convertDistance(val)}`;
// IMPORTANT: Pass the full section object to highlightRouteSection
highlightRouteSection(route, sec, val);
};

slider.addEventListener('input', (e) => updateAnalysis(parseFloat((e.target as HTMLInputElement).value)));

return section;
}

Key Features

  • Elevation Profile: Visual representation of route elevation changes
  • Terrain Analysis: Detailed slope, climb, and descent information
  • Surface Types: Road and surface type breakdown
  • Interactive Charts: Clickable elevation profile to highlight route segments
  • Statistics: Total elevation gain/loss, max slope, and more

Next Steps