diff options
| author | Christian Cleberg <[email protected]> | 2026-04-17 19:41:31 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-04-17 19:41:31 -0500 |
| commit | 623ae07ebacb9d596b225179727dc87641ad1cca (patch) | |
| tree | f1045282b3369bf3f4b0249cd649b47a5d010dad /assets/js/ui/compare.js | |
| parent | fd412c5197286518ff9491a1b51e6319c9a22904 (diff) | |
| download | world-incarceration-623ae07ebacb9d596b225179727dc87641ad1cca.tar.gz world-incarceration-623ae07ebacb9d596b225179727dc87641ad1cca.tar.bz2 world-incarceration-623ae07ebacb9d596b225179727dc87641ad1cca.zip | |
phase 2-6: complete D3/TopoJSON migration
Replace ZingChart + jQuery with D3 v7 + TopoJSON. Implements all
planned phases: choropleth map (NaturalEarth1 projection, YlOrRd
gradient), hover tooltip, zoom/pan/reset, country detail modal,
side-by-side compare, metric selector, label toggle, donut pie chart
with per-country drilldown bar chart. Upgrades Bootstrap JS bundle
from v4.5.3 (jQuery-dependent) to v5.0.0, fixes modal API calls
to use getInstance/constructor pattern compatible with BS 5.0.0+.
Removes jquery, zingchart ×3 library files.
Diffstat (limited to 'assets/js/ui/compare.js')
| -rw-r--r-- | assets/js/ui/compare.js | 72 |
1 files changed, 70 insertions, 2 deletions
diff --git a/assets/js/ui/compare.js b/assets/js/ui/compare.js index d933609..3b0a8bb 100644 --- a/assets/js/ui/compare.js +++ b/assets/js/ui/compare.js @@ -1,2 +1,70 @@ -// Phase 5: side-by-side country comparison panel -export function initCompare(countries) {} +let _pendingResult = false; + +export function initCompare(countries) { + const opts = Object.entries(countries) + .sort((a, b) => a[1].country.localeCompare(b[1].country)) + .map(([key, val]) => `<option value="${key}">${val.country}</option>`) + .join(""); + + document.getElementById("compare-select-1").innerHTML = opts; + document.getElementById("compare-select-2").innerHTML = opts; + + document.getElementById("compare-go-btn").addEventListener("click", () => { + const k1 = document.getElementById("compare-select-1").value; + const k2 = document.getElementById("compare-select-2").value; + + if (k1 === k2) { + document.getElementById("compare-alert").innerHTML = + "<div class='alert alert-danger'>Please select two different countries.</div>"; + return; + } + document.getElementById("compare-alert").innerHTML = ""; + _prepareResult(countries[k1], countries[k2]); + _pendingResult = true; + const cm = document.getElementById("compareModal"); + (bootstrap.Modal.getInstance(cm) || new bootstrap.Modal(cm)).hide(); + }); + + // Show result modal only after compareModal finishes hiding + document.getElementById("compareModal").addEventListener("hidden.bs.modal", () => { + if (_pendingResult) { + _pendingResult = false; + const rm = document.getElementById("compareResultModal"); + (bootstrap.Modal.getInstance(rm) || new bootstrap.Modal(rm)).show(); + } + }); +} + +function _prepareResult(c1, c2) { + document.getElementById("compare-result-c1").textContent = c1.country; + document.getElementById("compare-result-c2").textContent = c2.country; + + const rows = [ + ["Prison Population", _fmt(c1.pop, "pop"), _fmt(c2.pop, "pop")], + ["Rate per 100,000", _fmt(c1.rate, "rate"), _fmt(c2.rate, "rate")], + ["Females", _fmt(c1.females, "pct"), _fmt(c2.females, "pct")], + ["Juveniles", _fmt(c1.juveniles, "pct"), _fmt(c2.juveniles, "pct")], + ["Occupancy", _fmt(c1.occupancy, "pct"), _fmt(c2.occupancy, "pct")], + ["Government", _fmtGov(c1.government), _fmtGov(c2.government)], + ]; + + document.getElementById("compare-result-body").innerHTML = rows + .map(([label, v1, v2]) => + `<tr><td><b>${label}</b></td><td>${v1}</td><td>${v2}</td></tr>` + ) + .join(""); +} + +function _fmt(val, type) { + if (val === "--" || val === null || val === undefined || (typeof val === "number" && isNaN(val))) { + return "<span class='text-danger'>N/A</span>"; + } + if (type === "pop") return Number(val).toLocaleString("en"); + if (type === "rate") return String(val); + if (type === "pct") return (val * 100).toFixed(2) + " %"; + return String(val); +} + +function _fmtGov(val) { + return (!val || val === "--") ? "<span class='text-danger'>N/A</span>" : val; +} |
