javascript - 绘制从原点到圆外半径的路径

标签 javascript d3.js svg annotations

我正在向图表添加注释,并绘制从标签到其标记的圆中心的曲线路径。路径是从确定的原点(源)到目标点(圆心)绘制的。我通过返回路径字符串来做到这一点。我不想使用圆弧,因为出于美观原因,根据其源相对于圆的位置来控制线的曲线很重要。

我使用以下命令返回路径字符串。这给了我图A

newX = sourceX
newY = sourceY
c1x = newX + ((targetX-newX) * 0.8)
c1y = newY - rem
c2x = targetX - ((targetX-newX)* 0.05)
c2y = targetY - ((targetY-newY) * 0.8)
pathString  = "M " + newX + "," + (newY) + " C " + c1x + "," + c1y + " + c2x + "," + c2y + " " + targetX + "," + targetY;};
return pathString

我尝试四处寻找这一点,但这一切似乎都是直线与圆相交,我可以理解。但鉴于我有图表上的信息,我不知道如何实现图 B。任何帮助表示赞赏。

enter image description here

最佳答案

最常用的数学解决方案,例如 this one ,可能不适合您,因为您希望弯曲路径假想地继续前进,直到目标圆的中心。

虽然您可以为此创建更精确的数学(或使用 comments 中建议的库),但一个非常简单的解决方案就是绘制路径而不进行任何更改,然后使用 Stroke-dasharray,删除最后一部分,使路径完全结束于圆的边界(几乎,请参见下面的文章)。

所以,假设这条路径(在这里我使用你的函数,我将其命名为drawPath):

var svg = d3.select("svg");
var sourceX = 50,
  sourceY = 50;
var targetX = 300,
  targetY = 150;
var radius = 50;
svg.append("circle")
  .attr("cx", sourceX)
  .attr("cy", sourceY)
  .attr("r", 4);
svg.append("circle")
  .attr("cx", targetX)
  .attr("cy", targetY)
  .attr("r", 4);
svg.append("circle")
  .attr("cx", targetX)
  .attr("cy", targetY)
  .attr("r", radius)
  .style("fill", "none")
  .style("stroke", "black");
svg.append("path")
  .style("fill", "none")
  .style("stroke", "steelblue")
  .style("stroke-width", "2px")
  .attr("d", drawPath);

function drawPath() {
  newX = sourceX
  newY = sourceY
  c1x = newX + ((targetX - newX) * 0.5)
  c1y = newY - ((targetY - newY) * 0.5)
  c2x = targetX - ((targetX - newX) * 0.05)
  c2y = targetY - ((targetY - newY) * 0.5)
  pathString = "M " + newX + "," + (newY) + " C " + c1x + "," + c1y + "," + c2x + ", " + c2y + " " + targetX + ", " + targetY;
  return pathString
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="300"></svg>

我们可以更改 lines-dasharray删除路径的最后部分,方法如下:

.attr("stroke-dasharray", function() {
    return this.getTotalLength() - radius;
});

这是生成的代码:

var svg = d3.select("svg");
var sourceX = 50,
  sourceY = 50;
var targetX = 300,
  targetY = 150;
var radius = 50;
svg.append("circle")
  .attr("cx", sourceX)
  .attr("cy", sourceY)
  .attr("r", 4);
svg.append("circle")
  .attr("cx", targetX)
  .attr("cy", targetY)
  .attr("r", 4);
svg.append("circle")
  .attr("cx", targetX)
  .attr("cy", targetY)
  .attr("r", radius)
  .style("fill", "none")
  .style("stroke", "black");
svg.append("path")
  .style("fill", "none")
  .style("stroke", "steelblue")
  .style("stroke-width", "2px")
  .attr("d", drawPath)
  .attr("stroke-dasharray", function() {
    return this.getTotalLength() - radius;
  });
svg.append("circle")
  .attr("cx", function(d) {
    var path = d3.select("path").node()
    var point = path.getPointAtLength(path.getTotalLength() - radius);
    return point.x
  })
  .attr("cy", function(d) {
    var path = d3.select("path").node()
    var point = path.getPointAtLength(path.getTotalLength() - radius);
    return point.y
  })
  .attr("r", 4);

function drawPath() {
  newX = sourceX
  newY = sourceY
  c1x = newX + ((targetX - newX) * 0.5)
  c1y = newY - ((targetY - newY) * 0.5)
  c2x = targetX - ((targetX - newX) * 0.05)
  c2y = targetY - ((targetY - newY) * 0.5)
  pathString = "M " + newX + "," + (newY) + " C " + c1x + "," + c1y + "," + c2x + ", " + c2y + " " + targetX + ", " + targetY;
  return pathString
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="300"></svg>

如果我们添加另一个未修改的路径(红色),您可以看到该路径将继续直到圆的中心:

var svg = d3.select("svg");
var sourceX = 50,
  sourceY = 50;
var targetX = 300,
  targetY = 150;
var radius = 50;
svg.append("circle")
  .attr("cx", sourceX)
  .attr("cy", sourceY)
  .attr("r", 4);
svg.append("circle")
  .attr("cx", targetX)
  .attr("cy", targetY)
  .attr("r", 4);
svg.append("circle")
  .attr("cx", targetX)
  .attr("cy", targetY)
  .attr("r", radius)
  .style("fill", "none")
  .style("stroke", "black");
svg.append("path")
  .style("fill", "none")
  .style("stroke", "tomato")
  .style("stroke-width", "2px")
  .style("stroke-dasharray", "2,2")
  .attr("d", drawPath);
svg.append("path")
  .style("fill", "none")
  .style("stroke", "steelblue")
  .style("stroke-width", "2px")
  .attr("d", drawPath)
  .attr("stroke-dasharray", function() {
    return this.getTotalLength() - radius;
  });
svg.append("circle")
  .attr("cx", function(d) {
    var path = d3.select("path").node()
    var point = path.getPointAtLength(path.getTotalLength() - radius);
    return point.x
  })
  .attr("cy", function(d) {
    var path = d3.select("path").node()
    var point = path.getPointAtLength(path.getTotalLength() - radius);
    return point.y
  })
  .attr("r", 4);

function drawPath() {
  newX = sourceX
  newY = sourceY
  c1x = newX + ((targetX - newX) * 0.5)
  c1y = newY - ((targetY - newY) * 0.5)
  c2x = targetX - ((targetX - newX) * 0.05)
  c2y = targetY - ((targetY - newY) * 0.5)
  pathString = "M " + newX + "," + (newY) + " C " + c1x + "," + c1y + "," + c2x + ", " + c2y + " " + targetX + ", " + targetY;
  return pathString
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="300"></svg>

PS:值得一提的是,这里我假设(错误地)该路径在圆内的部分的长度等于圆的半径。事实并非如此:如果两个点不是很接近,则图表中的差异在视觉上可以忽略不计,但在数学上是明确定义的。但是,如果原点靠近圆的边界,则差异将会很明显。在这种情况下,请使用指定的库。

关于javascript - 绘制从原点到圆外半径的路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51476716/

相关文章:

javascript - 在 JavaScript 中创建单值数组

javascript - 使用 webpack 和 gulp 缩小、转译 ES6 代码的外部源映射

javascript - CKEditor:忽略其 config.js

javascript - 如何更新 d3.js 中的绑定(bind)数据?

javascript - Highcharts 列工具提示 - 始终位于顶部 + 适合容器

JavaScript JS 类方法用于更改从另一个方法作为参数发送的属性值

javascript - 基数插值曲线下面积

javascript - 导致 Rect 元素调用鼠标悬停事件的文本元素

javascript - 向下滑动 SVG 元素的简单方法?

javascript - 如何摆脱重叠的 svg 形状的细线