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>