const PI = Math.PI;
function daysIntoYear(date) {
return (Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) - Date.UTC(date.getFullYear(), 0, 0)) / 24 / 60 / 60 / 1000;
}
function secondsToDhms(seconds) {
seconds = Number(seconds);
var d = Math.floor(seconds / (3600 * 24));
var h = Math.floor(seconds % (3600 * 24) / 3600);
var m = Math.floor(seconds % 3600 / 60);
var s = Math.floor(seconds % 60);
var dDisplay = d > 0 ? d + (d == 1 ? " day, " : " days, ") : "";
var hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : "";
var mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : "";
var sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : "";
return dDisplay + hDisplay + mDisplay + sDisplay;
}
function dataSimulation(from, to, grouping) {
const timeDiff = (new Date(to) - new Date(from)) / 1000;
console.log("fromDate=" + from + " toDate=" + to + " diff=" + secondsToDhms(timeDiff) + " group=" + secondsToDhms(grouping));
datamapped = [];
dataEvery = 60 * 20; // Data get every 20mn
min = 999;
max = -999;
i = 0;
sum = 0;
for (x = new Date(from).getTime(); x <= new Date(to).getTime(); x = x + 1000 * dataEvery) {
date = new Date(x);
H = date.getHours();
M = date.getMinutes();
month = date.getMonth();
day = date.getDate();
nday = daysIntoYear(date);
value = day + (H / 100) + (M / 10000); // simple simulation
value = 20 + (10 * Math.sin(nday * (PI / 180))) + 3 * Math.sin(H * (360 / 24) * (PI / 180)); // more complex
sum = sum + value;
if (value > max)
max = value;
if (value < min)
min = value;
if ((i * dataEvery) > grouping) {
datamapped.push({
x: new Date(x).toISOString(),
min: min,
max: max,
avg: sum / i
});
i = 0;
sum = 0;
min = 999;
max = -999;
}
i = i + 1;
}
return datamapped;
}
async function fetchData(from, to, group) {
/**
const response = await fetch(`data.php?from=${from}&to=${to}&sensor=OWM&grouptime=86400`);
const data = await response.json();
datamapped = data.map(item => ({
x: item[0],
min: item[1],
max: item[2],
avg: item[3]
}));
**/
datamapped = dataSimulation(from, to, group);
return datamapped;
}
var LASTUPDATETIME;
LASTUPDATETIME = new Date();
var LOCK;
LOCK = false;
async function updateData(chart) {
difftime = (new Date().getTime() - LASTUPDATETIME.getTime());
console.log("LOCK=" + LOCK + " difftime=" + difftime);
if (LOCK == true) {
if (difftime < 1000)
return;
}
LOCK = true;
//if ( difftime < 500)
//{ // debounce
// console.log("too soon");
// return;
//}
const xmin = chart.scales.x.min;
const xmax = chart.scales.x.max;
const fromDate = new Date(xmin).toISOString();
const toDate = new Date(xmax).toISOString();
const timeDiff = (xmax - xmin) / 1000;
group = 31 * 24 * 3600;
if (timeDiff < 1 * 24 * 3600) { // <1 days, display per every minute
group = 60;
} else if (timeDiff < 4 * 24 * 3600) { // <4 days, display per every hours
group = 3600;
} else if (timeDiff < 33 * 24 * 3600) { // <1.1month, display per 4xday
group = 4 * 3600;
} else if (timeDiff < 4 * 31 * 24 * 3600) { // <4month, display per day
group = 24 * 3600;
}
/**
response = await fetch(`data.php?fmt=json&from=${fromDate}&to=${toDate}&sensor=OWM&grouptime=${group}`);
data = await response.json();
datamapped = data.map(item => ({
x: item[0],
min: item[1],
max: item[2],
avg: item[3]
}));
**/
datamapped = dataSimulation(fromDate, toDate, group);
chart.data.datasets[0].data = datamapped;
chart.data.datasets[1].data = datamapped;
chart.data.datasets[2].data = datamapped;
chart.scales.y.min = -100; // as a test, the Y axis should be at -100, but not working
chart.update('none');
LASTUPDATETIME = new Date();
LOCK = false;
}
async function createChart(from, to, group) {
const data = await fetchData(from, to, group);
const ctx = document.getElementById('temperatureChart').getContext('2d');
const temperatureChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
data: data, // The three values are on the same data ? strange
parsing: {
yAxisKey: 'min'
},
fill: '+1',
borderWidth: 0
},
{
data: data, // this is strange to have the same data than the previous
parsing: {
yAxisKey: 'max'
},
borderWidth: 0
},
{
data: data,
parsing: {
yAxisKey: 'avg'
},
borderColor: 'green',
fill: false,
borderWidth: 1
}
]
},
options: {
responsive: true,
animation: false,
elements: {
point: {
radius: 1
}
},
scales: {
x: {
type: 'time',
time: {
tooltipFormat: 'yyyy-MM-dd HH:mm'
},
title: {
display: true,
text: 'Date/Time'
},
},
y: {
beginAtZero: false,
title: {
display: true,
text: 'Temperature (°C)'
},
}
},
plugins: {
legend: {
display: true,
position: 'top'
},
zoom: {
pan: {
// pan options and/or events
enabled: true,
onPanComplete: function({
chart
}) {
updateData(chart);
}
},
zoom: {
wheel: {
enabled: true,
},
pinch: {
enabled: true
},
mode: 'x',
onZoomComplete: function({
chart
}) {
updateData(chart);
}
}
}
}
}
});
}
// Example usage
createChart('2024-01-01', '2024-12-31', 31 * 24 * 3600);
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Temperature Line Chart</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-zoom"></script>
</head>
<div style="width: 100%; margin: auto;">
<canvas id="temperatureChart"></canvas>
</div>