Simplified Graph component. Date scales based on timeframe selected

This commit is contained in:
2023-05-30 17:24:50 +02:00
parent 8526b0e552
commit c0d1bbef60

View File

@@ -7,9 +7,11 @@
CategoryScale, CategoryScale,
LinearScale, LinearScale,
PointElement, PointElement,
Tooltip,
Title, Title,
Legend Legend
} from 'chart.js'; } from 'chart.js';
import { getRelativePosition } from 'chart.js/helpers';
import type { ChartDataset } from 'chart.js'; import type { ChartDataset } from 'chart.js';
import type IChartFrame from '../interfaces/IChartFrame'; import type IChartFrame from '../interfaces/IChartFrame';
@@ -20,123 +22,112 @@
CategoryScale, CategoryScale,
LinearScale, LinearScale,
PointElement, PointElement,
Tooltip,
Title, Title,
Legend Legend
); );
export let name: string; export let name: string;
export let dataFrames: IChartFrame[]; export let dataFrames: IChartFrame[];
export let beginAtZero: boolean = true; export let hideTitle: boolean;
let chartCanvas: HTMLCanvasElement; let chartCanvas: HTMLCanvasElement;
let chart: Chart; let chart: Chart;
let prevData: any = {};
interface IDataset { onMount(() => renderChart());
labels: string[]; afterUpdate(() => {
data?: ChartDataset<'line', number[]>; chart.destroy();
} renderChart();
});
interface ITemperatureDataset extends IDataset { // Converts Date to format suitable for the current range displayed
inside: ChartDataset<'line', number[]>; function dateLabelsFormatedBasedOnResolution(dataFrames: IChartFrame[]): string[] {
outside?: ChartDataset<'line', number[]>; const firstFrame = dataFrames[0];
} const lastFrame = dataFrames[dataFrames.length - 1];
const deltaSeconds =
(new Date(lastFrame.key).getTime() - new Date(firstFrame.key).getTime()) / 1000;
let dateOptions: Intl.DateTimeFormatOptions = {
year: 'numeric',
month: 'numeric',
day: 'numeric'
};
interface IHumidityDataset extends IDataset {} if (deltaSeconds < 3600) {
interface IPressureDataset extends IDataset {} dateOptions = { hour: 'numeric', minute: 'numeric', second: 'numeric' };
} else if (deltaSeconds <= 86400) {
function pad(num) { dateOptions = { hour: 'numeric', minute: 'numeric' };
if (num < 10) { } else if (deltaSeconds <= 2592000) {
return `0${num}`; dateOptions = {
} day: 'numeric',
return num; month: 'numeric',
} year: '2-digit',
hour: 'numeric',
function prettierDateString(date) { minute: 'numeric'
return `${pad(date.getDate())}.${pad(date.getMonth() + 1)}.${pad(date.getYear() - 100)}`;
}
function computeTemperatureDataset(): ITemperatureDataset {
const labels: string[] = dataFrames.map(
(frame) => prettierDateString(new Date(frame.key)) || String(frame.key_as_string)
);
const data: number[] = dataFrames.map((frame) => frame.value);
return {
labels,
inside: {
label: '℃ inside',
borderColor: '#10e783',
backgroundColor: '#c8f9df',
lineTension: 0.5,
borderWidth: 3,
data
}
}; };
} }
function computeHumidityDataset(): IHumidityDataset { const scaledDate = new Intl.DateTimeFormat('no-NB', dateOptions);
const labels: string[] = dataFrames.map( return dataFrames.map((frame) => scaledDate.format(frame.key));
(frame) => prettierDateString(new Date(frame.key)) || String(frame.key_as_string)
);
const data: number[] = dataFrames.map((frame) => frame.value);
return {
labels,
data: {
label: '% humidity',
borderColor: '#57d2fb',
backgroundColor: '#d4f2fe',
lineTension: 0.5,
borderWidth: 3,
data
}
};
} }
function computePressureDataset(): IPressureDataset { // set dataset label & colors matching the name sent as prop
const labels: string[] = dataFrames.map( function setDataColorAndName(data: ChartDataset) {
(frame) => prettierDateString(new Date(frame.key)) || String(frame.key_as_string) if (name === 'Pressure') {
); Object.assign(data, {
const data: number[] = dataFrames.map((frame) => frame.value);
return {
labels,
data: {
label: 'Bar of pressure', label: 'Bar of pressure',
borderColor: '#ef5878', borderColor: '#ef5878',
backgroundColor: '#fbd7de', backgroundColor: '#fbd7de'
lineTension: 0.5, });
borderWidth: 3, } else if (name === 'Humidity') {
data Object.assign(data, {
label: '% humidity',
borderColor: '#57d2fb',
backgroundColor: '#d4f2fe'
});
} else if (name === 'Temperature') {
Object.assign(data, {
label: '℃ inside',
borderColor: '#10e783',
backgroundColor: '#c8f9df'
});
} }
};
} }
function renderChart() { function renderChart() {
const context: CanvasRenderingContext2D = chartCanvas.getContext('2d'); const context: CanvasRenderingContext2D | null = chartCanvas.getContext('2d');
if (!context) return
let dataset: IDataset | ITemperatureDataset | IHumidityDataset | IPressureDataset; // create labels and singular dataset (data)
if (name === 'Temperature') dataset = computeTemperatureDataset(); const labels: string[] = dateLabelsFormatedBasedOnResolution(dataFrames);
else if (name === 'Humidity') dataset = computeHumidityDataset(); const data: ChartDataset = {
else if (name === 'Pressure') dataset = computePressureDataset(); data: dataFrames.map((frame) => frame.value),
borderWidth: 3,
};
// based on name, add label and color options to dataset
setDataColorAndName(data)
// create chart instance, most here is chart options
chart = new Chart(context, { chart = new Chart(context, {
type: 'line', type: 'line',
data: { data: {
labels: dataset.labels, labels: labels,
datasets: [dataset?.inside || dataset.data] datasets: [data]
}, },
options: { options: {
elements: { elements: {
point: { point: {
radius: 1 radius: 2
},
line: {
tension: 0.5
} }
}, },
maintainAspectRatio: false, maintainAspectRatio: false,
plugins: { plugins: {
title: { title: {
display: true, display: !hideTitle,
position: 'left', position: 'left',
position: 'top',
text: `${name} over time`, text: `${name} over time`,
font: { font: {
size: 20 size: 20
@@ -163,8 +154,21 @@
// }, // },
mode: 'xy' mode: 'xy'
} }
},
tooltip: {
titleFont: {
size: 14
},
bodyFont: {
size: 14
},
enabled: true
} }
}, },
interaction: {
intersect: false,
mode: 'index'
},
scales: { scales: {
y: { y: {
beginAtZero: false, beginAtZero: false,
@@ -187,14 +191,6 @@
chart.update(); chart.update();
} }
onMount(() => renderChart());
afterUpdate(() => {
console.log('after update run');
chart.destroy();
renderChart();
});
</script> </script>
<canvas class="card" id="{name}" bind:this="{chartCanvas}" width="400" height="400"></canvas> <canvas id="{name}" bind:this="{chartCanvas}" width="400" height="400"></canvas>