viz = {
d3.select('#_svg').remove();
const wrapper = d3
.select("#wrapper")
.append("svg")
.attr('id', '_svg')
.attr("width", width)
.attr("height", height);
const bounds = wrapper
.append("g")
.style("transform", `translate(${margins.left}px, ${margins.top}px)`);
const earth = bounds
.append("path")
.attr("class", "earth")
.attr("d", pathGenerator(sphere));
const graticuleJson = d3.geoGraticule10();
const graticule = bounds
.append("path")
.attr("class", "graticule")
.attr("d", pathGenerator(graticuleJson));
const countries = bounds
.selectAll(".country")
.data(countryShapes.features)
.enter()
.append("path")
.attr("class", d => ["country", countryIdAccessor(d)].join(" "))
.attr("d", pathGenerator)
.attr("fill", d => {
const metricValue = metricDataByRegion[countryIdAccessor(d)];
if (typeof metricValue == "undefined") return "#e2e6e9";
return colorScale(metricValue);
});
const voronoi = bounds
.selectAll(".voronoi")
.data(countryShapes.features)
.enter()
.append("path")
.attr("class", "voronoi")
.attr("d", (d, i) => voronoiGenerator.renderCell(i));
const legendGroup = wrapper
.append("g")
.attr(
"transform",
`translate(${120},${
width < 800 ? boundedHeight - 30 : boundedHeight * 0.5
})`
);
const legendTitle = legendGroup
.append("text")
.attr("y", -23)
.attr("class", "legend-title")
.text("Population growth");
const legendByline = legendGroup
.append("text")
.attr("y", -9)
.attr("class", "legend-byline")
.text("Percent change in 2017");
const defs = wrapper.append("defs");
const legendGradientId = "legend-gradient";
const gradient = defs
.append("linearGradient")
.attr("id", legendGradientId)
.selectAll("stop")
.data(colorScale.range())
.enter()
.append("stop")
.attr("stop-color", d => d)
.attr(
"offset",
(d, i) =>
`${
(i * 100) / 2
}%`
);
const legendWidth = 120;
const legendHeight = 16;
const legendGradient = legendGroup
.append("rect")
.attr("x", -legendWidth / 2)
.attr("height", legendHeight)
.attr("width", legendWidth)
.style("fill", `url(#${legendGradientId})`);
const legendValueRight = legendGroup
.append("text")
.attr("class", "legend-value")
.attr("x", legendWidth / 2 + 10)
.attr("y", legendHeight / 2)
.text(`${d3.format(".1f")(maxChange)}%`);
const legendValueLeft = legendGroup
.append("text")
.attr("class", "legend-value")
.attr("x", -legendWidth / 2 - 10)
.attr("y", legendHeight / 2)
.text(`${d3.format(".1f")(-maxChange)}%`)
.style("text-anchor", "end");
navigator.geolocation.getCurrentPosition(myPosition => {
const [x, y] = projection([
myPosition.coords.longitude,
myPosition.coords.latitude
]);
const myLocation = bounds
.append("circle")
.attr("class", "my-location")
.attr("cx", x)
.attr("cy", y)
.attr("r", 0)
.transition()
.duration(500)
.attr("r", 10);
});
voronoi.on("mouseenter", onMouseEnter).on("mouseleave", onMouseLeave);
const tooltip = d3.select("#tooltip");
function onMouseEnter(...args) {
const datum = args[1];
tooltip.style("opacity", 1);
const countryId = countryIdAccessor(datum);
const metricValue = metricDataByRegion[countryId] || 0;
tooltip.select("#country").text(countryNameAccessor(datum));
tooltip.select("#value").text(`${d3.format(",.2f")(metricValue)}%`);
const [centerX, centerY] = pathGenerator.centroid(datum);
const x = centerX + margins.left;
const y = centerY + margins.top;
tooltip.style(
"transform",
`translate(` + `calc( -50% + ${x}px),` + `calc(-100% + ${y}px)` + `)`
);
d3.select(`.${countryId}`).classed("is-hovered", true);
}
function onMouseLeave() {
tooltip.style("opacity", 0);
d3.selectAll(`.country`).classed("is-hovered", false);
}
return `Renders the map`;
}