admin管理员组

文章数量:1405297

I need to manually draw some links between points on a circle and points clustered in the centre of said circle. I have the x,y pairs for the source and target points, but I don't want a simple straight line between them; I want a curved line (similar to the links that are found in tree diagrams). I could use linkHorizontal or linkVertical but their tangents are constant; I want to use linkRadial and have the tangent be the radial line at that particular arc point (the degree of which I also have).

I don't understand the linkRadial API though; it wants an angle and a radius, not an x or y point. How do I convert my two x,y pairs (and the radial line angle) into the angle and radius this is expecting?

I need to manually draw some links between points on a circle and points clustered in the centre of said circle. I have the x,y pairs for the source and target points, but I don't want a simple straight line between them; I want a curved line (similar to the links that are found in tree diagrams). I could use linkHorizontal or linkVertical but their tangents are constant; I want to use linkRadial and have the tangent be the radial line at that particular arc point (the degree of which I also have).

I don't understand the linkRadial API though; it wants an angle and a radius, not an x or y point. How do I convert my two x,y pairs (and the radial line angle) into the angle and radius this is expecting?

Share Improve this question edited Oct 20, 2020 at 9:28 Gerardo Furtado 102k9 gold badges128 silver badges177 bronze badges asked Jul 6, 2017 at 21:03 IronWaffleManIronWaffleMan 2,7125 gold badges33 silver badges67 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 6

Since you have a data array with the x and y positions ("I have the x,y pairs for the source and target points"), you'll have to convert them to angle and radius. Let's see how to do it.

Firstly, let's see an example with fixed coordinates. For instance, suppose you have this data array, with the x and y positions:

var data = [{
    source: {y: 150,x: 75
    },
    target: {y: 300,x: 0
    }
}, {
    source: {y: 150,x: 75
    },
    target: {y: 0,x: 0
    }
}, {
    source: {y: 150,x: 75
    },
    target: {y: 150,x: 150
    }
}, ];

Using this link generator...

var link = d3.linkHorizontal()
    .x(function(d) {
        return d.y;
    })
    .y(function(d) {
        return d.x;
    });

... you'll have a chart like this:

var data = [{
  source: {
    y: 150,
    x: 75
  },
  target: {
    y: 300,
    x: 0
  }
}, {
  source: {
    y: 150,
    x: 75
  },
  target: {
    y: 0,
    x: 0
  }
}, {
  source: {
    y: 150,
    x: 75
  },
  target: {
    y: 150,
    x: 150
  }
}, ];

var svg = d3.select("svg");

var link = d3.linkHorizontal()
  .x(function(d) {
    return d.y;
  })
  .y(function(d) {
    return d.x;
  });

svg.selectAll(null)
  .data(data)
  .enter()
  .append("path")
  .attr("fill", "none")
  .attr("stroke", "blue")
  .attr("d", link);
<script src="https://d3js/d3.v4.js"></script>
<svg></svg>

How can we convert this to a data set that can be used with d3.linkRadial()?

One option is iterating with each object, using basic trigonometry to populate the angle and radius properties:

var radialData = data.map(function(d) {
    return {
        source: {
            x: 0,
            y: 0
        },
        target: {
            x: Math.atan2(d.target.y - d.source.y, d.target.x - d.source.x) - Math.PI,
            y: Math.sqrt((d.target.x - d.source.x) * (d.target.x - d.source.x) + (d.target.y - d.source.y) * (d.target.y - d.source.y))
        }
    };
});

Then, using this link generator:

var linkRadial = d3.linkRadial()
    .angle(function(d) {
        console.log(d)
        return d.x;
    })
    .radius(function(d) {
        return d.y;
    });

We'll have this:

var data = [{
  source: {
    y: 150,
    x: 75
  },
  target: {
    y: 300,
    x: 0
  }
}, {
  source: {
    y: 150,
    x: 75
  },
  target: {
    y: 0,
    x: 0
  }
}, {
  source: {
    y: 150,
    x: 75
  },
  target: {
    y: 150,
    x: 150
  }
}, ];

var svg = d3.select("svg");

var radialData = data.map(function(d) {
  return {
    source: {
      x: 0,
      y: 0
    },
    target: {
      x: Math.atan2(d.target.y - d.source.y, d.target.x - d.source.x) - Math.PI,
      y: Math.sqrt((d.target.x - d.source.x) * (d.target.x - d.source.x) + (d.target.y - d.source.y) * (d.target.y - d.source.y))
    }
  };
});

var g = svg.append("g")
  .attr("transform", "translate(150,75)")

var linkRadial = d3.linkRadial()
  .angle(function(d) {
    return d.x;
  })
  .radius(function(d) {
    return d.y;
  });

g.selectAll(null)
  .data(radialData)
  .enter()
  .append("path")
  .attr("fill", "none")
  .attr("stroke", "red")
  .attr("d", linkRadial);
<script src="https://d3js/d3.v4.js"></script>
<svg></svg>

Now both generators together, for parison:

var data = [{
  source: {
    y: 150,
    x: 75
  },
  target: {
    y: 300,
    x: 0
  }
}, {
  source: {
    y: 150,
    x: 75
  },
  target: {
    y: 0,
    x: 0
  }
}, {
  source: {
    y: 150,
    x: 75
  },
  target: {
    y: 150,
    x: 150
  }
}, ];

var svg = d3.select("svg");

var link = d3.linkHorizontal()
  .x(function(d) {
    return d.y;
  })
  .y(function(d) {
    return d.x;
  });

svg.selectAll(null)
  .data(data)
  .enter()
  .append("path")
  .attr("fill", "none")
  .attr("stroke", "blue")
  .attr("d", link);

var radialData = data.map(function(d) {
  return {
    source: {
      x: 0,
      y: 0
    },
    target: {
      x: Math.atan2(d.target.y - d.source.y, d.target.x - d.source.x) - Math.PI,
      y: Math.sqrt((d.target.x - d.source.x) * (d.target.x - d.source.x) + (d.target.y - d.source.y) * (d.target.y - d.source.y))
    }
  };
});

var g = svg.append("g")
  .attr("transform", "translate(150,75)")

var linkRadial = d3.linkRadial()
  .angle(function(d) {
    return d.x;
  })
  .radius(function(d) {
    return d.y;
  });

g.selectAll(null)
  .data(radialData)
  .enter()
  .append("path")
  .attr("fill", "none")
  .attr("stroke", "red")
  .attr("d", linkRadial);
<script src="https://d3js/d3.v4.js"></script>
<svg></svg>

本文标签: javascriptHow to use linkRadial to draw a link between two pointsStack Overflow