How to create a weather map with react-leaflet
April 28th, 2023

Overview

react-leaflet is a popular front-end framework for displaying map data. They have a bunch of great examples on their site for creating maps from openstreetmap data. I haven't seen an example which displays radar data on top of those maps, so I thought I'd create a simple example which uses rainviewer as the source for those radar maps.

The code below has been used to create this demo.

Basic Map

Let's start with a simple foundation, where we just have a simple map we can drag around. No radar data yet. This is similiar to what is on the react-leaflet site and just a zoomed out view of Seattle.

<div> <MapContainer center={[47.606, -122.332]} zoom={8} scrollWheelZoom={true} style={{ height: "100vh", width: "100vw" }} > <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> </MapContainer> </div>

Adding Radar Data

What we want is radar data which will render on top of the basic map we have. We can do this by adding another TileLayer component alongside the one we have for the basic map. It will look something like this:

<TileLayer attribution="RainViewer.com" url={`https://tilecache.rainviewer.com${mostRecentWeatherMap}/256/{z}/{x}/{y}/2/1_1.png`} opacity={0.6} zIndex={2} />

All we need for this code snippet is a value for mostRecentWeatherMap. Since this is a path which represents the most recent weather map for the world, this value will always be changing. You can run the following bit of code to get a recent path value to use:

const getMostRecentWeatherMap = async () => { const res = await fetch( "https://api.rainviewer.com/public/weather-maps.json" ); const resJson = await res.json(); return resJson.radar.nowcast[0].path; };

You should get a value like /v2/radar/nowcast_61417de9b2bb.

In my demo, I run that bit of code in a useEffect and store the path in a state variable.

Putting it altogether, this is the code for my demo (using typescript):

import { useEffect, useState } from "react"; import { MapContainer, TileLayer } from "react-leaflet"; import "leaflet/dist/leaflet.css"; const RADAR_MAPS_URL = "https://api.rainviewer.com/public/weather-maps.json"; type RadarMapsResponse = { generated: number; host: string; radar: { past: RadarLayer[]; nowcast: RadarLayer[]; }; }; type RadarLayer = { time: number; path: string; }; const getMostRecentWeatherMap = async () => { const res = await fetch(RADAR_MAPS_URL); const resJson = (await res.json()) as RadarMapsResponse; return resJson.radar.nowcast[0].path; }; const WeatherMap = () => { const [mostRecentWeatherMap, setMostRecentWeatherMap] = useState< null | string >(null); useEffect(() => { (async () => { const path = await getMostRecentWeatherMap(); setMostRecentWeatherMap(path); })(); }); if (!mostRecentWeatherMap) { return <div>Loading...</div>; } return ( <div> <MapContainer center={[47.606, -122.332]} zoom={8} scrollWheelZoom={true} style={{ height: "100vh", width: "100vw" }} > <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> <TileLayer attribution="RainViewer.com" url={`https://tilecache.rainviewer.com${mostRecentWeatherMap}/256/{z}/{x}/{y}/2/1_1.png`} opacity={0.6} zIndex={2} /> </MapContainer> </div> ); }; export default WeatherMap;