1
0
Files
pi-weather-station/client/src/components/weatherCharts/DailyChart/index.js
T

231 lines
5.3 KiB
JavaScript

import React, { useContext, useState, useEffect, useCallback } from "react";
import { AppContext } from "~/AppContext";
import styles from "../styles.css";
import { Line } from "react-chartjs-2";
import { format } from "date-fns";
import {
convertTemp,
convertLength,
convertSpeed,
} from "~/services/conversions";
import { fontColor } from "../common";
const createChartOptions = ({
darkMode,
tempUnit,
speedUnit,
lengthUnit,
altMode,
}) => {
return {
maintainAspectRatio: false,
legend: {
display: false,
},
responsive: true,
hoverMode: "index",
stacked: false,
title: {
display: true,
text: `5 Day ${
altMode
? `Wind Speed / Precipitation (${lengthUnit})`
: `Temp / Precipitation`
}`,
fontColor: fontColor(darkMode),
fontFamily: "Rubik, sans-serif",
},
scales: {
xAxes: [
{
ticks: {
fontColor: fontColor(darkMode),
fontFamily: "Rubik, sans-serif",
},
},
],
yAxes: [
{
type: "linear",
display: true,
position: "left",
id: "y-axis-1",
ticks: {
fontColor: fontColor(darkMode),
fontFamily: "Rubik, sans-serif",
maxTicksLimit: 5,
callback: (val) => {
return altMode
? `${val} ${speedUnit === "mph" ? "mph" : "m/s"}`
: `${val} ${tempUnit.toUpperCase()}`;
},
},
},
{
type: "linear",
display: true,
position: "right",
id: "y-axis-2",
ticks: {
fontColor: fontColor(darkMode),
fontFamily: "Rubik, sans-serif",
maxTicksLimit: 5,
suggestedMin: 0,
callback: (val) => {
return `${val}${altMode ? ` ${lengthUnit}` : "%"}`;
},
},
gridLines: {
drawOnChartArea: false,
},
},
],
},
};
};
const chartColors = {
blue: "rgba(63, 127, 191, 0.5)",
gray: "rgba(127, 127, 127, 0.5)",
};
const mapChartData = ({
data: weatherData,
tempUnit,
speedUnit,
altMode,
lengthUnit,
}) => {
const data = weatherData?.data?.timelines?.[0]?.intervals;
if (!data) {
return null;
}
return {
labels: data.map((e) => {
const date = new Date(e.startTime);
const adjustedTimestamp =
date.getTime() + date.getTimezoneOffset() * 60 * 1000;
return format(new Date(adjustedTimestamp), "EEEEE");
}),
datasets: [
{
radius: 0,
label: altMode ? "Wind Speed" : "Temp",
data: data.map((e) => {
const {
values: { windSpeed, temperature },
} = e;
return altMode
? convertSpeed(windSpeed, speedUnit)
: convertTemp(temperature, tempUnit);
}),
yAxisID: "y-axis-1",
borderColor: chartColors.gray,
backgroundColor: chartColors.gray,
fill: false,
},
{
radius: 0,
label: "Precipitation",
data: data.map((e) => {
const {
values: { precipitationIntensity, precipitationProbability },
} = e;
return altMode
? convertLength(precipitationIntensity, lengthUnit)
: precipitationProbability;
}),
yAxisID: "y-axis-2",
borderColor: chartColors.blue,
backgroundColor: chartColors.blue,
fill: false,
},
],
};
};
/**
* Daily forecast chart
*
* @returns {JSX.Element} Hourly forecast chart
*/
const DailyChart = () => {
const {
dailyWeatherData,
dailyWeatherDataErr,
dailyWeatherDataErrMsg,
tempUnit,
darkMode,
lengthUnit,
speedUnit,
} = useContext(AppContext);
const [altMode, setAltMode] = useState(false);
const [chartData, setChartData] = useState(null);
const [chartOptions, setChartOptions] = useState(null);
const setChartDataCallback = useCallback((e) => setChartData(e), []);
const setChartOptionsCallback = useCallback((e) => setChartOptions(e), []);
useEffect(() => {
if (dailyWeatherData) {
setChartDataCallback(
mapChartData({
data: dailyWeatherData,
tempUnit,
lengthUnit,
speedUnit,
altMode,
})
);
setChartOptionsCallback(
createChartOptions({
tempUnit,
darkMode,
lengthUnit,
speedUnit,
altMode,
})
);
}
}, [
dailyWeatherData,
tempUnit,
lengthUnit,
altMode,
speedUnit,
darkMode,
setChartOptionsCallback,
setChartDataCallback,
]);
if (chartData && chartOptions) {
return (
<div
className={styles.container}
onClick={() => {
setAltMode(!altMode);
}}
>
<Line options={chartOptions} data={chartData} />
</div>
);
} else if (dailyWeatherDataErr) {
return (
<div
className={`${darkMode ? styles.dark : styles.light} ${
styles.errContainer
}`}
>
<div>Cannot get 5 day weather forecast</div>
<div className={styles.message}>{dailyWeatherDataErrMsg}</div>
</div>
);
} else {
return null;
}
};
export default DailyChart;