chart = {
const svg = d3
.create("svg")
.style("width", width + "px")
.style("height", height + "px")
.attr("viewBox", [0, 0, width, height])
.style("font", "12px sans-serif");
const simulation = d3
.forceSimulation(director)
.force("charge", d3.forceManyBody().strength(90))
.force("center", d3.forceCenter(width / 2, height / 2))
.force("forceY", d3.forceY(height / 2).strength(0.1))
.force(
"collision",
d3.forceCollide().radius((d) => radius(d.episodes) + 2)
)
.on("tick", ticked);
function ticked() {
svg
.selectAll("circle")
.data(director)
.join("circle")
.attr("r", (d) => radius(d.episodes))
.attr("cx", (d) => d.x)
.attr("cy", (d) => d.y)
.style("fill", (d) => colorScale(d.imdbAvg))
.style("fill-opacity", "0.5")
.style("stroke", "#333")
.on("mousemove", nodeMouseOver)
.on("mouseout", nodeMouseOut);
svg
.selectAll("text")
.data(director)
.join("text")
.text((d) => (d.episodes > 15 ? d.director : ""))
.style("text-anchor", "middle")
.style("fill", "#333")
.style("font-family", "Arial")
.style("font-size", 12)
.attr("x", (data) => data.x)
.attr("y", (data) => data.y);
}
function nodeMouseOver(event, d) {
let x = event.pageX + 18;
let y = event.pageY;
x > width - 200 ? (x = x - 218) : x;
toolTip
.style("left", x + "px")
.style("top", y + 2 + "px")
.style("display", "block")
.html(
`<strong>${d.director}</strong><br>Episodes: <strong>${d.episodes}</strong><br>IMDb Average: <strong>${d.imdbAvg}</strong>`
);
}
function nodeMouseOut(event, d) {
toolTip.style("display", "none");
}
return svg.node();
}