svg = {
const svg = d3.select(DOM.svg(width, height));
let hovered;
simulation
.nodes(graph_filtered)
.force("collide", collide)
.on("tick", ticked)
.alpha(1)
.restart();
const node = svg
.append("g")
.selectAll("circle")
.data(graph_filtered)
.join("circle");
const text = svg
.append('g')
.selectAll('text')
.data(graph_filtered)
.join('text')
.style("pointer-events", "none");
node
.on("pointerenter", (event, d) => {
hovered = d;
simulation.tick();
})
.on("pointerout", (event, d) => {
hovered = null;
simulation.tick();
});
node
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
function ticked() {
node
.attr("r", (d) => {
d.t = (d === hovered) ? (1-(1-d.t)*0.96) : (d.t*0.96);
d.r = (d.r >= 55) ? (d.r) : ((1-d.t)*d.radius + d.t*Math.max(d.radius*1.2, 50));
return d.r;
})
.attr("cx", (d) => d.x)
.attr("cy", (d) => d.y)
.attr("fill", (d) => color(d.continent));
collide
.radius((d) => d.r + nodePadding);
text
.text((d) => d.country)
.attr("visibility", (d) => (d.r >= 45) ? "visible" : "hidden")
.attr("x", (d) => d.x)
.attr("y", (d) => d.y)
.attr("text-anchor", "middle")
.attr("alignment-baseline", "central")
.attr("font-size", 12)
.attr("font-weight", "bold")
.attr("font-family", "sans-serif");
}
function splitBubbles(vis) {
if (vis == "all") {
centerScale
.domain(graph_filtered);
simulation
.force('x', d3.forceX())
.alpha(1)
.restart();
} else {
centerScale
.domain(graph_filtered.map((d) => d[vis]));
simulation
.force('x', d3.forceX().strength(.9).x((d) => centerScale(d[vis])))
.alpha(1)
.restart();
}
};
function hideTitles() {
svg.selectAll('title').remove();
}
function showTitles(scale) {
scale.domain(graph_filtered.map((d) => d[visualization]))
const titles = svg
.append('g')
.selectAll('title')
.data(scale.domain())
titles
.join('text')
.attr('class', 'title')
.merge(titles)
.attr('x',(d) => scale(d)-30)
.attr('y', height-((90/100)*height))
.text((d) => d)
}
splitBubbles(visualization);
return svg.node();
}