Skip to content

Add a Color Relief Layer

Color relief (also called hypsometric tinting) paints the map with colors based on elevation — lowlands are green, mid-elevations are brown, mountain peaks are white. This makes elevation immediately visible at a glance.

No three.js or external libraries needed. This uses a standard raster layer with a color expression.

How Color Relief Works

Color relief paints the terrain surface with colors that represent altitude:

🌊 Water / low    → Deep blue / dark green
🌿 Plains         → Light green
🌄 Hills          → Yellow / brown
⛰️  Mountains      → Dark brown / grey
🏔️  Peaks          → White / light grey

The simplest approach is to use a hillshade layer with carefully chosen shadow/highlight colors, combined with a semi-transparent base map.

Adding Color Relief with Hillshade

javascript
map.addSource('dem', {
  type: 'raster-dem',
  tiles: ['https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png'],
  tileSize: 256,
  encoding: 'terrarium',
  maxzoom: 15,
});

map.addLayer({
  id: 'color-relief',
  type: 'hillshade',
  source: 'dem',
  paint: {
    'hillshade-shadow-color': '#2d6a4f',   // low elevation → green
    'hillshade-highlight-color': '#f8f9fa', // high elevation → white
    'hillshade-accent-color': '#8B4513',    // steep slopes → brown
    'hillshade-exaggeration': 0.8,
    'hillshade-illumination-anchor': 'viewport',
  },
});

Tweak the Relief Opacity

Adjust how strongly the color relief overlays the base map by changing its hillshade-exaggeration or by inserting the layer at a different position with map.addLayer(..., 'beforeLayerId'):

javascript
// Softer relief
map.setPaintProperty('color-relief', 'hillshade-exaggeration', 0.4);

// Stronger relief
map.setPaintProperty('color-relief', 'hillshade-exaggeration', 1);

// Hide / show the relief layer entirely
map.setLayoutProperty('color-relief', 'visibility', 'none');
map.setLayoutProperty('color-relief', 'visibility', 'visible');

Complete Example

html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <link href="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.css" rel="stylesheet" />
    <script src="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.js"></script>
    <style>body { margin: 0; } #map { height: 100vh; width: 100%; }</style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      const map = new mapmetricsgl.Map({
        container: 'map',
        zoom: 5,
        center: [13, 47],
        // Replace with your own MapMetrics style URL + token
        style: 'https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_STYLE.json&token=YOUR_TOKEN',
      });

      map.on('load', () => {
        map.addSource('dem', {
          type: 'raster-dem',
          tiles: ['https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png'],
          tileSize: 256,
          encoding: 'terrarium',
          maxzoom: 15,
        });

        map.addLayer({
          id: 'color-relief',
          type: 'hillshade',
          source: 'dem',
          paint: {
            'hillshade-shadow-color': '#2d6a4f',
            'hillshade-highlight-color': '#f8f9fa',
            'hillshade-accent-color': '#8B4513',
            'hillshade-exaggeration': 0.8,
            'hillshade-illumination-anchor': 'viewport',
          },
        });
      });

      map.addControl(new mapmetricsgl.NavigationControl(), 'top-right');
    </script>
  </body>
</html>
jsx
import React, { useEffect, useRef } from 'react';
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';

const ColorReliefLayer = () => {
  const mapContainer = useRef(null);
  const map = useRef(null);

  useEffect(() => {
    if (map.current) return;
    map.current = new mapmetricsgl.Map({
      container: mapContainer.current,
      zoom: 5,
      center: [13, 47],
      // Replace with your own MapMetrics style URL + token
      style: 'https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_STYLE.json&token=YOUR_TOKEN',
    });

    map.current.on('load', () => {
      map.current.addSource('dem', {
        type: 'raster-dem',
        tiles: ['https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png'],
        tileSize: 256,
        encoding: 'terrarium',
        maxzoom: 15,
      });

      map.current.addLayer({
        id: 'color-relief',
        type: 'hillshade',
        source: 'dem',
        paint: {
          'hillshade-shadow-color': '#2d6a4f',
          'hillshade-highlight-color': '#f8f9fa',
          'hillshade-accent-color': '#8B4513',
          'hillshade-exaggeration': 0.8,
          'hillshade-illumination-anchor': 'viewport',
        },
      });
    });

    map.current.addControl(new mapmetricsgl.NavigationControl(), 'top-right');
    return () => { map.current?.remove(); map.current = null; };
  }, []);

  return <div ref={mapContainer} style={{ height: '100vh', width: '100%' }} />;
};

export default ColorReliefLayer;

For more information, visit the MapMetrics GitHub repository.