diff --git a/dashboard/js/charts.js b/dashboard/js/charts.js
new file mode 100644
index 0000000..0b7df74
--- /dev/null
+++ b/dashboard/js/charts.js
@@ -0,0 +1,46 @@
+const Charts = (() => {
+ function makeCurve(pts, stroke, fill, w, h) {
+ if (!pts || pts.length < 2) return '';
+ const xs = pts.map((_, i) => (i / (pts.length - 1)) * w);
+ const ys = pts.map(v => h - (v / 100) * (h - 6) - 3);
+ const wy = h - (70 / 100) * (h - 6) - 3;
+ let d = `M${xs[0]} ${ys[0]}`;
+ for (let i = 1; i < pts.length; i++) {
+ const cx = (xs[i - 1] + xs[i]) / 2;
+ d += ` C${cx} ${ys[i - 1]},${cx} ${ys[i]},${xs[i]} ${ys[i]}`;
+ }
+ const uid = Math.random().toString(36).slice(2);
+ return `
+
+
+
+
+
+
+
+
+ `;
+ }
+
+ function historyToCpuPts(history) {
+ return history.map(h => h.cpu_percent ?? 0);
+ }
+
+ function historyToMemPts(history) {
+ return history.map(h => {
+ if (!h.memory_total || h.memory_total === 0) return 0;
+ return (h.memory_used / h.memory_total) * 100;
+ });
+ }
+
+ function renderChart(svgEl, pts, color) {
+ if (!svgEl) return;
+ const cs = getComputedStyle(document.documentElement);
+ const c = cs.getPropertyValue(color).trim() || color;
+ svgEl.innerHTML = makeCurve(pts, c, c, 200, 52);
+ }
+
+ return { makeCurve, historyToCpuPts, historyToMemPts, renderChart };
+})();