fix bugs
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
import { COLORS, SUBTYPE_COLORS, SURVEILLANCE_COLORS } from "./globals.js";
|
||||
|
||||
import * as Charts from "./dashboard/globals.js";
|
||||
let trendChart;
|
||||
let influenzaSubtypeChart;
|
||||
let covidDistributedByAgeChart;
|
||||
let covidLineageFrequencyChart;
|
||||
let influenzaSubtypeFrequencyChart;
|
||||
@@ -31,38 +29,46 @@ function loadSummary() {
|
||||
if (item.percent_change > 0) trendColor = 'text-danger';
|
||||
if (item.percent_change < 0) trendColor = 'text-success';
|
||||
|
||||
|
||||
|
||||
html += `
|
||||
<div class="col-md-2 mb-3">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="col-md-2 mb-3">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
|
||||
<div class="d-flex justify-content-between">
|
||||
|
||||
<div class="d-flex justify-content-between">
|
||||
|
||||
<div>
|
||||
<h6 class="fw-bold">${item.code} Cases</h6>
|
||||
<h3 class="mb-1">${item.current_total}</h3>
|
||||
<small class="text-muted">Last 7 days</small>
|
||||
</div>
|
||||
|
||||
<div class="text-end">
|
||||
|
||||
<div class="${trendColor} fw-bold">
|
||||
${item.percent_change > 0 ? '▲' : item.percent_change < 0 ? '▼' : '–'}
|
||||
${Math.abs(item.percent_change)}%
|
||||
<div>
|
||||
<h6 class="fw-bold">
|
||||
${item.code === 'H5N1'
|
||||
? 'A/H5N1 Cases'
|
||||
: `${item.code} Cases`}
|
||||
</h6>
|
||||
<h3 class="mb-1">${item.current_total}</h3>
|
||||
<small class="text-muted">Last 7 days</small>
|
||||
</div>
|
||||
|
||||
<small class="text-muted">
|
||||
${item.previous_total ?? 0} last week
|
||||
</small>
|
||||
<div class="text-end">
|
||||
|
||||
<div class="${trendColor} fw-bold">
|
||||
${item.percent_change > 0 ? '▲' : item.percent_change < 0 ? '▼' : '–'}
|
||||
${Math.abs(item.percent_change)}%
|
||||
</div>
|
||||
|
||||
<small class="text-muted">
|
||||
${item.previous_total ?? 0} last week
|
||||
</small>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
`;
|
||||
|
||||
|
||||
window._summaryData = data;
|
||||
updateAlerts();
|
||||
@@ -89,58 +95,15 @@ function loadTrend(periodType, startYear, startWeek, endYear, endWeek) {
|
||||
.then(data => {
|
||||
|
||||
if (trendChart) trendChart.destroy();
|
||||
const totalYears = endYear - startYear;
|
||||
const useYearlyView = totalYears >= 5;
|
||||
|
||||
// const labelsSet = new Set();
|
||||
|
||||
// Object.values(data).forEach(program => {
|
||||
// program.forEach(row => {
|
||||
// labelsSet.add(`${row.year}-${row.period}`);
|
||||
// });
|
||||
// });
|
||||
|
||||
// const labels = Array.from(labelsSet).sort((a, b) => {
|
||||
|
||||
// const [yearA, weekA] = a.split('-').map(Number);
|
||||
// const [yearB, weekB] = b.split('-').map(Number);
|
||||
|
||||
// if (yearA !== yearB) return yearA - yearB;
|
||||
// return weekA - weekB;
|
||||
|
||||
// });
|
||||
let labels = [];
|
||||
|
||||
if (useYearlyView) {
|
||||
|
||||
labels = [...new Set(
|
||||
Object.values(data)
|
||||
.flat()
|
||||
.map(row => row.year)
|
||||
)].sort((a, b) => a - b);
|
||||
|
||||
} else {
|
||||
|
||||
const labelsSet = new Set();
|
||||
|
||||
Object.values(data).forEach(program => {
|
||||
program.forEach(row => {
|
||||
labelsSet.add(`${row.year}-${row.period}`);
|
||||
});
|
||||
});
|
||||
|
||||
labels = Array.from(labelsSet).sort((a, b) => {
|
||||
|
||||
const [yearA, weekA] = a.split('-').map(Number);
|
||||
const [yearB, weekB] = b.split('-').map(Number);
|
||||
|
||||
if (yearA !== yearB) return yearA - yearB;
|
||||
|
||||
return weekA - weekB;
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
const {
|
||||
yearlyView: useYearlyView,
|
||||
labels
|
||||
} = Charts.buildPeriodLabels(
|
||||
Object.values(data),
|
||||
startYear,
|
||||
endYear
|
||||
);
|
||||
|
||||
|
||||
const datasets = [];
|
||||
@@ -151,17 +114,14 @@ function loadTrend(periodType, startYear, startWeek, endYear, endWeek) {
|
||||
|
||||
if (!allowedPrograms.includes(code)) return;
|
||||
|
||||
// const values = labels.map(label => {
|
||||
// const found = data[code].find(row => `${row.year}-${row.period}` === label);
|
||||
// return found ? found.total : 0;
|
||||
// });
|
||||
|
||||
const values = labels.map(label => {
|
||||
|
||||
if (useYearlyView) {
|
||||
|
||||
return data[code]
|
||||
.filter(row => row.year == label)
|
||||
.reduce((sum, row) => sum + row.total, 0);
|
||||
.filter(row => String(row.year) === String(label))
|
||||
.reduce((sum, row) => sum + Number(row.total || 0), 0);
|
||||
|
||||
}
|
||||
|
||||
@@ -176,8 +136,8 @@ function loadTrend(periodType, startYear, startWeek, endYear, endWeek) {
|
||||
datasets.push({
|
||||
label: code,
|
||||
data: values,
|
||||
borderColor: SURVEILLANCE_COLORS[code],
|
||||
backgroundColor: SURVEILLANCE_COLORS[code],
|
||||
borderColor: Charts.SURVEILLANCE_COLORS[code],
|
||||
backgroundColor: Charts.SURVEILLANCE_COLORS[code],
|
||||
borderWidth: 3,
|
||||
pointRadius: 4,
|
||||
maxBarThickness: 50,
|
||||
@@ -201,6 +161,7 @@ function loadTrend(periodType, startYear, startWeek, endYear, endWeek) {
|
||||
return `${year}-W${String(week).padStart(2, '0')}`;
|
||||
});
|
||||
|
||||
|
||||
trendChart = new Chart(document.getElementById('trendChart'), {
|
||||
|
||||
type: 'line',
|
||||
@@ -244,7 +205,7 @@ function loadTrend(periodType, startYear, startWeek, endYear, endWeek) {
|
||||
}
|
||||
}
|
||||
});
|
||||
charts['trendChart'] = trendChart;
|
||||
Charts.charts['trendChart'] = trendChart;
|
||||
|
||||
});
|
||||
}
|
||||
@@ -254,88 +215,19 @@ function loadInfluenzaSubtypeDistribution(periodType, startYear, startWeek, endY
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
|
||||
let displayLabels = data.map(item => item.subtype);
|
||||
let dataset = data.map(item => item.total);
|
||||
const displayData = data.map(item => ({
|
||||
...item,
|
||||
subtype: item.subtype === "B/VIC" ? "B/Vic" : item.subtype
|
||||
}));
|
||||
|
||||
// const colors = displayLabels.map(
|
||||
// label => SUBTYPE_COLORS[label] || '#9ca3af'
|
||||
// );
|
||||
|
||||
if (influenzaSubtypeChart) influenzaSubtypeChart.destroy();
|
||||
influenzaSubtypeChart = new Chart(document.getElementById('influenzaSubtypeDistribution'), {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: displayLabels,
|
||||
datasets: [{
|
||||
data: dataset,
|
||||
backgroundColor: displayLabels.map(
|
||||
label => SUBTYPE_COLORS[label] || '#9ca3af'
|
||||
),
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
layout: {
|
||||
padding: {
|
||||
top: 20,
|
||||
right: 30,
|
||||
bottom: 20
|
||||
}
|
||||
},
|
||||
|
||||
indexAxis: 'y',
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
position: 'right'
|
||||
},
|
||||
datalabels: {
|
||||
color: '#000000',
|
||||
borderRadius: 6,
|
||||
z: 1000,
|
||||
padding: {
|
||||
top: 6,
|
||||
bottom: 6,
|
||||
},
|
||||
|
||||
font: {
|
||||
weight: 'bold',
|
||||
size: 12
|
||||
},
|
||||
formatter: (value) => value,
|
||||
anchor: 'end',
|
||||
align: 'end',
|
||||
offset: 4,
|
||||
clamp: true,
|
||||
clip: false
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
stacked: true,
|
||||
beginAtZero: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Number of Positive Influenza Subtypes'
|
||||
}
|
||||
},
|
||||
y: {
|
||||
stacked: true,
|
||||
beginAtZero: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Influenza Subtypes'
|
||||
},
|
||||
grid: {
|
||||
display: false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [ChartDataLabels]
|
||||
});
|
||||
charts['influenzaSubtypeDistribution'] = influenzaSubtypeChart;
|
||||
Charts.buildDistributionChart(
|
||||
'influenzaSubtypeDistribution',
|
||||
'bar',
|
||||
displayData,
|
||||
'subtype',
|
||||
'total',
|
||||
label => Charts.SUBTYPE_COLORS[label] || '#9ca3af'
|
||||
);
|
||||
|
||||
});
|
||||
}
|
||||
@@ -344,83 +236,7 @@ function loadCovidDistributedByAgeGroup(periodType, startYear, startWeek, endYea
|
||||
fetch(`/api/dashboard/covid-distributed-by-age-group?period_type=${periodType}&start_year=${startYear}&start_week=${startWeek}&end_year=${endYear}&end_week=${endWeek}`)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
|
||||
let displayLabels = data.map(item => item.age_group);
|
||||
let dataset = data.map(item => item.total);
|
||||
|
||||
|
||||
if (covidDistributedByAgeChart) covidDistributedByAgeChart.destroy();
|
||||
covidDistributedByAgeChart = new Chart(document.getElementById('covidDistributedByAgeGroup'), {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: displayLabels,
|
||||
datasets: [{
|
||||
label: 'Total Covid-19 Detected',
|
||||
data: dataset,
|
||||
backgroundColor: COLORS,
|
||||
maxBarThickness: 50
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
layout: {
|
||||
padding: {
|
||||
top: 50,
|
||||
bottom: 10,
|
||||
}
|
||||
},
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
position: 'bottom'
|
||||
},
|
||||
datalabels: {
|
||||
color: '#000',
|
||||
borderRadius: 6,
|
||||
z: 1000,
|
||||
padding: {
|
||||
top: 6,
|
||||
bottom: 6,
|
||||
left: 10,
|
||||
right: 10
|
||||
},
|
||||
font: {
|
||||
weight: 'bold',
|
||||
size: 12
|
||||
},
|
||||
formatter: (value) => value,
|
||||
anchor: 'end',
|
||||
align: 'end',
|
||||
offset: 4,
|
||||
clamp: true,
|
||||
clip: false
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
stacked: true,
|
||||
beginAtZero: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Patient Age Group'
|
||||
},
|
||||
grid: {
|
||||
display: false
|
||||
}
|
||||
},
|
||||
y: {
|
||||
stacked: true,
|
||||
beginAtZero: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Number of Positive SARS-CoV-2'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
charts['covidDistributedByAgeGroup'] = covidDistributedByAgeChart;
|
||||
Charts.buildDistributionChart('covidDistributedByAgeGroup', 'bar', data, 'age_group');
|
||||
|
||||
});
|
||||
}
|
||||
@@ -430,36 +246,23 @@ function loadCovidLineageFrequency(periodType, startYear, startWeek, endYear, en
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
|
||||
// const weeks = [...new Set(data.map(item => item.week))].sort();
|
||||
const totalYears = endYear - startYear;
|
||||
const useYearlyView = totalYears >= 5;
|
||||
const {
|
||||
yearlyView: useYearlyView,
|
||||
periods
|
||||
} = Charts.buildPeriods(
|
||||
data,
|
||||
'week',
|
||||
startYear,
|
||||
endYear
|
||||
);
|
||||
|
||||
let periods;
|
||||
|
||||
if (useYearlyView) {
|
||||
|
||||
periods = [...new Set(
|
||||
data.map(item => item.week.split('-')[0])
|
||||
)].sort((a, b) => a - b);
|
||||
|
||||
} else {
|
||||
|
||||
periods = [...new Set(
|
||||
data.map(item => item.week)
|
||||
)].sort();
|
||||
|
||||
}
|
||||
const lineages = [...new Set(data.map(item => item.lineage))];
|
||||
|
||||
|
||||
|
||||
const datasets = lineages.map((lineage, index) => {
|
||||
// const lineageData = weeks.map(week => {
|
||||
// const found = data.find(
|
||||
// item => item.week === week && item.lineage === lineage
|
||||
// );
|
||||
// return found ? found.total : 0;
|
||||
// });
|
||||
|
||||
const lineageData = periods.map(period => {
|
||||
|
||||
@@ -492,7 +295,7 @@ function loadCovidLineageFrequency(periodType, startYear, startWeek, endYear, en
|
||||
// borderColor: 'transparent',
|
||||
borderWidth: 0,
|
||||
pointRadius: 0,
|
||||
backgroundColor: hexToRGBA(colors[index % colors.length], 0.3),
|
||||
backgroundColor: hexToRGBA(Charts.COLORS[index % Charts.COLORS.length], 0.3),
|
||||
stack: 'total'
|
||||
};
|
||||
});
|
||||
@@ -545,11 +348,8 @@ function loadCovidLineageFrequency(periodType, startYear, startWeek, endYear, en
|
||||
}
|
||||
}
|
||||
});
|
||||
charts['covidLineageFrequency'] = covidLineageFrequencyChart;
|
||||
Charts.charts['covidLineageFrequency'] = covidLineageFrequencyChart;
|
||||
|
||||
// -------------------------
|
||||
// Custom right-side scrollable legend
|
||||
// -------------------------
|
||||
const legendContainer = document.getElementById('legendContainer');
|
||||
legendContainer.innerHTML = '';
|
||||
datasets.forEach((dataset, index) => {
|
||||
@@ -602,31 +402,22 @@ function loadInfluenzaSubtypeFrequency(periodType, startYear, startWeek, endYear
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
|
||||
const totalYears = endYear - startYear;
|
||||
const useYearlyView = totalYears >= 5;
|
||||
|
||||
let periods;
|
||||
|
||||
if (useYearlyView) {
|
||||
|
||||
periods = [...new Set(
|
||||
data.map(item => item.week.split('-')[0])
|
||||
)].sort((a, b) => a - b);
|
||||
|
||||
} else {
|
||||
|
||||
periods = [...new Set(
|
||||
data.map(item => item.week)
|
||||
)].sort();
|
||||
|
||||
}
|
||||
|
||||
const {
|
||||
yearlyView: useYearlyView,
|
||||
periods
|
||||
} = Charts.buildPeriods(
|
||||
data,
|
||||
'week',
|
||||
startYear,
|
||||
endYear
|
||||
);
|
||||
|
||||
const lineages = [...new Set(
|
||||
data.map(item => item.lineage)
|
||||
data.map(item => item.lineage === 'B/VIC' ? 'B/Vic' : item.lineage)
|
||||
)];
|
||||
|
||||
const lineageColors = lineages.map(
|
||||
label => SUBTYPE_COLORS[label] || '#9ca3af'
|
||||
label => Charts.SUBTYPE_COLORS[label] || '#9ca3af'
|
||||
);
|
||||
|
||||
const datasets = lineages.map((lineage, index) => {
|
||||
@@ -747,7 +538,7 @@ function loadInfluenzaSubtypeFrequency(periodType, startYear, startWeek, endYear
|
||||
|
||||
});
|
||||
|
||||
charts['influenzaSubtypeFrequency'] =
|
||||
Charts.charts['influenzaSubtypeFrequency'] =
|
||||
influenzaSubtypeFrequencyChart;
|
||||
|
||||
/*
|
||||
@@ -857,9 +648,9 @@ function hexToRGBA(hex, alpha) {
|
||||
}
|
||||
function updateAlerts() {
|
||||
|
||||
if (!window._summaryData || !window._provinceData) return;
|
||||
if (!window._summaryData || !window.latestProvinceData) return;
|
||||
|
||||
const raw = buildAlerts(window._summaryData, window._provinceData);
|
||||
const raw = buildAlerts(window._summaryData, window.latestProvinceData);
|
||||
const finalAlerts = processAlerts(raw);
|
||||
|
||||
renderAlerts(finalAlerts);
|
||||
@@ -1088,6 +879,7 @@ function normalizeProvince(name, validSet) {
|
||||
|
||||
return match || null;
|
||||
}
|
||||
window.normalizeProvince = normalizeProvince;
|
||||
function getRadius(total) {
|
||||
if (!total) return 0;
|
||||
const r = Math.sqrt(total);
|
||||
@@ -1095,10 +887,10 @@ function getRadius(total) {
|
||||
}
|
||||
|
||||
function getPositivityColor(subtype) {
|
||||
return SUBTYPE_COLORS[subtype] || "#9ca3af";
|
||||
return Charts.SUBTYPE_COLORS[subtype] || "#9ca3af";
|
||||
}
|
||||
const getColorByPathogen = name =>
|
||||
SUBTYPE_COLORS[name] || '#9ca3af';
|
||||
Charts.SUBTYPE_COLORS[name] || '#9ca3af';
|
||||
|
||||
function addPositivityLegend() {
|
||||
|
||||
@@ -1157,7 +949,7 @@ function addPositivityLegend() {
|
||||
>
|
||||
|
||||
<span style="
|
||||
background:${SUBTYPE_COLORS[item]};
|
||||
background:${Charts.SUBTYPE_COLORS[item]};
|
||||
width:10px;
|
||||
height:10px;
|
||||
display:inline-block;
|
||||
@@ -1237,7 +1029,7 @@ function loadProvinceMap(
|
||||
map = L.map('provinceMap')
|
||||
.setView([12.7, 104.9], 7);
|
||||
|
||||
|
||||
window.map = map;
|
||||
|
||||
L.tileLayer(
|
||||
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
@@ -1258,7 +1050,7 @@ function loadProvinceMap(
|
||||
])
|
||||
.then(([geojson, data]) => {
|
||||
|
||||
window._provinceData = data;
|
||||
window.latestProvinceData = data;
|
||||
|
||||
updateAlerts();
|
||||
|
||||
@@ -1268,7 +1060,7 @@ function loadProvinceMap(
|
||||
)
|
||||
);
|
||||
|
||||
Object.keys(SUBTYPE_COLORS)
|
||||
Object.keys(Charts.SUBTYPE_COLORS)
|
||||
.forEach(subtype => {
|
||||
|
||||
subtypeLayers[subtype] =
|
||||
@@ -1331,7 +1123,7 @@ function loadProvinceMap(
|
||||
">
|
||||
|
||||
<span>
|
||||
${r.pathogen_name}
|
||||
${r.pathogen_name === 'B/VIC' ? 'B/Vic' : r.pathogen_name}
|
||||
</span>
|
||||
|
||||
<span style="font-weight:600">
|
||||
@@ -1411,17 +1203,17 @@ function loadProvinceMap(
|
||||
{
|
||||
radius: getRadius(row.total),
|
||||
fillColor: getColorByPathogen(
|
||||
row.pathogen_name
|
||||
row.pathogen_name === 'B/VIC' ? 'B/Vic' : row.pathogen_name
|
||||
),
|
||||
fillOpacity: 0.85,
|
||||
stroke: false
|
||||
}
|
||||
);
|
||||
|
||||
if (subtypeLayers[row.pathogen_name]) {
|
||||
if (subtypeLayers[row.pathogen_name === 'B/VIC' ? 'B/Vic' : row.pathogen_name]) {
|
||||
marker.addTo(
|
||||
subtypeLayers[
|
||||
row.pathogen_name
|
||||
row.pathogen_name === 'B/VIC' ? 'B/Vic' : row.pathogen_name
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user