chart = {
const svg = d3
.create("svg")
.attr("width", config.width)
.attr("height", config.height)
.attr("id", "d3-chord-chart")
.attr("viewBox", [
-config.width / 2,
-config.height / 2,
config.width,
config.height
]);
const g = svg.append("g");
const textId = DOM.uid("text");
const textPath = d3.arc()({
outerRadius: config.outerRadius,
startAngle: 0,
endAngle: 2 * Math.PI
});
g.append("path")
.attr("id", textId.id)
.attr("d", textPath)
.attr("fill", "none")
.attr("stroke", "lightgray");
const arcGen = d3
.arc()
.innerRadius(config.innerRadius)
.outerRadius(config.outerRadius);
const chordGen = d3
.chordDirected()
.padAngle(12 / config.innerRadius)
.sortSubgroups(d3.descending)
.sortChords(d3.descending);
const ribbon = d3
.ribbonArrow()
.radius(config.innerRadius - 0.5)
.padAngle(1 / config.innerRadius);
// ----
function render([matrix, groups]) {
const chord = chordGen(matrix);
const groupByIndex = d3.index(groups.values(), (d) => d.index);
console.log(groupByIndex);
// chord graph content
g.selectAll(".chord-content")
.data(chord, (d) => {
const k = [
groupByIndex.get(d.source.index)?.name,
"-",
groupByIndex.get(d.target.index)?.name
].join("");
console.log(k);
return k;
})
.join(
// enter
(node) =>
node
.append("g")
.attr("class", "chord-content")
.attr("data-content", JSON.stringify)
.call((g) =>
g
.append("path")
.attr("d", ribbon)
.attr("opacity", 0.3)
.attr("fill", (d) => groupByIndex.get(d.source.index).color)
),
(node) =>
node.call((g) =>
g
.select("path")
.attr("d", ribbon)
.attr("fill", (d) => groupByIndex.get(d.source.index).color)
),
// exit
(node) => node.remove()
);
// axis and label
g.selectAll(".axis-arc")
.data(chord.groups, (d) => groupByIndex.get(d.index)?.name)
.join(
// enter
(node) =>
node
.append("g")
.attr("class", "axis-arc")
.attr("data-axis-content", JSON.stringify)
.call((g) =>
g
.append("path")
.attr("opacity", 0.5)
.attr("d", arcGen)
.attr("fill", (d) => groupByIndex.get(d.index).color)
)
.call((g) =>
g
.append("text")
.append("textPath")
.attr("xlink:href", textId.href)
.attr("startOffset", (d) => d.startAngle * config.outerRadius)
.text((d) => groupByIndex.get(d.index)?.name)
),
// update
(node) =>
node
.call((g) =>
g
.select("path")
.attr("d", arcGen)
.attr("fill", (d) => groupByIndex.get(d.index).color)
)
.call((g) =>
g
.select("textPath")
.attr("startOffset", (d) => d.startAngle * config.outerRadius)
.text((d) => groupByIndex.get(d.index)?.name)
),
// exit
(node) => node.remove()
);
}
render(defaultValues);
return Object.assign(svg.node(), { render });
}