Choropleth refinements

- Removed zoom + pan for other graphs
- Removed legend/key from choropleth
- Attempts at changing country border strokes when toggling between light/dark mode
This commit is contained in:
bennteaa 2025-06-02 22:11:28 +10:00
parent 3de4b68136
commit 52c4d65792
2 changed files with 46 additions and 10 deletions

BIN
.DS_Store vendored

Binary file not shown.

View file

@ -80,6 +80,8 @@ darkModeToggle.addEventListener('click', () => {
g.selectAll("text").style("fill", darkMode ? "#eee" : "#000"); g.selectAll("text").style("fill", darkMode ? "#eee" : "#000");
g.selectAll(".lowest-annotation").style("fill", darkMode ? "#eee" : "red"); g.selectAll(".lowest-annotation").style("fill", darkMode ? "#eee" : "red");
g.selectAll(".lowest-box").attr("fill", darkMode ? "#222" : "#fff").attr("stroke", darkMode ? "#aaa" : "#999"); g.selectAll(".lowest-box").attr("fill", darkMode ? "#222" : "#fff").attr("stroke", darkMode ? "#aaa" : "#999");
// Update the chart as different colours are used in different charts (namely the choropleth)
updateChart();
}); });
@ -144,6 +146,12 @@ Promise.all([
updateLegend(selectedChart); updateLegend(selectedChart);
// Remove zoom for non-choropleth charts
if (selectedChart !== "choropleth") {
svg.on(".zoom", null); // Remove zoom event listeners
g.attr("transform", `translate(${margin.left},${margin.top})`); // Reset transform
}
// Update chart titles // Update chart titles
let title1 = "Self-Reported Health"; let title1 = "Self-Reported Health";
let title2 = ""; let title2 = "";
@ -179,7 +187,7 @@ Promise.all([
} else if (selectedChart === "heatmap") { } else if (selectedChart === "heatmap") {
drawHeatmap(filteredData); drawHeatmap(filteredData);
} else if (selectedChart === "choropleth") { } else if (selectedChart === "choropleth") {
drawChoropleth(filteredData, worldData); drawChoropleth(filteredData, worldData, selectedContinent);
} }
} }
@ -200,11 +208,11 @@ Promise.all([
const c = d3.select("#continentSelect").property("value"); const c = d3.select("#continentSelect").property("value");
const s = d3.select("#sexSelect").property("value"); const s = d3.select("#sexSelect").property("value");
const e = d3.select("#incomeSelect").property("value"); const e = d3.select("#incomeSelect").property("value");
const chartType = d3.select("#chartTypeSelect").property("value"); //Get selected chart type const chartType = d3.select("#chartTypeSelect").property("value");
const parts = [ const parts = [
"education_health", "education_health",
chartType, //Add chart type into the filename chartType,
c !== "All" ? c : null, c !== "All" ? c : null,
s !== "All" ? s : null, s !== "All" ? s : null,
e !== "All" ? e.replace(/[^a-zA-Z0-9]+/g, "_").toLowerCase() : null e !== "All" ? e.replace(/[^a-zA-Z0-9]+/g, "_").toLowerCase() : null
@ -221,7 +229,7 @@ Promise.all([
// Update legend depending on chart type // Update legend depending on chart type
function updateLegend(chartType) { function updateLegend(chartType) {
const legend = d3.select("#legend"); const legend = d3.select("#legend");
legend.html(""); // Clear existing legend.html("");
if (chartType === "heatmap") { if (chartType === "heatmap") {
const wrapper = legend.append("div") const wrapper = legend.append("div")
@ -241,7 +249,9 @@ function updateLegend(chartType) {
.style("justify-content", "space-between") .style("justify-content", "space-between")
.style("font-size", "12px") .style("font-size", "12px")
.html('<span>0%</span><span>50%</span><span>100%</span>'); .html('<span>0%</span><span>50%</span><span>100%</span>');
} else if (chartType === "choropleth") {
// No drawing of any legend for choropleth
return;
} else { } else {
educationLevels.forEach(level => { educationLevels.forEach(level => {
const item = legend.append("div").attr("class", "legend-item"); const item = legend.append("div").attr("class", "legend-item");
@ -541,7 +551,7 @@ function drawHeatmap(data) {
} }
// Choropleth map drawing function // Choropleth map drawing function
function drawChoropleth(data, worldData) { function drawChoropleth(data, worldData, selectedContinent) {
// Remove any previous zoom behavior // Remove any previous zoom behavior
svg.on("mousedown.zoom", null).on("touchstart.zoom", null).on("touchmove.zoom", null).on("touchend.zoom", null); svg.on("mousedown.zoom", null).on("touchstart.zoom", null).on("touchmove.zoom", null).on("touchend.zoom", null);
@ -577,7 +587,7 @@ function drawChoropleth(data, worldData) {
const val = valueByCountry[name]; const val = valueByCountry[name];
return val != null ? colorScale(val) : "#ccc"; return val != null ? colorScale(val) : "#ccc";
}) })
.attr("stroke", darkMode ? "#222" : "#fff") .attr("stroke", () => darkMode ? "#fff" : "#000")
.attr("stroke-width", 0.5) .attr("stroke-width", 0.5)
.on("mouseover", function(event, d) { .on("mouseover", function(event, d) {
const name = d.properties.name; const name = d.properties.name;
@ -596,12 +606,38 @@ function drawChoropleth(data, worldData) {
}); });
// Add zoom and pan // Add zoom and pan
svg.call(d3.zoom() const zoomBehavior = d3.zoom()
.scaleExtent([1, 8]) .scaleExtent([1, 8])
.on("zoom", (event) => { .on("zoom", (event) => {
g.attr("transform", event.transform); g.attr("transform", event.transform);
}) });
svg.call(zoomBehavior);
// Zoom to continent if selected
if (selectedContinent && selectedContinent !== "All") {
// Get country names in the selected continent
const countriesInContinent = data
.filter(d => d.CONTINENT === selectedContinent)
.map(d => d["Reference area"]);
// Find features for those countries
const features = countries.filter(f => countriesInContinent.includes(f.properties.name));
if (features.length > 0) {
// Compute bounding box
const geoPath = d3.geoPath().projection(projection);
const bounds = geoPath.bounds({type: "FeatureCollection", features});
const [[x0, y0], [x1, y1]] = bounds;
const dx = x1 - x0, dy = y1 - y0;
const scale = Math.max(1, Math.min(8, 0.9 / Math.max(dx / width, dy / height)));
const translate = [
width / 2 - scale * (x0 + dx / 2),
height / 2 - scale * (y0 + dy / 2)
];
svg.transition().duration(1000).call(
zoomBehavior.transform,
d3.zoomIdentity.translate(translate[0], translate[1]).scale(scale)
); );
}
}
// Add legend for color scale // Add legend for color scale
const legendWidth = 200; const legendWidth = 200;