I struggle with the following D3 Chord layout. So far I splitted the data to dependencies and flows. With the help of this data a matrix will be generated to actually draw the dependencies as a chord layout visualization.
By nature data is growing and I tried to push() a dummy data into dependencies and also flows. Further I call my init() function where all the D3 magic is placed. But instead to to redraw the circle the additional data the new data is drawn on top of existing data.
What do I miss?
////////////////////////////////////////////////////////////
//////////////////////// Set-Up ////////////////////////////
////////////////////////////////////////////////////////////
var dependencies = [
{ id: 0, name: "0", color: "#301E1E" },
{ id: 1, name: "1", color: "#083E77" },
{ id: 2, name: "2", color: "#342350" },
{ id: 3, name: "3", color: "#567235" },
]
var flows = [
{ from: 0, to: 0, quantity: 0 },
{ from: 0, to: 1, quantity: 4 },
{ from: 0, to: 2, quantity: 3 },
{ from: 0, to: 3, quantity: 2 },
{ from: 1, to: 0, quantity: 4 },
{ from: 1, to: 1, quantity: 0 },
{ from: 1, to: 2, quantity: 3 },
{ from: 1, to: 3, quantity: 2 },
{ from: 2, to: 0, quantity: 3 },
{ from: 2, to: 1, quantity: 3 },
{ from: 2, to: 2, quantity: 0 },
{ from: 2, to: 3, quantity: 0 },
{ from: 3, to: 0, quantity: 2 },
{ from: 3, to: 1, quantity: 2 },
{ from: 3, to: 2, quantity: 2 },
{ from: 3, to: 3, quantity: 0 },
]
var matrix = []
////////////////////////////////////////////////////////////
////////////////////// Create SVG //////////////////////////
////////////////////////////////////////////////////////////
var margin = { left: 20, top: 20, right: 20, bottom: 20 }
var width = Math.min(window.innerWidth, 900) - margin.left - margin.right
var height = Math.min(window.innerHeight, 900) - margin.top - margin.bottom
var innerRadius = Math.min(width, height) * 0.39
var outerRadius = innerRadius * 1.1;
var opacityDefault = 0.8;
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + (width / 2 + margin.left) + "," + (height / 2 + margin.top) + ")");
////////////////////////////////////////////////////////////
/////////// Create scale and layout functions //////////////
////////////////////////////////////////////////////////////
init()
function init() {
// Map flows data to valid matrix
flows.forEach(function (flow) {
//initialize sub-array if not yet exists
if (!matrix[flow.to]) {
matrix[flow.to] = [];
}
matrix[flow.to][flow.from] = flow.quantity;
})
//A "custom" d3 chord function that automatically sorts the order of the chords in such a manner to reduce overlap
var chord = d3.layout.chord()
.padding(.15)
.sortChords(d3.descending) //which chord should be shown on top when chords cross. Now the biggest chord is at the bottom
.matrix(matrix);
var arc = d3.svg.arc()
.innerRadius(innerRadius * 1.01)
.outerRadius(outerRadius);
var path = d3.svg.chord()
.radius(innerRadius);
////////////////////////////////////////////////////////////
////////////////// Draw outer Arcs /////////////////////////
////////////////////////////////////////////////////////////
var outerArcs = svg.selectAll("g.group")
.data(chord.groups)
.enter().append("g")
.attr("class", "group")
outerArcs.append("path")
.style("fill", function (d) { return dependencies[d.index].color; })
//.style("fill", function(d) { return colors(d.index); })
.attr("d", arc)
.each(function (d, i) {
//Search pattern for everything between the start and the first capital L
var firstArcSection = /(^.+?)L/;
//Grab everything up to the first Line statement
var newArc = firstArcSection.exec(d3.select(this).attr("d"))[1];
//Replace all the comma's so that IE can handle it
newArc = newArc.replace(/,/g, " ");
//If the end angle lies beyond a quarter of a circle (90 degrees or pi/2)
//flip the end and start position
if (d.endAngle > 90 * Math.PI / 180 & d.startAngle < 270 * Math.PI / 180) {
var startLoc = /M(.*?)A/, //Everything between the first capital M and first capital A
middleLoc = /A(.*?)0 0 1/, //Everything between the first capital A and 0 0 1
endLoc = /0 0 1 (.*?)$/; //Everything between the first 0 0 1 and the end of the string (denoted by $)
//Flip the direction of the arc by switching the start en end point (and sweep flag)
//of those elements that are below the horizontal line
var newStart = endLoc.exec(newArc)[1];
var newEnd = startLoc.exec(newArc)[1];
var middleSec = middleLoc.exec(newArc)[1];
//Build up the new arc notation, set the sweep-flag to 0
newArc = "M" + newStart + "A" + middleSec + "0 0 0 " + newEnd;
}//if
//Create a new invisible arc that the text can flow along
svg.append("path")
.attr("class", "hiddenArcs")
.attr("id", "arc" + i)
.attr("d", newArc)
.style("fill", "none");
});
////////////////////////////////////////////////////////////
////////////////// Append Names ////////////////////////////
////////////////////////////////////////////////////////////
//Append the label names on the outside
outerArcs.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)" : "");
})
.style("font-size", 16 + "px")
.text(function (d, i) { return dependencies[i].name; });
////////////////////////////////////////////////////////////
////////////////// Draw inner chords ///////////////////////
////////////////////////////////////////////////////////////
svg.selectAll("path.chord")
.data(chord.chords)
.enter().append("path")
.attr("class", "chord")
.style("fill", "grey")
.style("opacity", opacityDefault)
.attr("d", path)
}
////////////////////////////////////////////////////////////
/////////////////////// Add more Data //////////////////////
////////////////////////////////////////////////////////////
document.getElementById("chart").onclick = function() {
dependencies.push({
id: dependencies.length,
name: dependencies.length,
color: "black"
})
// Creates new Flows and set quantity to 1
for (var i = 0; i < dependencies.length; i++) {
flows.push({
from: dependencies.length - 1,
to: i,
quantity: 1,
})
}
// Adds new Flow quantity to existing flows
for (var j = 0; j < dependencies.length; j++) {
flows.push({
from: j,
to: dependencies.length - 1,
quantity: 1,
})
}
init()
}
body {
font-size: 12px;
font-family: 'Lato', sans-serif;
text-align: center;
fill: #2B2B2B;
cursor: default;
}
@media (min-width: 600px) {
#chart {
font-size: 16px;
}
}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>Step 1 - Collaborations between MCU Avengers</title>
<!-- D3.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<!-- Google Fonts -->
<link href='https://fonts.googleapis.com/css?family=Lato:400,900' rel='stylesheet' type='text/css'>
</head>
<body>
<div id="chart"></div>
</body>
</html>