Sets y-position of selected nodes according to a defined array after sankey.js has calculated their position.
xxxxxxxxxx
<meta charset="utf-8">
<title>SANKEY Experiment</title>
<style>
.node rect {
cursor: move;
fill-opacity: .9;
shape-rendering: crispEdges;
}
.node text {
pointer-events: none;
text-shadow: 0 1px 0 #fff;
}
.link {
fill: none;
stroke: #000;
stroke-opacity: .2;
}
.link:hover {
stroke-opacity: .5;
}
</style>
<body>
<p id="chart">
<script src="https://d3js.org/d3.v3.js"></script>
<script src="sankey.js"></script>
<script>
var units = "Mt CO2";
var margin = {top: 10, right: 10, bottom: 10, left: 10},
width = 1200 - margin.left - margin.right,
height = 740 - margin.top - margin.bottom;
var formatNumber = d3.format(",.0f"), // zero decimal places
format = function(d) { return formatNumber(d) + " " + units; },
color = d3.scale.category20();
// append the svg canvas to the page
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 + ")");
// Set the sankey diagram properties
var sankey = d3.sankey()
.nodeWidth(36)
.nodePadding(10)
.size([width, height]);
var path = sankey.link();
// load the data
d3.json("emissions.json", function(error, graph) {
var nodeMap = {};
graph.nodes.forEach(function(x) { nodeMap[x.name] = x; });
graph.links = graph.links.map(function(x) {
return {
source: nodeMap[x.source],
target: nodeMap[x.target],
value: x.value
};
});
sankey
.nodes(graph.nodes)
.links(graph.links)
.layout(32);
// add in the links
var link = svg.append("g").selectAll(".link")
.data(graph.links)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke-width", function(d) { return Math.max(1, d.dy); })
.sort(function(a, b) { return b.dy - a.dy; });
// add the link titles
link.append("title")
.text(function(d) {
return d.source.name + " → " +
d.target.name + "\n" + format(d.value); });
// add in the nodes
var node = svg.append("g").selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
//.call(d3.behavior.drag()
// .origin(function(d) { return d; })
// .on("dragstart", function() {
// this.parentNode.appendChild(this); })
// .on("drag", dragmove))
.call(function () {
manualLayout();
});
// add the rectangles for the nodes
node.append("rect")
.attr("height", function(d) { return d.dy; })
.attr("width", sankey.nodeWidth())
.style("fill", function(d) {
if (d.name == "Europe" || d.name == "Spain" || d.name == "Ukraine" || d.name == "Poland"
|| d.name == "France" || d.name == "Italy" || d.name == "United Kingdom" || d.name == "Germany"
|| d.name == "Russian Federation" || d.name == "Netherlands" || d.name == "Czech Republic") return "#FF8A4D"
else if (d.name == "North America" || d.name == "United States" || d.name == "Canada"
|| d.name == "Mexico" ) return "#BAFFC9"
else if (d.name == "Asia" || d.name == "China" || d.name == "India" || d.name == "Japan"
|| d.name == "South Korea" || d.name == "Indonesia" || d.name == "Thailand"
|| d.name == "Kazakhstan" || d.name == "Taiwan" || d.name == "Malaysia"
|| d.name == "Vietnam" || d.name == "Pakistan" || d.name == "Uzbekistan" ) return "#FFFEBB"
else if (d.name == "Middle East" || d.name == "Saudi Arabia" || d.name == "UAE"
|| d.name == "Turkey" || d.name == "Iran" || d.name == "Kuwait"
|| d.name == "Iraq" ) return "#F0CF28"
else if (d.name == "Africa" || d.name == "South Africa" || d.name == "Egypt"
|| d.name == "Algeria" ) return "#592062"
else if (d.name == "Latin Am - Carribean" || d.name == "Brazil" || d.name == "Venezuela"
|| d.name == "Argentina") return "#FFB4BB"
else if (d.name == "Oceania" || d.name == "Australia") return "#61E3F1"
else if (d.name == "Coal") return "#3B3131"
else if (d.name == "Oil") return "#886666"
else if (d.name == "Gas Flaring") return "#AEC7E8"
else if (d.name == "Cement") return "#666688"
else if (d.name == "Gas") return "#AEC7E8"
else return d.color = color(d.name.replace(/ .*/, "")); })
.style("stroke", function(d) {
return d3.rgb(d.color).darker(2); })
.append("title")
.text(function(d) {
return d.name + "\n" + format(d.value);
});
// add in the title for the nodes
node.append("text")
.attr("x", -6)
.attr("y", function(d) { return d.dy / 2; })
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function(d) { return d.name; })
.filter(function(d) { return d.x < width / 2; })
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start");
// the function for moving the nodes
function dragmove(d) {
d3.select(this).attr("transform",
"translate(" + (
d.x = Math.max(0, Math.min(width - d.dx, d3.event.x))
) + "," + (
d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))
) + ")");
sankey.relayout();
link.attr("d", path);
}
// manually customize node position
function manualLayout() {
//https://stackoverflow.com/questions/10337640/how-to-access-the-dom-element-that-correlates-to-a-d3-svg-object
//displacements in order of foo nodes (foo[0][j])
var displacements = [56,299,485,647,766, 55, 746, 307, 490, 612, 677, 429];
var foo = d3.selectAll("g.node");
for (j=0; j < displacements.length; j++) {
pickNode = foo[0][j]; //equals "this" in d3.behavior.drag()...on("dragstart")
d = graph.nodes[j];
d3.select(pickNode).attr("transform",
"translate(" + (
d.x = d.x
) + "," + (
d.y = displacements[j] //Math.max(0, Math.min(height - d.dy, d3.event.y))
) + ")");
}
sankey.relayout();
link.attr("d", path);
}
});
</script>
</body>
</html>
Modified http://d3js.org/d3.v3.js to a secure url
https://d3js.org/d3.v3.js