in app/assets/javascripts/sankey.js [111:216]
sankey.reversibleLink = function() {
var curvature = .5;
// Used when source is behind target, the first and last paths are simple
// lines at the start and end node while the second path is the spline
function forwardLink(part, d) {
var x0 = d.source.x + d.source.dx,
x1 = d.target.x,
xi = d3.interpolateNumber(x0, x1),
x2 = xi(curvature),
x3 = xi(1 - curvature),
y0 = d.source.y + d.sy,
y1 = d.target.y + d.ty,
y2 = d.source.y + d.sy + d.dy,
y3 = d.target.y + d.ty + d.dy;
switch (part) {
case 0:
return "M" + x0 + "," + y0 + "L" + x0 + "," + (y0 + d.dy);
case 1:
return "M" + x0 + "," + y0
+ "C" + x2 + "," + y0 + " " + x3 + "," + y1 + " " + x1 + "," + y1
+ "L" + x1 + "," + y3
+ "C" + x3 + "," + y3 + " " + x2 + "," + y2 + " " + x0 + "," + y2
+ "Z";
case 2:
return "M" + x1 + "," + y1 + "L" + x1 + "," + (y1 + d.dy);
}
}
// Used for self loops and when the source is actually in front of the
// target; the first element is a turning path from the source to the
// destination, the second element connects the two twists and the last
// twists into the target element.
//
//
// /--Target
// \----------------------\
// Source--/
//
function backwardLink(part, d) {
var curveExtension = 30;
var curveDepth = 15;
function getDir(d) {
return d.source.y + d.sy > d.target.y + d.ty ? -1 : 1;
}
function p(x, y) {
return x + "," + y + " ";
}
var dt = getDir(d) * curveDepth,
x0 = d.source.x + d.source.dx,
y0 = d.source.y + d.sy,
x1 = d.target.x,
y1 = d.target.y + d.ty;
switch (part) {
case 0:
return "M" + p(x0, y0) +
"C" + p(x0, y0) +
p(x0 + curveExtension, y0) +
p(x0 + curveExtension, y0 + dt) +
"L" + p(x0 + curveExtension, y0 + dt + d.dy) +
"C" + p(x0 + curveExtension, y0 + d.dy) +
p(x0, y0 + d.dy) +
p(x0, y0 + d.dy) +
"Z";
case 1:
return "M" + p(x0 + curveExtension, y0 + dt) +
"C" + p(x0 + curveExtension, y0 + 3 * dt) +
p(x1 - curveExtension, y1 - 3 * dt) +
p(x1 - curveExtension, y1 - dt) +
"L" + p(x1 - curveExtension, y1 - dt + d.dy) +
"C" + p(x1 - curveExtension, y1 - 3 * dt + d.dy) +
p(x0 + curveExtension, y0 + 3 * dt + d.dy) +
p(x0 + curveExtension, y0 + dt + d.dy) +
"Z";
case 2:
return "M" + p(x1 - curveExtension, y1 - dt) +
"C" + p(x1 - curveExtension, y1) +
p(x1, y1) +
p(x1, y1) +
"L" + p(x1, y1 + d.dy) +
"C" + p(x1, y1 + d.dy) +
p(x1 - curveExtension, y1 + d.dy) +
p(x1 - curveExtension, y1 + d.dy - dt) +
"Z";
}
}
return function(part) {
return function(d) {
if (d.source.x < d.target.x) {
return forwardLink(part, d);
} else {
return backwardLink(part, d);
}
}
}
};