---
title: "Weather layer with a custom color blind ramp | Weather SDK | JavaScript maps SDK"
description: "Visualize temperature layer with custom color blind ramp."
---

> For AI agents: a documentation index is available at [/llms.txt](https://docs.maptiler.com/llms.txt). Markdown versions of all pages are available by appending .md to any URL.

# Weather layer with a custom color blind ramp

Experience the power of visualizing weather temperature data with the MapTiler Weather Temperature dataset. Utilize a personalized color scheme designed specifically for individuals with color blindness, and easily access temperature information for any location by simply hovering over it.

In the temperature layer, we use one of the color ramps built-in in the SDK. Using the `animateByFactor(3600)` function of the temperature layer, we can create a dynamic time-based animation for the next 4 days. Each second of animation corresponds to one hour.

### NPM module setup

```bash
npm install --save @maptiler/sdk @maptiler/weather
```

#### main.js

```js
import { Map, MapStyle, config } from '@maptiler/sdk';
import '@maptiler/sdk/dist/maptiler-sdk.css';
import { TemperatureLayer, ColorRamp } from '@maptiler/weather';

config.apiKey = 'YOUR_MAPTILER_API_KEY_HERE';
const map = (window.map = new Map({
  container: 'map', // container's id or the HTML element to render the map
  style: MapStyle.BACKDROP,  // stylesheet location
  zoom: 3,
  center: [-94.77, 38.57],
  hash: true,
  projectionControl: true,
}));

const timeTextDiv = document.getElementById("time-text");
const pointerDataDiv = document.getElementById("pointer-data");
let pointerLngLat = null;

// You can define a custom color ramp using an extensive definition such as this one:
const customColoramp = new ColorRamp({ 
  stops: [
    { value: -65, color: [49, 54, 149, 255] },
    { value: -40, color: [69, 117, 180, 255] },
    { value: -30, color: [116, 173, 209, 255] },
    { value: -20, color: [171, 217, 233, 255] },
    { value: -10, color: [224, 243, 248, 255] },
    { value: 0, color: [255, 255, 255, 255] },
    { value: 12, color: [255, 255, 191, 255] },
    { value: 20, color: [254, 224, 144, 255] },
    { value: 25, color: [253, 174, 97, 255] },
    { value: 30, color: [244, 109, 67, 255] },
    { value: 40, color: [215,48,39, 255] },
    { value: 55, color: [165, 0, 38, 255] },
  ],
});

const weatherLayer = new TemperatureLayer({
  colorramp: customColoramp
});

// Called when the animation is progressing
weatherLayer.on("tick", event => {
  refreshTime();
  updatePointerValue(pointerLngLat);
});

map.on('load', function () {
  map.setPaintProperty("Water", 'fill-color', "rgba(0, 0, 0, 0.4)");
  map.addLayer(weatherLayer, 'Water');
  weatherLayer.animateByFactor(3600);
});

map.on('mouseout', function(evt) {
  if (!evt.originalEvent.relatedTarget) {
    pointerDataDiv.innerText = "";
    pointerLngLat = null;
  }
});

// Update the date time display
function refreshTime() {
  const d = weatherLayer.getAnimationTimeDate();
  timeTextDiv.innerText = d.toString();
}

function updatePointerValue(lngLat) {
  if (!lngLat) return;
  pointerLngLat = lngLat;
  const value = weatherLayer.pickAt(lngLat.lng, lngLat.lat);
  if (!value) {
    pointerDataDiv.innerText = "";
    return;
  }
  pointerDataDiv.innerText = `${value.value.toFixed(1)}°`;
}

map.on('mousemove', (e) => {
  updatePointerValue(e.lngLat);
});

class colorRampLegendControl {
  constructor(options) {
    this._options = {...options};
    this._container = document.createElement("div");
    this._container.classList.add("maplibregl-ctrl");
    this._container.classList.add("maplibregl-ctrl-color-ramp");
  }
  onAdd(map) {
    this._map = map;
    const colorramp = this._options.colorRamp;
    const canvas = colorramp.getCanvasStrip();
    canvas.style.height = "30px";
    canvas.style.width = "200px";
    canvas.style.border = "1px dashed #00000059";

    const bounds = colorramp.getBounds()

    const desc = document.createElement("div");
    desc.classList.add("color-ramp-label");
    desc.innerHTML = `(min: ${bounds.min}, max: ${bounds.max})`;
    
    this._container.appendChild(desc);
    this._container.appendChild(canvas);
    return this._container;
  }
  onRemove() {
    if (!this._map || !this._container) {
      return;
    }
    this._container.parentNode.removeChild(this._container);
    this._map = undefined;
    delete this._map;
  }
}

map.addControl(new colorRampLegendControl({colorRamp: customColoramp}), 'bottom-left');
```

#### index.html

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="robots" content="noindex" />
    <title>Weather layer with a custom color blind ramp | NPM example</title>
    <link rel="stylesheet" href="./style.css" />
  </head>
  <body>
    <div id="time-info">
      <span id="time-text"></span>
    </div>
    <div id="variable-name">Temperature</div>
    <div id="pointer-data"></div>
    <div id="map"></div>
    <script type="module" src="./main.js"></script>
  </body>
</html>
```

#### style.css

```css
body { margin: 0; padding: 0; font-family: sans-serif; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; background-color: #444952;}
#pointer-data {
  z-index: 1;
  position: fixed;
  font-size: 20px;
  font-weight: 900;
  margin: 27px 0px 0px 10px;
  color: #fff;
  text-shadow: 0px 0px 10px #0007;
}

#variable-name {
  z-index: 1;
  position: fixed;
  font-size: 20px;
  font-weight: 500;
  margin: 5px 0px 0px 10px;
  color: #fff;
  text-shadow: 0px 0px 10px #0007;
}

#time-info {
  position: fixed;
  width: 60vw;
  bottom: 0;
  z-index: 1;
  margin: 10px;
  text-shadow: 0px 0px 5px black;
  color: white;
  font-size: 18px;
  font-weight: 500;
  text-align: center;
  left: 0;
  right: 0;
  margin: auto;
  padding: 20px;
}

#time-text {
  font-size: 12px;
  font-weight: 600;
}

.maplibregl-ctrl-color-ramp {
  color: #333359;
  position: relative;
  padding: 6px 8px;
  font-family: OpenSans Semibold, OpenSans Regular, OpenSans Italic;
  background: white;
  box-shadow: 0 0 15px rgb(0 0 0 / 20%);
  border-radius: 5px;
  bottom: 0;
  right: 0;
  margin: 10px;
}

.color-ramp-label {
  font-size: 16px;
}
```

### Basic JavaScript setup

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Display a temperature layer</title>
  <script src="https://cdn.maptiler.com/maptiler-sdk-js/v4.2.0/maptiler-sdk.umd.min.js"></script>
  <link href="https://cdn.maptiler.com/maptiler-sdk-js/v4.2.0/maptiler-sdk.css" rel="stylesheet" />
  <script src="https://cdn.maptiler.com/maptiler-weather/v4.0.1/maptiler-weather.umd.min.js"></script>
  <style>
    body { margin: 0; padding: 0; font-family: sans-serif; }
    #map { position: absolute; top: 0; bottom: 0; width: 100%; background-color: #444952;}
    #pointer-data {
      z-index: 1;
      position: fixed;
      font-size: 20px;
      font-weight: 900;
      margin: 27px 0px 0px 10px;
      color: #fff;
      text-shadow: 0px 0px 10px #0007;
    }

    #variable-name {
      z-index: 1;
      position: fixed;
      font-size: 20px;
      font-weight: 500;
      margin: 5px 0px 0px 10px;
      color: #fff;
      text-shadow: 0px 0px 10px #0007;
    }

    #time-info {
      position: fixed;
      width: 60vw;
      bottom: 0;
      z-index: 1;
      margin: 10px;
      text-shadow: 0px 0px 5px black;
      color: white;
      font-size: 18px;
      font-weight: 500;
      text-align: center;
      left: 0;
      right: 0;
      margin: auto;
      padding: 20px;
    }

    #time-text {
      font-size: 12px;
      font-weight: 600;
    }

    .maplibregl-ctrl-color-ramp {
      color: #333359;
      position: relative;
      padding: 6px 8px;
      font-family: OpenSans Semibold, OpenSans Regular, OpenSans Italic;
      background: white;
      box-shadow: 0 0 15px rgb(0 0 0 / 20%);
      border-radius: 5px;
      bottom: 0;
      right: 0;
      margin: 10px;
    }

    .color-ramp-label {
      font-size: 16px;
    }
  </style>
</head>
<body>
  <div id="time-info">
    <span id="time-text"></span>
  </div>
  <div id="variable-name">Temperature</div>
  <div id="pointer-data"></div>
  <div id="map"></div>
  <script>
      maptilersdk.config.apiKey = 'YOUR_MAPTILER_API_KEY_HERE';
      const map = (window.map = new maptilersdk.Map({
        container: 'map', // container's id or the HTML element to render the map
        style: maptilersdk.MapStyle.BACKDROP,  // stylesheet location
        zoom: 3,
        center: [-94.77, 38.57],
        hash: true,
        projectionControl: true,
      }));

      const timeTextDiv = document.getElementById("time-text");
      const pointerDataDiv = document.getElementById("pointer-data");
      let pointerLngLat = null;

      // You can define a custom color ramp using an extensive definition such as this one:
      const customColoramp = new maptilerweather.ColorRamp({ 
        stops: [
          { value: -65, color: [49, 54, 149, 255] },
          { value: -40, color: [69, 117, 180, 255] },
          { value: -30, color: [116, 173, 209, 255] },
          { value: -20, color: [171, 217, 233, 255] },
          { value: -10, color: [224, 243, 248, 255] },
          { value: 0, color: [255, 255, 255, 255] },
          { value: 12, color: [255, 255, 191, 255] },
          { value: 20, color: [254, 224, 144, 255] },
          { value: 25, color: [253, 174, 97, 255] },
          { value: 30, color: [244, 109, 67, 255] },
          { value: 40, color: [215,48,39, 255] },
          { value: 55, color: [165, 0, 38, 255] },
        ],
      });

      const weatherLayer = new maptilerweather.TemperatureLayer({
        colorramp: customColoramp
      });

      // Called when the animation is progressing
      weatherLayer.on("tick", event => {
        refreshTime();
        updatePointerValue(pointerLngLat);
      });

      map.on('load', function () {
        map.setPaintProperty("Water", 'fill-color', "rgba(0, 0, 0, 0.4)");
        map.addLayer(weatherLayer, 'Water');
        weatherLayer.animateByFactor(3600);
      });

      map.on('mouseout', function(evt) {
        if (!evt.originalEvent.relatedTarget) {
          pointerDataDiv.innerText = "";
          pointerLngLat = null;
        }
      });

      // Update the date time display
      function refreshTime() {
        const d = weatherLayer.getAnimationTimeDate();
        timeTextDiv.innerText = d.toString();
      }

      function updatePointerValue(lngLat) {
        if (!lngLat) return;
        pointerLngLat = lngLat;
        const value = weatherLayer.pickAt(lngLat.lng, lngLat.lat);
        if (!value) {
          pointerDataDiv.innerText = "";
          return;
        }
        pointerDataDiv.innerText = `${value.value.toFixed(1)}°`;
      }

      map.on('mousemove', (e) => {
        updatePointerValue(e.lngLat);
      });

      class colorRampLegendControl {
        constructor(options) {
          this._options = {...options};
          this._container = document.createElement("div");
          this._container.classList.add("maplibregl-ctrl");
          this._container.classList.add("maplibregl-ctrl-color-ramp");
        }
        onAdd(map) {
          this._map = map;
          const colorramp = this._options.colorRamp;
          const canvas = colorramp.getCanvasStrip();
          canvas.style.height = "30px";
          canvas.style.width = "200px";
          canvas.style.border = "1px dashed #00000059";

          const bounds = colorramp.getBounds()

          const desc = document.createElement("div");
          desc.classList.add("color-ramp-label");
          desc.innerHTML = `(min: ${bounds.min}, max: ${bounds.max})`;
          
          this._container.appendChild(desc);
          this._container.appendChild(canvas);
          return this._container;
        }
        onRemove() {
          if (!this._map || !this._container) {
            return;
          }
          this._container.parentNode.removeChild(this._container);
          this._map = undefined;
          delete this._map;
        }
      }

      map.addControl(new colorRampLegendControl({colorRamp: customColoramp}), 'bottom-left');
  </script>
</body>
</html>
```

## Learn more

Check out the [Weather JS module reference](https://docs.maptiler.com/sdk-js/modules/weather/)

Check out the [Temperature layer reference](https://docs.maptiler.com/sdk-js/modules/weather/api/temperature/)

Check out the [Color ramp reference](https://docs.maptiler.com/sdk-js/modules/weather/api/color-ramp/)

## Related examples

### [Weather custom popup](https://docs.maptiler.com/sdk-js/examples/weather-custom-popup/)

Examples

Create highly customizable popups for weather maps using MarkerLayout.

### [Weather layer switcher](https://docs.maptiler.com/sdk-js/examples/weather-layer-switcher/)

Examples

Switch weather layers and view detailed data under cursors.

### [Weather wind and temperature layer](https://docs.maptiler.com/sdk-js/examples/weather-wind-temperature/)

Examples

Visualize wind and temperature layers with cursor data.

### [Custom color ramp (color ramp)](https://docs.maptiler.com/sdk-js/examples/color-ramp-custom/)

Examples

Visualize point layers by creating custom map color ramps.
