Chart.register(ChartDataLabels); const charts = {}; function buildStackedChart(canvasId, labels, datasets) { const ctx = document.getElementById(canvasId); if (!ctx) return; if (charts[canvasId]) { charts[canvasId].destroy(); } charts[canvasId] = new Chart(ctx, { type: "bar", data: { labels: labels, datasets: datasets, datalabels: { display: true } }, plugins: [ChartDataLabels], options: { responsive: true, maintainAspectRatio: false, layout: { padding: { top: 20, bottom: 30 } }, plugins: { legend: { position: 'bottom', align: 'center', labels: { padding: 20, boxWidth: 10, boxHeight: 10, usePointStyle: true, pointStyle: 'circle' } }, datalabels: { color: "#000", anchor: "end", align: "top", clamp: true, clip: false, font: { weight: "bold", size: 10 }, formatter: function (value) { return value > 0 ? value : null; } } }, scales: { x: { stacked: true }, y: { stacked: true, beginAtZero: true } } } }); } function buildChart(id, type, labels, data) { const ctx = document.getElementById(id); if (!ctx) return; if (charts[id]) charts[id].destroy(); charts[id] = new Chart(ctx, { type: type, data: { labels: labels, datasets: [{ data: data, borderWidth: 2, tension: 0.3, barPercentage: 0.8, categoryPercentage: 0.6, maxBarThickness: 50 }] }, options: { responsive: true, maintainAspectRatio: false, layout: { padding: { top: 30, bottom: 30 } }, plugins: { legend: { position: 'bottom', align: 'center', display: type === 'pie' || type === 'doughnut', labels: { padding: 10, boxWidth: 14, boxHeight: 14, usePointStyle: true, pointStyle: 'circle' } }, datalabels: { color: "#282626", anchor: type === "bar" ? "end" : "center", align: type === "bar" ? "top" : "center", font: { size: 10 }, formatter: function(value, ctx) { const data = ctx.chart.data.datasets[0].data; const total = data.reduce((a, b) => a + b, 0); const percent = total ? (value / total * 100).toFixed(1) : 0; return percent + '%'; } } } } }); } function buildMixedTrendChart(canvasId, labels, samples, fluRate, covidRate) { const ctx = document.getElementById(canvasId); if (!ctx) return; if (charts[canvasId]) charts[canvasId].destroy(); charts[canvasId] = new Chart(ctx, { data: { labels: labels, datasets: [ { type: 'line', label: 'Influenza %', data: fluRate, borderColor: '#fa2929', backgroundColor: '#fa2929', tension: 0.4, yAxisID: 'y1', pointStyle: 'line', }, { type: 'line', label: 'COVID-19 %', data: covidRate, borderColor: '#1976D2', backgroundColor: '#1976D2', tension: 0.4, yAxisID: 'y1', pointStyle: 'line', }, { type: 'bar', label: 'Total Cases', data: samples, backgroundColor: '#0B8F3C', borderRadius: 2, barPercentage: 0.8, categoryPercentage: 0.7, yAxisID: 'y', } ] }, plugins: [ChartDataLabels], options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom', labels: { usePointStyle: true, padding: 20 } }, datalabels: { align: "top", anchor: "end", color: "#555", font: { size: 10 }, formatter: function (value, context) { if (Number(value) === 0) return null; if (context.dataset.type === 'line') { return value + '%'; } return value; } } }, layout: { padding: { top: 30, bottom: 20 } }, scales: { y: { position: 'left', title: { display: true, text: 'Cases' } }, y1: { position: 'right', grid: { drawOnChartArea: false }, title: { display: true, text: '% Positivity' }, } } } }); } // function buildMixedTrendChart(canvasId, labels, samples, positivity) { // const ctx = document.getElementById(canvasId); // if (!ctx) return; // if (charts[canvasId]) charts[canvasId].destroy(); // charts[canvasId] = new Chart(ctx, { // data: { // labels: labels, // datasets: [ // { // type: 'line', // label: '% Positive', // data: positivity, // borderColor: '#1e6ef2', // borderWidth: 2, // tension: 0.4, // fill: false, // pointRadius: 2, // pointStyle: 'line', // yAxisID: 'y1', // }, // { // type: 'bar', // label: 'Total sample ', // data: samples, // backgroundColor: '#2ecc71', // borderRadius: 2, // barPercentage: 0.8, // categoryPercentage: 0.7, // yAxisID: 'y', // } // ] // }, // plugins: [ChartDataLabels], // options: { // responsive: true, // maintainAspectRatio: false, // plugins: { // legend: { // position: 'bottom', // align: 'center', // labels: { // usePointStyle: true, // padding: 20, // boxWidth: 30, // font: { size: 12 } // } // }, // datalabels: { // align: "top", // anchor: "end", // color: "#555", // font: { // size: 10 // }, // formatter: function (value, context) { // if (Number(value) === 0) return null; // if (context.dataset.type === 'line') { // console.log(value); // return value + '%'; // } // return value; // } // } // }, // layout: { // padding: { // top: 20, // bottom: 50 // } // }, // scales: { // y: { // position: 'left', // title: { // display: true, // text: 'Total sample' // } // }, // y1: { // position: 'right', // grid: { // drawOnChartArea: false // }, // title: { // display: true, // text: '% Positive' // }, // ticks: { // callback: value => value + '%' // } // } // } // } // }); // }