Skip to content

Instantly share code, notes, and snippets.

@mtvbrianking
Last active January 12, 2024 07:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mtvbrianking/943fe580e5432f41f6ca154a5d92182a to your computer and use it in GitHub Desktop.
Save mtvbrianking/943fe580e5432f41f6ca154a5d92182a to your computer and use it in GitHub Desktop.
chart.js timeseries demo
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>chart.js timeseries demo</title>
</head>
<body style="padding: 25px; margin: 25px;">
<div style="width: 85%">
<button id="reset-zoom">Reset Zoom</button>
<button id="fetch-today">Today</button>
<button id="fetch-yesterday">Yesterday</button>
<!-- <button id="fetch-week">This week</button> -->
<!-- <button id="fetch-month">This Month</button> -->
<!-- <button id="fetch-quarter">This Quarter</button> -->
<!-- <button id="fetch-year">This Year</button> -->
<canvas id="my-chart" />
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.2.1/dist/chart.umd.min.js"></script>
<!-- <script src="https://cdn.jsdelivr.net/npm/date-fns@2.30.0/index.min.js"></script> -->
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@3.0.0/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/hammerjs@2.0.8/hammer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-zoom@2.0.1/dist/chartjs-plugin-zoom.min.js"></script>
<script type="module">
import { format, subDays, getTime, startOfDay, endOfDay } from "https://cdn.jsdelivr.net/npm/date-fns@2.30.0/+esm";
function seedData(start, end) {
console.log('seeding', { start: start, end: end });
const data = [];
let y = 100;
for (let x = start; x <= end; x += 1000) {
y += 5 - Math.random() * 10;
data.push({ x, y });
}
return data;
}
function fetchData(x1, x2) {
const step = Math.max(1, Math.round((x2 - x1) / 100000));
const data = [];
let i = 0;
while (i < seed.length && seed[i].x < x1) {
i++;
}
while (i < seed.length && seed[i].x <= x2) {
data.push(seed[i]);
i += step;
}
// let dur = Math.floor(x2 - x1);
// console.log(`Fetched: ${data.length} from ${Math.floor(x1)} to ${Math.floor(x2)} for ${dur.toLocaleString("en-US")}`);
return data;
}
// console.log("fetchData(start, end).length", fetchData(start, end).length);
function startFetch({chart}) {
const {min, max} = chart.scales.x;
// console.log('zoom', chart.getZoomLevel());
console.log('Fetch data btn ' + Math.floor(min) + ' and ' + Math.floor(max));
clearTimeout(timer);
timer = setTimeout(() => {
let fetched = fetchData(min, max);
chart.data.datasets[0].data = fetched;
chart.stop(); // make sure animations are not running
chart.update('none');
}, 500);
}
// ---------
let timer;
let end = getTime(new Date()); // now
let start = getTime(subDays(end, 1)); // 2 days ago
let then = getTime(subDays(end, 7)); // a week ago
let seed = seedData(then, end);
// -------------------------------------
const data = {
datasets: [
{
label: "# of orders",
// backgroundColor: '#eeeeee',
// borderColor: '#ff0000',
// fill: false,
data: fetchData(start, end)
}
]
};
const scales = {
x: {
// type: "time",
type: "timeseries",
parsing: false,
// min: start,
// max: end,
min: (args) => {
const {chart, scale} = args;
return chart.data.datasets[0].data[0].x;
},
max: (args) => {
const {chart, scale} = args;
let size = chart.data.datasets[0].data.length;
return chart.data.datasets[0].data[size - 1].x;
},
ticks: {
autoSkip: true,
autoSkipPadding: 50,
maxRotation: 0
},
time: {
displayFormats: {
second: "HH:mm:ss",
minute: "HH:mm",
hour: "MMM-dd HH:mm",
day: "MMM-dd",
month: "yyyy-MM",
year: "yyyy",
}
},
title: {
display: true,
text: "Period"
}
},
y: {
type: "linear",
title: {
display: true,
text: "No of Orders"
}
}
};
const config = {
type: "line",
data: data,
options: {
plugins: {
title: {
text: "Chart.js timescale demo",
display: true
},
zoom: {
pan: {
enabled: true,
modifierKey: "ctrl",
onPanComplete: startFetch,
},
zoom: {
drag: {
enabled: true
},
mode: "x",
onZoomComplete: startFetch,
}
}
},
scales: scales
}
};
// Chart.register(zoomPlugin); esm
const ctx = document.getElementById("my-chart");
const chart = new Chart(ctx, config);
window.chart = chart;
document.getElementById("reset-zoom").addEventListener("click", function () {
chart.resetZoom();
console.log("zoom level: ", chart.getZoomLevel());
});
document.getElementById("fetch-today").addEventListener("click", function () {
let now = new Date();
let from = getTime(startOfDay(now));
let to = getTime(endOfDay(now));
clearTimeout(timer);
timer = setTimeout(() => {
let fetched = fetchData(from, to);
chart.data.datasets[0].data = fetched;
chart.stop();
chart.update('none');
}, 500);
});
document.getElementById("fetch-yesterday").addEventListener("click", function () {
let yesterday = subDays(new Date(), 1);
let from = getTime(startOfDay(yesterday));
let to = getTime(endOfDay(yesterday));
clearTimeout(timer);
timer = setTimeout(() => {
let fetched = fetchData(from, to);
chart.data.datasets[0].data = fetched;
chart.stop();
chart.update('none');
}, 500);
});
</script>
</body>
</html>
@mtvbrianking
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment