arcchart = {
const height = 600;
const ch = height-margin.top-50;
const nodes = Array.from(
new Set(gamedata.flatMap(d => [d.Name, d.Platform]))
).map(id => ({
id,
type: gamedata.some(g => g.Platform === id) ? "platform" : "game"
}));
nodes.sort((a, b) => {
if (a.type === b.type) return d3.ascending(a.id, b.id);
return a.type === "game" ? -1 : 1;
});
const gameNodes = nodes.filter(d => d.type === "game");
const platformNodes = nodes.filter(d => d.type === "platform");
const gx = d3.scaleLinear()
.domain([0, gameNodes.length - 1])
.range([50, width * 0.7]);
const px = d3.scaleLinear()
.domain([0, platformNodes.length - 1])
.range([width * 0.75, width - 50]);
const xPositions = nodes.map(d =>
d.type === "game" ? gx(gameNodes.indexOf(d)) : px(platformNodes.indexOf(d))
);
const nodeIndex = Object.fromEntries(nodes.map((d, i) => [d.id, i]));
const links = gamedata.map(d => ({
source: nodeIndex[d.Name],
target: nodeIndex[d.Platform]
}));
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("preserveAspectRatio", "xMidYMid meet")
.style("width", "100%")
.style("height", "auto")
.style("font", "10px sans-serif")
.style("overflow", "visible");
svg.append("g")
.selectAll("path")
.data(links)
.join("path")
.attr("fill", "none")
.attr("stroke", "#999")
.attr("stroke-width", 1)
.attr("d", d => {
const x1 = xPositions[d.source];
const x2 = xPositions[d.target];
const r = Math.abs(x2 - x1) / 2;
return `M${x1},${ch} A${r},${r} 0 0,1 ${x2},${ch}`;
});
svg.append("g")
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("cx", (d, i) => xPositions[i])
.attr("cy", ch)
.attr("r", d => d.type === "platform" ? 10 : 5)
.style("fill", d => d.type === "platform" ? "#007acc" : "#333")
.style("stroke", "#fff")
.style("stroke-width", 1);
svg.append("g")
.selectAll("text")
.data(nodes)
.join("text")
.attr("transform", (d, i) => `translate(${xPositions[i]},${ch + 10})rotate(90)`)
.attr("text-anchor", "start")
.style("font-size", d => d.type === "platform" ? "12px" : "8px")
.style("font-weight", d => d.type === "platform" ? "bold" : "normal")
.style("fill", d => d.type === "platform" ? "#007acc" : "#333")
.text(d => d.id);
return svg.node();
}