rainview api integration
This commit is contained in:
@@ -8,9 +8,11 @@ import markerShadow from 'leaflet/dist/images/marker-shadow.png';
|
|||||||
import L from 'leaflet';
|
import L from 'leaflet';
|
||||||
import { Header } from '@components/Header';
|
import { Header } from '@components/Header';
|
||||||
import AirportLayer from '@components/AirportLayer.tsx';
|
import AirportLayer from '@components/AirportLayer.tsx';
|
||||||
import { useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Airport } from '@lib/airport.types.ts';
|
import { Airport } from '@lib/airport.types.ts';
|
||||||
import AirportDrawer from '@components/AirportDrawer.tsx';
|
import AirportDrawer from '@components/AirportDrawer.tsx';
|
||||||
|
import { getWeatherMapUrl } from '@lib/rainViewer.ts';
|
||||||
|
import { Switch } from '@mantine/core';
|
||||||
|
|
||||||
// Fix Leaflet's default icon path issues with Webpack
|
// Fix Leaflet's default icon path issues with Webpack
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
@@ -24,13 +26,22 @@ L.Icon.Default.mergeOptions({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const openStreetMapUrl = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';
|
const openStreetMapUrl = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';
|
||||||
// const rainViewerUrl = 'https://tilecache.rainviewer.com/v2/radar/{time}/256/10/290/391/2/1_1.png'
|
|
||||||
// https://api.rainviewer.com/public/weather-maps.json
|
|
||||||
const defaultZoom = 6;
|
const defaultZoom = 6;
|
||||||
const defaultCenter: L.LatLngExpression = [38.944444, -77.455833];
|
const defaultCenter: L.LatLngExpression = [38.944444, -77.455833];
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [airport, setAirport] = useState<Airport | null>(null);
|
const [airport, setAirport] = useState<Airport | null>(null);
|
||||||
|
const [rainViewerUrl, setRainViewerUrl] = useState<string | null>(null);
|
||||||
|
const [showRadar, setShowRadar] = useState<boolean>(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (showRadar) {
|
||||||
|
getWeatherMapUrl().then(url => {
|
||||||
|
setRainViewerUrl(url);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [showRadar])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='App'>
|
<div className='App'>
|
||||||
<Header />
|
<Header />
|
||||||
@@ -52,8 +63,21 @@ function App() {
|
|||||||
>
|
>
|
||||||
<ZoomControl position={'bottomright'} />
|
<ZoomControl position={'bottomright'} />
|
||||||
<TileLayer url={openStreetMapUrl} />
|
<TileLayer url={openStreetMapUrl} />
|
||||||
|
{ rainViewerUrl && showRadar && (
|
||||||
|
<TileLayer url={rainViewerUrl} opacity={0.5} zIndex={5} />
|
||||||
|
)}
|
||||||
<AirportLayer setAirport={setAirport} />
|
<AirportLayer setAirport={setAirport} />
|
||||||
</MapContainer>
|
</MapContainer>
|
||||||
|
<div style={{
|
||||||
|
position: 'absolute', top: '100px', right: '10px', zIndex: 1000, backgroundColor: '#fff',
|
||||||
|
borderRadius: '8px', boxShadow: '0 2px 6px rgba(0,0,0,0.15)', padding: '10px'
|
||||||
|
}}>
|
||||||
|
<Switch
|
||||||
|
label="Radar"
|
||||||
|
checked={showRadar}
|
||||||
|
onChange={(event) => setShowRadar(event.currentTarget.checked)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
36
ui/src/lib/rainViewer.ts
Normal file
36
ui/src/lib/rainViewer.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { WeatherMaps } from '@lib/rainViewer.types.ts';
|
||||||
|
|
||||||
|
const weatherMapsUrl = 'https://api.rainviewer.com/public/weather-maps.json';
|
||||||
|
|
||||||
|
async function getWeatherMaps(): Promise<WeatherMaps | undefined> {
|
||||||
|
const response = await fetch(`${weatherMapsUrl}`, {
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
if (response?.status === 200) {
|
||||||
|
return response.json();
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// const rainViewerUrl = 'https://tilecache.rainviewer.com/v2/radar/1744386000/256/{z}/{x}/{y}/2/1_1.png';
|
||||||
|
// const rainViewerUrl = 'https://tilecache.rainviewer.com/v2/radar/1744386000/256/10/290/391/2/1_1.png'
|
||||||
|
// https://api.rainviewer.com/public/weather-maps.json
|
||||||
|
export async function getWeatherMapUrl(): Promise<string | null> {
|
||||||
|
const weatherMaps = await getWeatherMaps();
|
||||||
|
if (weatherMaps != undefined) {
|
||||||
|
let url = weatherMaps.host;
|
||||||
|
let latest = "";
|
||||||
|
if (weatherMaps.radar.nowcast.length > 0) {
|
||||||
|
latest = weatherMaps.radar.nowcast[weatherMaps.radar.nowcast.length - 1].path;
|
||||||
|
} else if (weatherMaps.radar.past.length > 0) {
|
||||||
|
latest = weatherMaps.radar.past[weatherMaps.radar.past.length - 1].path;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
url += latest + "/256/{z}/{x}/{y}/2/1_1.png";
|
||||||
|
return url;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
21
ui/src/lib/rainViewer.types.ts
Normal file
21
ui/src/lib/rainViewer.types.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
export interface WeatherMaps {
|
||||||
|
version: string;
|
||||||
|
generated: number;
|
||||||
|
host: string;
|
||||||
|
radar: RadarObject;
|
||||||
|
satellite: SatelliteObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RadarObject {
|
||||||
|
past: FrameObject[];
|
||||||
|
nowcast: FrameObject[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SatelliteObject {
|
||||||
|
infrared: FrameObject[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FrameObject {
|
||||||
|
time: number;
|
||||||
|
path: string;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user