我正在向图表添加注释,并绘制从标签到其标记的圆中心的曲线路径。路径是从确定的原点(源)到目标点(圆心)绘制的。我通过返回路径字符串来做到这一点。我不想使用圆弧,因为出于美观原因,根据其源相对于圆的位置来控制线的曲线很重要。
我使用以下命令返回路径字符串。这给了我图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。任何帮助表示赞赏。
最佳答案
最常用的数学解决方案,例如 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/