{
const height = 300;
const maxRadius = 20;
const margin = 100;
const width = 600;
const xScale = d3
.scaleBand()
.domain(dataset.map((d) => d.mip))
.range([margin, width - margin]);
const yScale = d3
.scaleBand()
.domain(dataset.map((d) => d.mip))
.range([Math.PI, -Math.PI / 4]);
const radiusScale = d3
.scaleLinear()
.domain([0, d3.max(newdata, (d) => d.val)])
.range([0, 1]);
const colorScale = d3
.scaleOrdinal()
.domain([...new Set(newdata.map((d) => d.kind))])
.range(colors);
console.log(colorScale.domain());
const svg = d3
.create("svg")
.attr("viewBox", [0, -height / 2, width, 1.5 * height]);
const simulation = d3
.forceSimulation(newdata)
.force(
"x",
d3
.forceX()
.x((d, i) => xScale(d.mip) + i * 10 + Math.random())
.strength(100)
)
.force(
"y",
d3
.forceY()
.y(height / 2)
.strength(0.1)
)
.force(
"collision",
d3
.forceCollide()
.radius((d) => maxRadius * radiusScale(d.val) ** 0.95 + 5)
.strength(1)
)
.force("charge", d3.forceManyBody().strength(-30).distanceMax(40))
.stop();
svg
.selectAll("circle")
.data(newdata)
.join("circle")
.attr("r", (d) => maxRadius * radiusScale(d.val) ** 0.6)
.attr("cx", (d, i) => xScale(d.mip) + i * Math.random())
.attr(
"cy",
(d, i) =>
0.1 * height +
(Math.sin(yScale(d.mip)) * height) / 2 +
(i + 1) * Math.random()
)
.attr("fill", (d) => colorScale(d.kind))
.attr("fill-opacity", 0.4)
.attr("stroke", (d) => colorScale(d.kind));
const circles = svg.selectAll("circle");
simulation.alpha(1).restart();
function adjustCollisions() {
const padding = 2;
circles.each((currentData, i, nodes) => {
const currentCircle = nodes[i];
const x1 =
+currentCircle.getAttribute("cx") + Math.random() * Math.random();
const y1 =
+currentCircle.getAttribute("cy") + Math.random() * Math.random();
const r1 = +currentCircle.getAttribute("r") + Math.random();
for (let j = 0; j < i; j++) {
const prevCircle = nodes[j];
const x2 = +prevCircle.getAttribute("cx");
const y2 = +prevCircle.getAttribute("cy");
const r2 = +prevCircle.getAttribute("r");
const dx = x1 - x2;
const dy = y1 - y2;
const distance = Math.sqrt(dx * dx + dy * dy);
const minDistance = r1 + r2 + padding;
if (distance < minDistance) {
const moveX = (dx / distance) * (minDistance - distance);
const moveY = (dy / distance) * (minDistance - distance);
currentCircle.setAttribute("cx", x1 + moveX);
currentCircle.setAttribute("cy", y1 + moveY);
}
}
});
simulation.tick();
}
setInterval(adjustCollisions, 1000 / 3);
return svg.node();
}