Recently I am trying to understand D3 Chord graphs, especially with the D3v7. I got two different datasets and want to dynamically update those sets. In general it works beside two problems:
The first object in each datasets will be ignored. I do not why as any console.log shows the existing data but it is simply not drawn. For example dataset 1 based on groups1 and paths1 is missing object A and in dataset2 object E is missing.
As soon as the graph gets updated the old elements are still there and the graph creates new paths without removing the old ones. Each click and change increases the D3 elements in the browser, instead replacing them.
Since D3v3 and D3v7 a bit changed and I can´t figure out quickly enough to help myself.
////////////////////////////////////////////////////////////
////////////////////// Set-Up Data /////////////////////////
////////////////////////////////////////////////////////////
let groups1 = [
{ name: "A", color: "blue" },
{ name: "B", color: "red" },
{ name: "C", color: "green" },
{ name: "D", color: "yellow" },
]
let paths1 = [
{ from: groups1.name = "A", to: groups1.name = "A", strength: 0 },
{ from: groups1.name = "A", to: groups1.name = "B", strength: 5 },
{ from: groups1.name = "A", to: groups1.name = "C", strength: 5 },
{ from: groups1.name = "A", to: groups1.name = "D", strength: 5 },
{ from: groups1.name = "B", to: groups1.name = "A", strength: 5 },
{ from: groups1.name = "B", to: groups1.name = "B", strength: 0 },
{ from: groups1.name = "B", to: groups1.name = "C", strength: 5 },
{ from: groups1.name = "B", to: groups1.name = "D", strength: 5 },
{ from: groups1.name = "C", to: groups1.name = "A", strength: 5 },
{ from: groups1.name = "C", to: groups1.name = "B", strength: 5 },
{ from: groups1.name = "C", to: groups1.name = "C", strength: 0 },
{ from: groups1.name = "C", to: groups1.name = "D", strength: 5 },
{ from: groups1.name = "D", to: groups1.name = "D", strength: 0 },
{ from: groups1.name = "D", to: groups1.name = "A", strength: 5 },
{ from: groups1.name = "D", to: groups1.name = "B", strength: 5 },
{ from: groups1.name = "D", to: groups1.name = "C", strength: 5 },
]
let groups2 = [
{ name: "E", color: "#301E1E" },
{ name: "F", color: "#083E77" },
{ name: "G", color: "#342350" },
]
let paths2 = [
{ from: groups2.name = "E", to: groups2.name = "E", strength: 0 },
{ from: groups2.name = "E", to: groups2.name = "F", strength: 5 },
{ from: groups2.name = "E", to: groups2.name = "G", strength: 5 },
{ from: groups2.name = "F", to: groups2.name = "E", strength: 5 },
{ from: groups2.name = "F", to: groups2.name = "F", strength: 0 },
{ from: groups2.name = "F", to: groups2.name = "G", strength: 5 },
{ from: groups2.name = "G", to: groups2.name = "E", strength: 5 },
{ from: groups2.name = "G", to: groups2.name = "F", strength: 5 },
{ from: groups2.name = "G", to: groups2.name = "G", strength: 0 },
]
let chord = []
let matrix = []
function getMatrix(paths, groups) {
matrix = []
var mapPaths = paths.map(item => {
const container = {}
container.from = groups.findIndex(ele => ele.name == item.from)
container.to = groups.findIndex(ele => ele.name == item.to)
container.strength = item.strength
return container
})
mapPaths.forEach(function (item) {
// initialize sub-arra if not yet exists
if (!matrix[item.to]) {
matrix[item.to] = []
}
matrix[item.to][item.from] = item.strength
})
return matrix
}
// --- --- --- --- --- ---
const vw = document.documentElement.clientWidth / 2
const vh = document.documentElement.clientHeight / 2
let innerRadius = Math.min(vw, vh) * 0.5
let outerRadius = innerRadius * 1.1;
let svg = d3.select("#chart").append("svg")
.attr("width", vw)
.attr("height", vh)
.attr("overflow", "unset")
var chordGenerator = d3.chord()
.padAngle(0.10)
.sortSubgroups(d3.ascending)
.sortChords(d3.descending)
chord = chordGenerator(getMatrix(paths1, groups1))
var arc = d3.arc()
.innerRadius(innerRadius * 1.01)
.outerRadius(outerRadius)
var ribbon = d3.ribbon()
.radius(innerRadius);
window.update = update;
update(paths1, groups1)
function update(thisPaths, thisGroups) {
let groups = thisGroups
let paths = thisPaths
getMatrix(thisPaths, thisGroups)
const chords = chordGenerator(matrix);
let wrapper = svg.append("g")
.attr("transform", "translate(" + vw / 2 + "," + vh / 2 + ")")
let ribbons = wrapper.append("g");
let g = wrapper.selectAll("g")
.data(chord.groups)
.enter()
.append("g")
.attr("class", "group")
const ribbonsUpdate = ribbons.selectAll("path")
.data(chords, ({ source, target }) => source.index + '-' + target.index)
const duration = 1000;
ribbonsUpdate
.transition()
.duration(duration)
.attr("d", ribbon)
.style("fill", function (d) { return groups[d.target.index].color; })
ribbonsUpdate
.enter()
.append("path")
.attr("opacity", 0)
.attr("d", ribbon)
.style("fill", function (d) { return groups[d.target.index].color; })
.transition()
.duration(duration)
.attr('opacity', 1)
// adding Arc Blocks
g.append("path")
.style("fill", function (d) { return groups[d.index].color; })
.attr("d", arc)
.style("opacity", 1)
// adding labels
g.append("text")
.each(function(d){ d.angle = (d.startAngle + d.endAngle) / 2; })
.attr("dy", ".35em")
.attr("class", "titles")
.attr("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; })
.attr("transform", function(d) {
return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")"
+ "translate(" + (outerRadius + 10) + ")"
+ (d.angle > Math.PI ? "rotate(180)" : "");
})
.text(function(d,i){ return groups[i].name; })
ribbonsUpdate
.exit()
.transition()
.duration(duration)
.attr("opacity", 0)
.remove();
}
document.getElementById('data1').onclick = () => {
chord = chordGenerator(getMatrix(paths1, groups1))
update(paths1, groups1);
}
document.getElementById('data2').onclick = () => {
chord = chordGenerator(getMatrix(paths2, groups2))
update(paths2, groups2);
}
body {
font-size: 16px;
font-family: 'Oswald', sans-serif;
text-align: center;
background-color: #ECF0F3;
cursor: default;
overflow: hidden;
}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>Animated_D3v7</title>
<!-- jQuery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<!-- D3.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.6.1/d3.min.js" charset="utf-8"></script>
<!-- fontawesome stylesheet https://fontawesome.com/ -->
<script src="https://kit.fontawesome.com/98a5e27706.js" crossorigin="anonymous"></script>
</head>
<style>
body {
font-size: 16px;
font-family: 'Oswald', sans-serif;
background-color: #ECF0F3;
cursor: default;
overflow: hidden;
}
</style>
<body>
<button id="data1">data 1</button>
<button id="data2">data 2</button>
<div id="chart"></div>
</body>
</html>