map = {
const width = 960;
const height = 500;
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height)
.style("max-width", "100%")
.style("height", "auto");
const tooltip = d3.select(document.body)
.append("div")
.style("position", "absolute")
.style("visibility", "hidden")
.style("background-color", "white")
.style("border", "solid")
.style("border-width", "1px")
.style("border-radius", "5px")
.style("padding", "10px");
const projection = d3.geoNaturalEarth1()
.fitSize([width, height], topojson.feature(countriesData, countriesData.objects.countries));
const path = d3.geoPath()
.projection(projection);
svg.append("g")
.selectAll("path")
.data(topojson.feature(countriesData, countriesData.objects.countries).features)
.join("path")
.attr("d", path)
.attr("fill", d => {
const countryName = d.properties.name;
const mappedName = getCountryMappedName(countryName);
const temp = getTemperature(mappedName, selectedYear, selectedMonth.value);
return temp !== null ? colorScale(temp) : "#ccc";
})
.attr("stroke", "#fff")
.attr("stroke-width", 0.5)
.on("mouseover", function(event, d) {
d3.select(this).attr("stroke-width", 1.5);
const countryName = d.properties.name;
const mappedName = getCountryMappedName(countryName);
const temp = getTemperature(mappedName, selectedYear, selectedMonth.value);
tooltip
.style("visibility", "visible")
.html(`<strong>${countryName}</strong><br>Temperature: ${temp !== null ? temp.toFixed(2) + "°C" : "No data"}`);
tooltip
.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY - 28) + "px");
})
.on("mousemove", function(event) {
tooltip
.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY - 28) + "px");
})
.on("mouseout", function() {
d3.select(this).attr("stroke-width", 0.5);
tooltip.style("visibility", "hidden");
});
const legendWidth = 300;
const legendHeight = 20;
const legend = svg.append("g")
.attr("transform", `translate(${width - legendWidth - 10}, ${height - 40})`);
const defs = svg.append("defs");
const linearGradient = defs.append("linearGradient")
.attr("id", "temperature-gradient")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "0%");
linearGradient.selectAll("stop")
.data([
{offset: "0%", color: colorScale(minTemp)},
{offset: "50%", color: colorScale(0)},
{offset: "100%", color: colorScale(maxTemp)}
])
.join("stop")
.attr("offset", d => d.offset)
.attr("stop-color", d => d.color);
legend.append("rect")
.attr("width", legendWidth)
.attr("height", legendHeight)
.style("fill", "url(#temperature-gradient)");
legend.selectAll(".legend-tick")
.data([minTemp, 0, maxTemp])
.join("g")
.attr("class", "legend-tick")
.attr("transform", d => `translate(${legendWidth * (d - minTemp) / (maxTemp - minTemp)}, 0)`)
.call(g => g.append("line")
.attr("y1", legendHeight)
.attr("y2", legendHeight + 6)
.attr("stroke", "black"))
.call(g => g.append("text")
.attr("y", legendHeight + 16)
.attr("text-anchor", "middle")
.attr("font-size", "10px")
.text(d => d + "°C"));
legend.append("text")
.attr("x", legendWidth / 2)
.attr("y", -5)
.attr("text-anchor", "middle")
.attr("font-size", "12px")
.text("Average Temperature");
return svg.node();
}