This example created for development purposes using the d3-sankey plugin for D3 4.0.
Based on xaranke's port of Mike Bostock's Sankey Diagram with drag behavior enabled and several fixes for the d3 version 4.x release.
It would be nice if d3-sankey's value
accessor was configurable, to avoid creating the empty_links
data structure in the code below.
xxxxxxxxxx
<html>
<meta charset="utf-8">
<title>Sankey Diagram</title>
<style>
body {
font-family: sans-serif;
}
#chart {
height: 500px;
}
.node rect {
cursor: move;
fill-opacity: .9;
shape-rendering: crispEdges;
}
.node text {
pointer-events: none;
font-size: 12px;
}
.link {
fill: none;
stroke: #000;
stroke-opacity: .16;
}
.link:hover {
stroke-opacity: .5;
}
</style>
<body>
<div id="chart"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://unpkg.com/d3-sankey@0.4.1"></script>
<script>
var margin = {
top: 1,
right: 1,
bottom: 6,
left: 1
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var fontScale = d3.scaleLinear()
.range([8, 30]);
var formatNumber = d3.format(",.0f"),
format = function(d) {
return formatNumber(d) + " TWh";
},
color = d3.scaleOrdinal(d3.schemeCategory20);
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(" + margin.left + "," + margin.top + ")");
var weightText = svg.append("text")
.text("Links weighted equally")
.attr("x", width/2-170)
.attr("y", height)
.style("font-size", "24px");
var sankey = d3.sankey()
.nodeWidth(15)
.nodePadding(10)
.size([width, height]);
var path = sankey.link();
d3.json("energy.json", function(energy) {
var empty_links = energy.links.map(function(d) {
d.id = d.source + " -> " + d.target;
return {
source: d.source,
target: d.target,
id: d.id,
value: 1
}
});
sankey
.nodes(energy.nodes)
.links(empty_links)
.layout(32);
fontScale.domain(d3.extent(energy.nodes, function(d) { return d.value }));
var link = svg.append("g").selectAll(".link")
.data(empty_links, function(d) { return d.id; })
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke-width", function(d) {
return Math.max(1, d.dy) + "px";
})
.sort(function(a, b) {
return b.dy - a.dy;
});
link.append("title")
.text(function(d) {
return d.source.name + " → " + d.target.name + "\n" + format(d.value);
});
var node = svg.append("g").selectAll(".node")
.data(energy.nodes, function(d) { return d.name; })
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
node.append("rect")
.attr("height", function(d) {
return d.dy;
})
.attr("width", sankey.nodeWidth())
.style("fill", function(d) {
return d.color = color(d.name.replace(/ .*/, ""));
})
.style("stroke", function(d) {
return d3.rgb(d.color).darker(1.8);
})
.append("title")
.text(function(d) {
return d.name + "\n" + format(d.value);
});
node.append("text")
.attr("x", -6)
.attr("y", function(d) {
return d.dy / 2;
})
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.style("fill", function(d) {
return d3.rgb(d.color).darker(2.4);
})
.text(function(d) {
return d.name;
})
.style("font-size", function(d) {
return Math.floor(fontScale(d.value)) + "px";
})
.filter(function(d) {
return d.x < width / 2;
})
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start");
function update(nodeData, linkData) {
sankey
.nodes(nodeData)
.links(linkData)
.layout(32);
sankey.relayout();
fontScale.domain(d3.extent(nodeData, function(d) { return d.value }));
svg.selectAll(".link")
.data(linkData, function(d) { return d.id; })
.sort(function(a, b) {
return b.dy - a.dy;
})
.transition()
.duration(1300)
.attr("d", path)
.style("stroke-width", function(d) {
return Math.max(1, d.dy) + "px";
});
svg.selectAll(".node")
.data(nodeData, function(d) { return d.name; })
.transition()
.duration(1300)
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
svg.selectAll(".node rect")
.transition()
.duration(1300)
.attr("height", function(d) {
return d.dy;
});
svg.selectAll(".node text")
.transition()
.duration(1300)
.attr("y", function(d) {
return d.dy / 2;
})
.style("font-size", function(d) {
return Math.floor(fontScale(d.value)) + "px";
});
};
var counter = 0;
function toggleTransition() {
counter++;
var activeLinks = counter % 2 ? energy.links : empty_links;
weightText.text(counter % 2 ? "Links weighted by value" : "Links weighted equally");
update(energy.nodes, activeLinks);
setTimeout(toggleTransition, 2400);
};
setTimeout(toggleTransition, 2400);
});
</script>
https://d3js.org/d3.v4.min.js
https://unpkg.com/d3-sankey@0.4.1