chart = {
const svg = d3
.create("svg")
.attr("width", chartWidth + margin.left + margin.right)
.attr("height", chartHeight + margin.top + margin.bottom);
svg.append("style").html(style);
const g = svg
.append("g")
.attr("transform", `translate(${[margin.left, margin.top]})`);
g.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${chartHeight})`)
.call(d3.axisBottom(x));
g.append("g")
.attr("class", "links")
.selectAll("path")
.data(nested)
.join("path")
.attr("fill", "none")
.attr("stroke", (d) =>
highlight.includes(d[0]) ? colour(d[0]) : "#b3b09e"
)
.attr("stroke-width", 1.5)
// we use d[1] to access the data from the nested array
.attr("d", (d) => line(d[1]));
// add circles
g.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(data) // join to ungrouped data because we want a circle for every datapoint
.join("circle")
.attr("fill", (d) =>
highlight.includes(d.country) ? colour(d.country) : "#b3b09e"
)
.attr("stroke", "white")
.attr(
"transform",
(d) => `translate(${x(d.measure) + x.bandwidth() / 2},${y(d.rank)})`
)
.attr("r", 4); // set radius
// add country labels
g.append("g")
.attr("class", "labels")
.selectAll("text")
.data(
//only to final value of the x-scale
data.filter((d) => d.measure == measuresUnique[measuresUnique.length-1])
)
.join("text")
.attr(
"transform",
(d) => `translate(${x(d.measure) + x.bandwidth() / 2},${y(d.rank)})`
)
.text((d) => d.country)
.attr("dy", 4)
.attr("dx", 8);
// add rank labels
g.append("g")
.attr("class", "labels")
.selectAll("text")
.data(
data
.filter((d) => d.measure == measuresUnique[0])
.filter((d) => d.rank % 5 === 0 || d.rank == 1) //only to ranks divisible by five, or to the first rank
)
.join("text")
.attr(
"transform",
(d) => `translate(${x(d.measure) + x.bandwidth() / 2},${y(d.rank)})`
)
.text((d) => d.rank)
.attr("dy", 4)
.attr("dx", -8)
.attr("text-anchor", "end");
// return the outer SVG element so it can be rendered
return svg.node();
}