finalize detail page except NDS and squencing
This commit is contained in:
@@ -89,7 +89,6 @@ function loadTrend(periodType, startYear, startWeek, endYear, endWeek) {
|
||||
const [yearB, weekB] = b.split('-').map(Number);
|
||||
|
||||
if (yearA !== yearB) return yearA - yearB;
|
||||
|
||||
return weekA - weekB;
|
||||
|
||||
});
|
||||
@@ -109,11 +108,8 @@ 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;
|
||||
|
||||
});
|
||||
|
||||
datasets.push({
|
||||
@@ -135,14 +131,11 @@ function loadTrend(periodType, startYear, startWeek, endYear, endWeek) {
|
||||
});
|
||||
|
||||
trendChart = new Chart(document.getElementById('trendChart'), {
|
||||
|
||||
type: 'line',
|
||||
|
||||
data: {
|
||||
labels: displayLabels,
|
||||
datasets: datasets
|
||||
},
|
||||
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
@@ -160,11 +153,52 @@ function loadTrend(periodType, startYear, startWeek, endYear, endWeek) {
|
||||
x: { grid: { display: false } }
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Province Map Helpers
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
function normalizeProvince(name, validSet) {
|
||||
if (!name || !validSet) return null;
|
||||
|
||||
const clean = str =>
|
||||
str.toLowerCase().replace(/\s+/g, '');
|
||||
|
||||
const raw = name.trim();
|
||||
|
||||
const map = {
|
||||
"kepville": "Kep",
|
||||
"sihanoukville": "Preah Sihanouk",
|
||||
"sihanoukvillecity": "Preah Sihanouk",
|
||||
"krongpailin": "Pailin",
|
||||
"mondulkiri": "Mondulkiri",
|
||||
"odormeanchey": "Oddar Meanchey",
|
||||
"tbongkhmom": "Tboung Khmum",
|
||||
"tboungkhmum": "Tboung Khmum",
|
||||
"rattanakiri": "Ratanak Kiri"
|
||||
};
|
||||
|
||||
const key = clean(raw);
|
||||
|
||||
if (map[key] && validSet.has(map[key])) {
|
||||
return map[key];
|
||||
}
|
||||
|
||||
const match = [...validSet].find(p => clean(p) === key);
|
||||
|
||||
return match || null;
|
||||
}
|
||||
function getRadius(total) {
|
||||
if (!total) return 0;
|
||||
const r = Math.sqrt(total);
|
||||
return Math.max(4, Math.min(r * 2, 22));
|
||||
}
|
||||
|
||||
|
||||
@@ -184,72 +218,81 @@ function loadProvinceMap(startYear, startWeek, endYear, endWeek) {
|
||||
attribution: '© OpenStreetMap'
|
||||
}).addTo(map);
|
||||
|
||||
|
||||
Promise.all([
|
||||
fetch('/geo/cambodia_provinces.geojson').then(r => r.json()),
|
||||
fetch(`/api/dashboard/province-circles?start_year=${startYear}&start_week=${startWeek}&end_year=${endYear}&end_week=${endWeek}`).then(r => r.json())
|
||||
])
|
||||
.then(([geojson, data]) => {
|
||||
.then(([geojson, data]) => {
|
||||
|
||||
L.geoJSON(geojson, {
|
||||
style: {
|
||||
fillOpacity: 0,
|
||||
color: '#ccc',
|
||||
weight: 1,
|
||||
interactive: false
|
||||
},
|
||||
const validProvinces = new Set(
|
||||
geojson.features.map(f => f.properties.ADM1_EN)
|
||||
);
|
||||
|
||||
onEachFeature: function (feature, layer) {
|
||||
L.geoJSON(geojson, {
|
||||
style: {
|
||||
fillOpacity: 0,
|
||||
color: '#ccc',
|
||||
weight: 1,
|
||||
interactive: false
|
||||
},
|
||||
|
||||
const province = feature.properties.ADM1_EN;
|
||||
const center = layer.getBounds().getCenter();
|
||||
onEachFeature: function (feature, layer) {
|
||||
|
||||
const rows = data.filter(d => d.site_province_name === province);
|
||||
const province = feature.properties.ADM1_EN;
|
||||
const center = layer.getBounds().getCenter();
|
||||
|
||||
const offsets = {
|
||||
1: -0.15,
|
||||
2: 0,
|
||||
3: 0.15
|
||||
};
|
||||
const rows = data.filter(d => {
|
||||
if (![1, 2, 3].includes(d.surveillance_id)) return false;
|
||||
|
||||
rows.forEach(row => {
|
||||
const name = normalizeProvince(d.patient_province, validProvinces);
|
||||
return name === province;
|
||||
});
|
||||
|
||||
const lat = center.lat;
|
||||
const lng = center.lng + offsets[row.surveillance_id];
|
||||
const offsets = { 1: -0.15, 2: 0, 3: 0.15 };
|
||||
|
||||
const programName =
|
||||
row.surveillance_id === 1 ? 'SARI' :
|
||||
row.surveillance_id === 2 ? 'ILI' : 'LBM';
|
||||
const colors = {
|
||||
1: '#2563eb',
|
||||
2: '#10b981',
|
||||
3: '#9333ea'
|
||||
};
|
||||
|
||||
const colors = {
|
||||
1: '#2563eb',
|
||||
2: '#10b981',
|
||||
3: '#9333ea'
|
||||
};
|
||||
rows.forEach(row => {
|
||||
|
||||
L.circleMarker([lat, lng], {
|
||||
const percent = row.total
|
||||
? ((row.positive / row.total) * 100).toFixed(1)
|
||||
: 0;
|
||||
|
||||
radius: 9,
|
||||
fillColor: colors[row.surveillance_id],
|
||||
color: '#fff',
|
||||
weight: 1,
|
||||
fillOpacity: 0.9
|
||||
const offset = offsets[row.surveillance_id] ?? 0;
|
||||
|
||||
})
|
||||
.bindTooltip(`
|
||||
<strong>${province}</strong><br>
|
||||
${programName}<br>
|
||||
Total: ${row.total}
|
||||
`)
|
||||
.addTo(map);
|
||||
const lat = center.lat;
|
||||
const lng = center.lng + offset;
|
||||
|
||||
});
|
||||
const programName =
|
||||
row.surveillance_id === 1 ? 'SARI' :
|
||||
row.surveillance_id === 2 ? 'ILI' : 'LBM';
|
||||
|
||||
}
|
||||
L.circleMarker([lat, lng], {
|
||||
radius: getRadius(row.total),
|
||||
fillColor: colors[row.surveillance_id],
|
||||
color: '#fff',
|
||||
weight: 1,
|
||||
fillOpacity: 0.9
|
||||
})
|
||||
.bindTooltip(`
|
||||
<strong>${province}</strong><br>
|
||||
${programName}<br>
|
||||
Cases: ${row.total}<br>
|
||||
Positivity: ${percent}%
|
||||
`)
|
||||
.addTo(map);
|
||||
|
||||
}).addTo(map);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}).addTo(map);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -267,7 +310,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
new DashboardFilter((startYear, startWeek, endYear, endWeek) => {
|
||||
|
||||
loadTrend('week', startYear, startWeek, endYear, endWeek);
|
||||
|
||||
loadProvinceMap(startYear, startWeek, endYear, endWeek);
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user