score:1

Eventually, I came up with this function that solves the goal of using both d3.line() and d3.linkHorizontal(). The key was to use a implementation of d3.DefaultLinkObject so that I could use the original source and target passed by attr("d", f(d)).

So, if it helps anybody:

``````class myLinkObject implements d3.DefaultLinkObject {
public source: [number, number];
public target: [number, number];
constructor(s: [number, number], t: [number, number]) {
this.source = s;
this.target = t;
}
}

function linkGenerator(d) {

var deltaX = self.settings.nodes.width / 2;

var pSource: [number, number] = [self.orientation.x(d.source) + deltaX, self.orientation.y(d.source);
var pTarget: [number, number] = [self.orientation.x(d.target) - deltaX, self.orientation.y(d.target);

var points = [pSource, pTarget];
var linkObject: myLinkObject = new myLinkObject(pSource, pTarget);
var path = "";

if (self.settings.links.style == "step") {

var lineGenerator = d3.line().curve(d3.curveStep);
path = lineGenerator(points);

} else if (self.settings.links.style == "diagonal") {

var lineGenerator = d3.line();
path = lineGenerator(points);

} else {  // bezier

var linkGen = d3.linkHorizontal().x(d => d[0]).y(d => d[1]);
path = linkGen(linkObject);
}

return path;
}
``````

score:2

Here is a simple Bezier curve function to use instead of the D3's:

``````const getBezierPath = (from, to) => {
if (Math.abs(from.x - to.x) > Math.abs(from.y - to.y)) {
const midX = (to.x + from.x) / 2;
return `M \${from.x},\${from.y} C \${midX},\${from.y} \${midX},\${to.y} \${to.x},\${to.y}`;
} else {
const midY = (to.y + from.y) / 2;
return `M \${from.x},\${from.y} C \${from.x},\${midY} \${to.x},\${midY} \${to.x},\${to.y}`;
}
};
``````

See a demo in a fiddle