我正在向图表添加注释,并绘制从标签到其所标记的圆心的弯曲路径。从确定的原点(源)到目标点(圆心)绘制路径。我通过返回路径字符串来做到这一点。出于审美原因,我不想使用弧线作为控制线的曲线的重要依据,它取决于线源相对于圆的位置。
我使用以下命令返回路径字符串。这给了我图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,因为我掌握了图中的信息。任何帮助表示赞赏。
答案 0 :(得分:2)
最常用的数学解决方案,例如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>
我们可以将stroke-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:值得一提的是,我在这里(错误地)假设该路径在圆内的部分的长度等于圆的半径。事实并非如此:如果两点距离不太近,则图表上的差异在视觉上可以忽略不计,但是在数学上定义得很好。但是,如果原点靠近圆的边界,则差异会很明显。在这种情况下,请使用指示的库。