Working on sky conditions display:
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
import { Airport } from './airport.types';
|
||||
import { Metar } from './metar.types';
|
||||
import { getRequest } from '.';
|
||||
|
||||
@@ -6,11 +5,11 @@ interface GetMetarsResponse {
|
||||
data: Metar[];
|
||||
}
|
||||
|
||||
export async function getMetars(airports: Airport[]): Promise<GetMetarsResponse> {
|
||||
if (airports.length == 0) {
|
||||
export async function getMetars(icaos: string[]): Promise<GetMetarsResponse> {
|
||||
if (icaos.length == 0) {
|
||||
return { data: [] };
|
||||
}
|
||||
const stationICAOs: string = airports.map((airport) => airport.icao).join(',');
|
||||
const stationICAOs: string = icaos.map((icao) => icao).join(',');
|
||||
const response = await getRequest(`metars/${stationICAOs}`, {});
|
||||
return response?.data || { data: [] };
|
||||
}
|
||||
|
||||
@@ -2,16 +2,23 @@
|
||||
|
||||
import { getAirport } from '@/api/airport';
|
||||
import { Airport } from '@/api/airport.types';
|
||||
import Link from 'next/link';
|
||||
import { getMetars } from '@/api/metar';
|
||||
import { Metar } from '@/api/metar.types';
|
||||
import SkyConditions from '@/components/Metars/SkyConditions';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export default function Page({ params }: { params: { icao: string } }) {
|
||||
const [airport, setAirport] = useState<Airport | undefined>(undefined);
|
||||
const [metar, setMetar] = useState<Metar | undefined>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
async function loadAirport() {
|
||||
const { data: airport } = await getAirport({ icao: params.icao });
|
||||
setAirport(airport);
|
||||
const { data: airportData } = await getAirport({ icao: params.icao });
|
||||
setAirport(airportData);
|
||||
const { data: metarData } = await getMetars([airportData.icao]);
|
||||
if (metarData.length > 0) {
|
||||
setMetar(metarData[0]);
|
||||
}
|
||||
}
|
||||
loadAirport();
|
||||
}, []);
|
||||
@@ -21,7 +28,7 @@ export default function Page({ params }: { params: { icao: string } }) {
|
||||
<>
|
||||
<div className=''>
|
||||
<h3 className=''>{airport.full_name}</h3>
|
||||
<Link href={'/'}>Back</Link>
|
||||
{metar && <SkyConditions metar={metar} />}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -41,7 +41,7 @@ export default function MapTiles() {
|
||||
async function updateAirports(bounds: LatLngBounds) {
|
||||
const ne = bounds.getNorthEast();
|
||||
const sw = bounds.getSouthWest();
|
||||
const { data: _airports } = await getAirports({
|
||||
const { data: airportData } = await getAirports({
|
||||
bounds: {
|
||||
northEast: { lat: ne.lat, lon: ne.lng },
|
||||
southWest: { lat: sw.lat, lon: sw.lng }
|
||||
@@ -49,15 +49,15 @@ export default function MapTiles() {
|
||||
limit: 100,
|
||||
page: 1
|
||||
});
|
||||
const { data: metars } = await getMetars(_airports);
|
||||
const { data: metars } = await getMetars(airportData.map((a) => a.icao));
|
||||
metars.forEach((metar) => {
|
||||
_airports.forEach((airport) => {
|
||||
airportData.forEach((airport) => {
|
||||
if (metar.station_id == airport.icao) {
|
||||
airport.metar = metar;
|
||||
}
|
||||
});
|
||||
});
|
||||
setAirports(_airports);
|
||||
setAirports(airportData);
|
||||
}
|
||||
|
||||
function metarIcon(airport: Airport) {
|
||||
|
||||
@@ -31,7 +31,7 @@ export default function MetarModal({ airport, isOpen, onClose }: MetarModalProps
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal opened={isOpen} onClose={onClose} withCloseButton={false} size={'55rem'} className='modal'>
|
||||
<Modal opened={isOpen} onClose={onClose} withCloseButton={false} size={'50%'} className='modal'>
|
||||
<span className='title'>
|
||||
<Link href={`/airport/${airport.icao}`}>
|
||||
{airport.icao} {airport.full_name}
|
||||
@@ -45,39 +45,6 @@ export default function MetarModal({ airport, isOpen, onClose }: MetarModalProps
|
||||
<div className='min-w-0 flex-1'>
|
||||
<hr />
|
||||
{airport.metar && <MetarInfo metar={airport.metar} />}
|
||||
{/* <p className='text-sm font-medium text-gray-500'>{airport.metar?.raw_text}</p>
|
||||
<div className='mt-2 flex'>
|
||||
<span
|
||||
className={`flex inline-block align-middle text-sm text-white py-2 px-4 rounded-full
|
||||
${metarBGColor(airport.metar)}
|
||||
`}
|
||||
>
|
||||
{airport.metar?.flight_category ? airport.metar?.flight_category : 'UNKN'}
|
||||
</span>
|
||||
<div className='flex inline-block px-2'>
|
||||
<span className={`text-sm text-black ${windColor(airport.metar)} py-2 px-3 rounded-full`}>
|
||||
{airport.metar && airport.metar.wind_dir_degrees && Number(airport.metar.wind_dir_degrees) > 0 ? (
|
||||
<FaLocationArrow
|
||||
className='align-middle'
|
||||
style={{ rotate: `${-45 + 180 + Number(airport.metar.wind_dir_degrees)}deg` }}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{airport.metar && airport.metar.wind_dir_degrees && airport.metar.wind_dir_degrees == 'VRB' ? (
|
||||
<FaArrowsSpin className='align-middle pr-1.5' />
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<span className='align-middle'>
|
||||
{airport.metar?.wind_speed_kt != undefined && airport.metar?.wind_speed_kt > 0
|
||||
? `${airport.metar?.wind_speed_kt} KT`
|
||||
: `CALM`}
|
||||
</span>
|
||||
</span>
|
||||
{airport.metar?.wx_string?.split(' ').map((wx) => <MetarIcon wx={wx} />)}
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
'use client';
|
||||
|
||||
import { Metar, SkyCondition } from '@/api/metar.types';
|
||||
import { Box } from '@mantine/core';
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
PointElement,
|
||||
LineElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Filler,
|
||||
Legend
|
||||
} from 'chart.js';
|
||||
import { Line } from 'react-chartjs-2';
|
||||
|
||||
ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Filler, Legend);
|
||||
Customized,
|
||||
Label,
|
||||
LabelList,
|
||||
Line,
|
||||
LineChart,
|
||||
ReferenceLine,
|
||||
ResponsiveContainer,
|
||||
XAxis,
|
||||
YAxis
|
||||
} from 'recharts';
|
||||
|
||||
export default function SkyConditions({ metar }: { metar: Metar }) {
|
||||
function skyConditionColor(skyCondition: SkyCondition) {
|
||||
@@ -32,35 +30,54 @@ export default function SkyConditions({ metar }: { metar: Metar }) {
|
||||
return '#e6194b';
|
||||
}
|
||||
}
|
||||
function createDataset(skyCondition: SkyCondition) {
|
||||
return {
|
||||
fill: true,
|
||||
label: skyCondition.sky_cover,
|
||||
data: [skyCondition.cloud_base_ft_agl, skyCondition.cloud_base_ft_agl],
|
||||
backgroundColor: skyConditionColor(skyCondition)
|
||||
};
|
||||
}
|
||||
if (metar.sky_condition && metar.sky_condition.length > 0) {
|
||||
console.log(metar);
|
||||
const options = {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Sky Conditions'
|
||||
}
|
||||
const data: any = [
|
||||
{
|
||||
name: 'start'
|
||||
},
|
||||
{
|
||||
name: 'end'
|
||||
}
|
||||
};
|
||||
const data = {
|
||||
labels: ['', ''],
|
||||
datasets: metar.sky_condition.map((skyCondition) => createDataset(skyCondition))
|
||||
};
|
||||
];
|
||||
metar.sky_condition.forEach((skyCondition, index) => {
|
||||
data[0][index] = skyCondition.cloud_base_ft_agl;
|
||||
data[1][index] = skyCondition.cloud_base_ft_agl;
|
||||
});
|
||||
|
||||
return <Line options={options} data={data} />;
|
||||
return (
|
||||
<LineChart data={data} width={350} height={300}>
|
||||
<YAxis domain={[0, (dataMax: number) => (dataMax < 1000 ? 1000 : Math.ceil(dataMax / 1000) * 1000)]} />
|
||||
{metar.sky_condition.map((skyCondition, index) => (
|
||||
<Line
|
||||
key={`sky-condition-line-${index}`}
|
||||
type={'linear'}
|
||||
dataKey={index}
|
||||
dot={false}
|
||||
isAnimationActive={false}
|
||||
>
|
||||
<LabelList
|
||||
dataKey={index}
|
||||
position='insideRight'
|
||||
content={(props) => renderCustomizedLabel(props, skyCondition.sky_cover)}
|
||||
/>
|
||||
</Line>
|
||||
))}
|
||||
</LineChart>
|
||||
);
|
||||
} else {
|
||||
return <></>;
|
||||
}
|
||||
}
|
||||
|
||||
const renderCustomizedLabel = (props: any, skyCover: string) => {
|
||||
const { x, y, value, index } = props;
|
||||
if (index == 1) {
|
||||
return (
|
||||
<text x={x} y={y - 5} fill={'#285A64'} textAnchor='end'>
|
||||
{skyCover} {value}
|
||||
</text>
|
||||
);
|
||||
} else {
|
||||
return <></>;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user