How to display GPX track elevation profile

The elevation profile control for MapTiler SDK is a super easy way to show the elevation profile of any GPX (GPS) trace or GeoJSON. By utilizing elevation data from MapTiler, this feature allows you to effortlessly showcase the elevation profile of your hiking routes, bicycle routes, trail runs, and more.

Following this step-by-step example, you can easily view the profile of various activities.

Drag and drop a GPX file onto the map to view your track profile.

  1. Install the npm package.

npm install --save @maptiler/sdk @maptiler/elevation-profile-control
  1. Create the map style. Add the map style to your stylesheet. The div must have a non-zero height.

    body { 
      margin: 0;
      padding: 0;
    }
    
    #map {
        position: absolute;
        top: 0;
        bottom: 0;
        width: 100%;
    }
    
  1. Create a <div> element with a certain id where you want your map to be.

    Add <div> tag into your page. This div will be the container where the map will be loaded.


<div id="map"></div>
  1. Create a <div> element with a certain id where you want your control to be.

    Add <div> tag into your page. This div will be the container where the control will be loaded.


<div id="profileContainer"></div>
  1. Include the CSS file.

    If you have a bundler that can handle CSS, you can import the CSS from @maptiler/sdk/dist/maptiler-sdk.css.


import '@maptiler/sdk/dist/maptiler-sdk.css';
<div class="markdown-alert markdown-alert-note" markdown="1">
<p class="markdown-alert-title">Note</p>
Including the CSS file using a `<link>` in the head of the document via the CDN is the easiest way.


<pre class="language-html" style="position: relative;" markdown="0"><code class="language-html">
&lt;link href=&#39;https://cdn.maptiler.com/maptiler-sdk-js/v4.1.0/maptiler-sdk.css&#39; rel=&#39;stylesheet&#39; /&gt; </code></pre>


</div>
  1. Load the map with the style. Include the following code in your JavaScript.

import { config, Map, helpers, MapStyle } from '@maptiler/sdk';
    
    config.apiKey = 'YOUR_MAPTILER_API_KEY_HERE';
    const map = new Map({
        container: 'map', // container's id or the HTML element in which SDK will render the map
        style: MapStyle.OUTDOOR,
        center: [7.6011, 45.9078], // starting position [lng, lat]
        zoom: 11.39 // starting zoom
    });
  1. Replace YOUR_MAPTILER_API_KEY_HERE with your own API key. Make sure to secure the key before you publish it.

  2. We are going to define some variables that we will use later in the tutorial.


let polyline, epc, marker;
  1. Add a GPX trace to the map. You can use a GPX directly from a URL or upload your GPX to the MapTiler. Check out the How to edit your data in MapTiler tutorial. Download the Cervinia Valtournenche mountain bike sample data

map.on('load', async () => {

      polyline = await helpers.addPolyline(map, {
        data: 'https://docs.maptiler.com/sdk-js/assets/cervinia-valtournenche.gpx', //from a URL or a MapTiler Data UUID
        lineColor: '#66f',
        lineWidth: 4, 
        outline: true, 
        outlineWidth: 2
      });

    });
  1. Add the Marker object to the @maptiler/sdk import.

import { config, Map, helpers, MapStyle, Marker } from '@maptiler/sdk';
  1. Create a marker and add it to the map. We will use this marker to display the location of the elevation profile cursor with the position of the marker on the map.

map.on('load', async () => {

      polyline = await helpers.addPolyline(map, {
        data: 'https://docs.maptiler.com/sdk-js/assets/cervinia-valtournenche.gpx', //from a URL or a MapTiler Data UUID
        lineColor: '#66f', 
        lineWidth: 4, 
        outline: true, 
        outlineWidth: 2
      });

      marker = new Marker()
        .setLngLat([0, 0])
        .addTo(map);

    });
  1. Import the MapTiler elevation profile control

import { ElevationProfileControl } from "@maptiler/elevation-profile-control";
  1. Instantiate the control and add it to a Map instance, most likely inside a map "load" event callback

map.on('load', async () => {

      polyline = await helpers.addPolyline(map, {
        data: 'https://docs.maptiler.com/sdk-js/assets/cervinia-valtournenche.gpx', //from a URL or a MapTiler Data UUID
        lineColor: '#66f', 
        lineWidth: 4, 
        outline: true, 
        outlineWidth: 2
      });

      marker = new Marker()
        .setLngLat([0, 0])
        .addTo(map);

      // Create an instance
      epc = new ElevationProfileControl({
        container: "profileContainer",
        visible: true,
        showButton: false,
        profileLineColor: "#66f",
        profileBackgroundColor: "#a103fc11",
        displayTooltip: true,
        onMove: (data) => {
          marker.setLngLat(data.position)
        },
      });

      // Add it to your map
      map.addControl(epc);

      // Add some data (from a URL or a MapTiler Data UUID)
      const sourceObject = map.getSource(polyline.polylineSourceId);
      epc.setData(sourceObject._data);

      moveMarkerToGPXStart(sourceObject._data);

    });
  1. Move the Marker to the GPX start point

function moveMarkerToGPXStart(data) {
      marker.setLngLat(data.features[0].geometry.coordinates[0])
    }
  1. Let’s add some styling to the profile control to see the track profile on the map along with your GPS track.

#profileContainer {
      background:#fff;
      width: 50vw;
      height: 200px;
      margin-top: 20px;
      position: absolute;
      bottom: 10px;
      opacity: 0.9;
    }
  1. With these steps, you have your map where the GPX track is shown with its elevation profile. In the following steps, we will see how to add the functionality of dragging and dropping a GPX file on the map to view the new track along with its profile.

  2. Use the HTML Drag and Drop API to drag a file onto our map.


document.getElementById('map').addEventListener('drop', function(ev) {
        ev.preventDefault();

        if (ev.dataTransfer.files) {
          // Use DataTransfer interface to access the file(s)
          [...ev.dataTransfer.files].forEach((file, i) => {
            readGPXFile(file);
          });
        } else {
          // Use DataTransferItemList interface to access the file(s)
          [...ev.dataTransfer.items].forEach((item, i) => {
            // If dropped items aren't files, reject them
            if (item.kind === "file") {
              const file = item.getAsFile();
              readGPXFile(file);
            }
          });
        }
      });
      document.getElementById('map').addEventListener('dragover', function(ev) {
        ev.preventDefault();
      });
  1. Add the gpx function and the LngLatBounds object to the @maptiler/sdk import.

import { config, Map, helpers, MapStyle, Marker, gpx, LngLatBounds } from '@maptiler/sdk';
  1. Read the GPX file data. To read the content of the file in the browser without having to upload it to any server, we will use the FileReader object.

function readGPXFile(file){
      if (file.name.split('.').pop().toLowerCase() !== 'gpx') {
        return;
      }
      const reader = new FileReader();
      reader.onload = function (event) {
        const sourceObject = map.getSource(polyline.polylineSourceId);
        sourceObject.setData(gpx(event.target.result));

        epc.setData(sourceObject._data);
        fitToDataBounds(sourceObject._data);
      };
      reader.readAsText(file, 'UTF-8');
    }
  1. Adjust the map view to the newly loaded track and move the marker to the track start point.

function fitToDataBounds(data) {
      // Geographic coordinates of the LineString
      const coordinates = data.features[0].geometry.coordinates;

      // Pass the first coordinates in the LineString to `lngLatBounds` &
      // wrap each coordinate pair in `extend` to include them in the bounds
      // result. A variation of this technique could be applied to zooming
      // to the bounds of multiple Points or Polygon geomteries - it just
      // requires wrapping all the coordinates with the extend method.
      const bounds = coordinates.reduce((bounds, coord) => {
          return bounds.extend(coord);
      }, new LngLatBounds(coordinates[0], coordinates[0]));

      map.fitBounds(bounds, {
        padding: 20
      });
      moveMarkerToGPXStart(data);
    }

Learn more

You can also use elevation control via CDN. See the Elevation profile control example to use it as a CDN instead of an NPM module.

Add a GPX Line layer (polyline helper)

Add a GPX Line layer (polyline helper)

Examples

Add GPX line layer using MapTiler polyline helper.

Show the trace position with Elevation profile control

Show trace position Elevation profile control

Examples

Synchronize a moving map marker with elevation profile cursor.

Customize Elevation profile control

Customize Elevation profile control

Examples

Customize the MapTiler SDK elevation profile control interface.

Display a 3D terrain map

3D terrain map

Tutorials

Create and display 3D terrain maps on web pages.

Was this helpful?