I'm coding an horizontal hierarchical tree power bi custom visual using typescript and D3, using d3's treeLayout, and I need to write a link generator that can plot bezier, step AND diagonal links, at user's will.
The catch (for me) is: since the nodes are rects with certain width, the links should go from (source.x + width/2, y) to (target.x - width/2, y). I manage to do it with the diagonal and step options, using d3.line() function (which returns a path string) , but have stumbled upon the bezier option, and the linkHorizontal function (which returns a link() function). I have read the entire documentation and even the d3 code itself but so far haven't managed to use its source, target and context functions to achieve what I need.
Here's my code so far, simplified:
- this.settings.links.style holds the user's link option "bezier", "curve" or "step"
- this.settings.nodes.width holds the width of the node
- this.orientation.x maps x and y functions as seen in Bostock's https://bl.ocks.org/mbostock/3184089 (the original code also considers other orientations)
const linkH = d3.linkHorizontal().x(d => this.orientation.x(d)).y(d => this.orientation.y(d));
let linkGenerator = this.settings.links.style == "bezier" ? linkH
:
(this.settings.links.style == "step" ?
d => d3.line().curve(d3.curveStep)([[this.orientation.x(d.source) + this.settings.nodes.width / 2, this.orientation.y(d.source)],
[this.orientation.x(d.target) - this.settings.nodes.width / 2, this.orientation.y(d.target)]])
:
d => d3.line()([[this.orientation.x(d.source) + this.settings.nodes.width / 2, this.orientation.y(d.source)],
[this.orientation.x(d.target) - this.settings.nodes.width, this.orientation.y(d.target)]])
)
var links = linkGroup.selectAll("path")
.data(this.viewModel.hierarchy.links())
.enter()
.append("path")
.attr("d", linkGenerator);