How to Implement Elevation Profile Analysis in GeoLibre

GeoLibre's elevation profile feature enables users to draw a line on a MapLibre GL map, sample terrain elevations via the Open-Meteo API, compute distance statistics, and render interactive SVG charts that export to CSV and SVG formats.

This implementation provides a complete end-to-end workflow for terrain analysis in geographic web applications. By combining client-side geometry processing with external elevation services, GeoLibre delivers a lightweight yet powerful tool for outdoor planning and terrain visualization. The following guide explains how to implement elevation profile analysis using the official GeoLibre source architecture.

Architecture Overview

The elevation profile system in opengeos/GeoLibre follows a modular design split across five logical layers. Each layer handles specific responsibilities from user interaction to data persistence.

  • UI Control Layer – ElevationProfileControl.ts manages the MapLibre GL control button, floating panel interface, and user interactions including line drawing, unit toggling, and state persistence.
  • Geometry & Statistics Layer – geometry.ts provides pure-math utilities for resampling polylines, calculating haversine distances, and aggregating elevation statistics.
  • Data Fetching Layer – client.ts interfaces with the Open-Meteo API endpoint (https://api.open-meteo.com/v1/elevation), handling timeouts and error classification.
  • Chart Rendering Layer – profileChart.ts generates SVG paths for line visualization and area fills, plus scaling functions for hover interactions.
  • Export Layer – Helper methods in ElevationProfileControl serialize data to CSV and SVG formats, supporting both browser downloads and native file system integration via Tauri.

Step-by-Step Implementation Workflow

1. Initialize the Map Control

The process begins when users activate the elevation profile button. The _createMountainIcon method renders the control interface, while the panel registers click handlers for the drawing mode. When activated, the system listens for map clicks via _onMapClick, storing vertices in the _drawVertices array until the user double-clicks or presses Enter to finish.

2. Resample the Line Geometry

Once drawing completes, the _profileLine method calls resampleLine from packages/plugins/src/plugins/elevation-profile/elevation/geometry.ts. This function interpolates the user-drawn polyline into uniformly spaced segments, producing sampled.coords and sampled.distances arrays. The resampling respects the MAX_POINTS_PER_REQUEST constant (set to 100), ensuring API compliance while maintaining geographic accuracy.

3. Fetch Elevation Data

The fetchElevations function in client.ts constructs a query string from the resampled coordinates and sends a GET request to the Open-Meteo elevation endpoint. The implementation includes:

  • Timeout handling for network resilience
  • Response validation ensuring coordinate/elevation array length parity
  • Error wrapping via the custom ElevationFetchError class for debugging

4. Calculate Terrain Statistics

With elevation data returned, computeStats (in geometry.ts) iterates through the height array to derive:

  • Minimum and maximum elevation values
  • Cumulative ascent (gain) and descent (loss)
  • Total distance along the profile line

These metrics update the statistics panel in real-time.

5. Build Chart Geometry

The buildChartGeometry function in profileChart.ts transforms the distance/elevation pairs into SVG-ready data structures:

  • linePath – SVG path commands for the profile line
  • areaPath – Closed path for the filled area beneath the line
  • xScale / yScale – Linear mapping functions between data values and pixel coordinates
  • indexForX – Binary search utility for hover position lookup

6. Render Interactive Visualization

The _renderChart method constructs the SVG DOM element, attaches mousemove handlers for hover tracking, and updates the read-out box with distance and elevation values at the cursor position. The chart automatically adapts to the panelWidth configuration parameter.

7. Export Results

Users export data through two pathways:

  • CSV Export: _exportCsv calls profileToCsv (in export/csv.ts) to format coordinates and elevations as comma-separated values
  • SVG Export: _exportSvg inlines computed CSS styles and adds a background rectangle via _buildExportSvg for print-ready graphics

Both methods use the injected ExportTextFile callback when running in Tauri environments, falling back to browser Blob downloads otherwise.

8. Persist State

The getState and setState methods enable serialization of the profile state (collapsed, unitSystem, line), allowing GeoLibre to restore profiles from project files or deep-link URLs via the loadLine method.

Key Source Files and Their Functions

File Key Function Purpose
core/ElevationProfileControl.ts loadLine(), _exportCsv(), _exportSvg() Main MapLibre control class managing UI lifecycle, drawing logic, and exports
elevation/geometry.ts resampleLine(), computeStats() Pure geometric calculations including haversine distance and elevation aggregation
elevation/client.ts fetchElevations() Open-Meteo API wrapper with error handling and timeout management
chart/profileChart.ts buildChartGeometry() SVG path generation and scaling function creation
export/csv.ts profileToCsv() Data serialization for spreadsheet export
utils/deep-link.ts URL parameter parsing Helper for restoring profiles from query strings

Practical Implementation Examples

Adding the Control to Your Map

Instantiate the control with your preferred units and sample limits:

import { ElevationProfileControl } from
  'packages/plugins/src/plugins/elevation-profile/core/ElevationProfileControl';

const elevationControl = new ElevationProfileControl({
  title: 'Elevation Profile',
  unitSystem: 'metric',   // or 'imperial'
  panelWidth: 340,
  maxSamples: 80,        // Must be < MAX_POINTS_PER_REQUEST (100)
});

map.addControl(elevationControl, 'top-right');

Loading a Line Programmatically

Restore profiles from saved coordinates or deep links:

const line = [
  [-122.45, 37.78],
  [-122.44, 37.79],
  [-122.43, 37.80],
];

await elevationControl.loadLine(line);   // Draws line, fetches data, fits bounds

Triggering Exports

Call export methods directly from UI event handlers:

// Download as CSV
elevationControl._exportCsv();

// Download as SVG
elevationControl._exportSvg();

Switching Unit Systems

Cycle between measurement systems programmatically:

elevationControl._cycleUnits();   // Toggles metric ↔ imperial, updates labels

Error Handling and Performance Considerations

The implementation includes robust error boundaries. When fetchElevations encounters network timeouts, HTTP failures, or payload mismatches, it throws ElevationFetchError with descriptive context rather than failing silently.

For performance, the maxSamples configuration parameter (defaulting to 100) prevents API rate limiting while maintaining visual fidelity. The resampling algorithm in geometry.ts uses spherical haversine calculations for accurate distance measurement across large geographic spans.

Summary

  • GeoLibre implements elevation profile analysis through a five-layer architecture separating UI, geometry, network, rendering, and export concerns.
  • The Open-Meteo API provides free elevation data with a 100-point limit per request, handled transparently by the resampling logic in geometry.ts.
  • Interactive SVG charts are generated serverlessly via profileChart.ts, supporting hover interactions and responsive scaling.
  • State persistence methods enable deep-linking and project save/restore functionality across sessions.
  • Export utilities support both CSV (data analysis) and SVG (visualization) workflows with automatic environment detection.

Frequently Asked Questions

How does GeoLibre handle the Open-Meteo API's 100-point limit?

The resampleLine function in geometry.ts automatically interpolates user-drawn lines to meet the MAX_POINTS_PER_REQUEST constant (100 points). You can configure a lower limit via the maxSamples option in the control constructor to reduce API calls, though this reduces profile resolution.

What coordinate format does the elevation profile expect?

All internal functions expect arrays of [longitude, latitude] number pairs (EPSG:4326). The loadLine() method validates that input arrays contain at least two points before processing, throwing descriptive errors for malformed input.

Can I customize the chart appearance?

The buildChartGeometry function in profileChart.ts returns raw SVG path data and scaling functions, allowing you to override the _renderChart method in ElevationProfileControl.ts to inject custom CSS classes or modify the SVG structure before DOM insertion.

Does the elevation profile work offline?

No, the current implementation requires internet connectivity to reach https://api.open-meteo.com/v1/elevation. However, the geometry calculation and chart rendering modules are pure JavaScript functions that operate offline once elevation data is cached or provided programmatically via loadLine().

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →