Typescript 如何使用D3'偏移贝塞尔曲线的源点和目标点;s链接生成器?

Typescript 如何使用D3'偏移贝塞尔曲线的源点和目标点;s链接生成器?,typescript,d3.js,powerbi-custom-visuals,Typescript,D3.js,Powerbi Custom Visuals,我正在使用typescript和D3,使用D3的treeLayout,编写一个水平层次树power双自定义视觉,我需要编写一个链接生成器,可以根据用户的意愿绘制bezier、阶跃和对角链接 对我来说,问题是:由于节点是具有一定宽度的矩形,链接应该从(source.x+width/2,y)到(target.x-width/2,y)。我使用d3.line()函数(返回路径字符串)和linkHorizontal函数(返回link()函数)成功地使用了对角线和步长选项。我已经阅读了整个文档,甚至d3代码

我正在使用typescript和D3,使用D3的treeLayout,编写一个水平层次树power双自定义视觉,我需要编写一个链接生成器,可以根据用户的意愿绘制bezier、阶跃和对角链接

对我来说,问题是:由于节点是具有一定宽度的矩形,链接应该从(source.x+width/2,y)到(target.x-width/2,y)。我使用d3.line()函数(返回路径字符串)和linkHorizontal函数(返回link()函数)成功地使用了对角线和步长选项。我已经阅读了整个文档,甚至d3代码本身,但到目前为止还没有设法使用它的源、目标和上下文函数来实现我所需要的

以下是我迄今为止的代码,简化版:

  • 此.settings.links.style保存用户的链接选项“bezier”、“curve”或“step”
  • this.settings.nodes.width保存节点的宽度
  • 这个.orientation.x映射了在Bostock中看到的x和y函数(原始代码也考虑了其他方向)

下面是一个简单的Bezier曲线函数,用于代替D3:

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}`;
  }
};

最后,我提出了这个函数,它解决了同时使用d3.line()和d3.linkHorizontal()的问题。关键是使用d3.DefaultLinkObject的实现,这样我就可以使用attr传递的原始源和目标(“d”,f(d))

因此,如果它能帮助任何人:

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;
}

谢谢,这很有帮助@EduardoWaghabi请将答案标记为正确
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;
}