gpt4 book ai didi

d3.js - 在 d3.js 中绘制 bezierCurve

转载 作者:行者123 更新时间:2023-12-04 01:33:49 32 4
gpt4 key购买 nike

如何在 d3.js 中使用 bezierCurveTo 方法绘制线条,使线条如下图所示

enter image description here

我刚刚提到了bezier Curve但我对此一无所知。

最佳答案

有很多方法可以做到这一点。可以制作一个 custom curve这实现了这一点。
但是,我们也可以让它更简单。从 d3 布局传递给链接生成器的数据,例如 d3.linkHorizo​​ntal,通常包含源和目标属性,这些属性中的每一个通常都包含 x 和 y 属性。假设这种结构,我们可以创建一个使用这些的函数,并使用贝塞尔曲线创建并返回适当的路径数据:

var linker = function(d) {
var x0 = d.source.x;
var y0 = d.source.y;
var y1 = d.target.y;
var x1 = d.target.x;
var k = 120;

var path = d3.path()
path.moveTo(y0,x0)
path.bezierCurveTo(y1-k,x0,y0,x1,y1-k,x1);
path.lineTo(y1,x1);

return path.toString();
}
以上是非常基本的,它使用 d3.path但是您可以轻松地自己构建 SVG 路径字符串。网上有很多交互式贝塞尔曲线浏览器,因此您可以找出最有效的控制点。由于我使用的树布局是垂直的,我通过反转 x 和 y 将它变成水平的,这就是为什么我的坐标是 [y,x]。我用 k将贝塞尔曲线偏移到左侧整体链接的一小部分:
enter image description here
但是您可以轻松地使用它来将曲线放置在链接的中间:
enter image description here
这是它的实际操作:

var data = { "name": "Parent", "children": [ 
{ "name": "Child A", "children": [ { "name": "Grandchild1"}, {"name":"Grandchild2" } ] },
{ "name": "Child B", }
] };

var width = 400;
var height = 300;

margin = {left: 50, top: 10, right:30, bottom: 10}

var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);

var g = svg.append("g").attr('transform','translate('+ margin.left +','+ margin.right +')');

var root = d3.hierarchy(data);

var tree = d3.tree()
.size([height-margin.top-margin.bottom,width-margin.left-margin.right]);

var linker = function(d) {
var x0 = d.source.x;
var y0 = d.source.y;
var y1 = d.target.y;
var x1 = d.target.x;
var k = (y1-y0)/2;

var path = d3.path()
path.moveTo(y0,x0)
path.lineTo(y0+k/2,x0)
path.bezierCurveTo(y1-k,x0,y0+k,x1,y1-k/2,x1);
path.lineTo(y1,x1);

return path.toString();
}

var link = g.selectAll(".link")
.data(tree(root).links())
.enter().append("path")
.attr("class", "link")
.attr("d", linker);

var node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); })
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })

node.append("circle")
.attr("r", 2.5);

node.append("text")
.text(function(d) { return d.data.name; })
.attr('y',-10)
.attr('x',-10)
.attr('text-anchor','middle');
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 3px;
}

.link {
fill: none;
stroke: #ccc;
stroke-width: 2px;
}
<script src="https://d3js.org/d3.v4.min.js"></script>

但是,在阅读评论时,我注意到您的问题可能更多地与 dagreD3 相关 - 这使事情发生了很大变化。相对于 D3,Dagre D3 提供了更好的易用性,但牺牲了 D3 的一些灵活性。如果你想为 DagreD3 提供某种类型的曲线,那么你应该使用 d3 曲线或一些自定义曲线(如上面链接的答案)。您可以在足够轻松地添加边缘时指定曲线。
但这并不能解决与图像中来自同一点的边缘问题。我将提供一个基于 d3 的解决方案——它可能会破坏边缘标签的放置、过渡等——所以如果你需要那个功能,它应该被构建一点。我将使用上面的贝塞尔生成器。以下灵感来自 this :

var g = new dagreD3.graphlib.Graph()
.setGraph({rankdir: 'LR'})
.setDefaultEdgeLabel(function() { return {}; });

g.setNode(0, { label: "0"});
g.setNode(1, { label: "1"});
g.setNode(2, { label: "2"});
g.setNode(3, { label: "3"});
g.setNode(4, { label: "4"});

g.setEdge(0, 1);
g.setEdge(0, 2);
g.setEdge(1, 3);
g.setEdge(1, 4);

var render = new dagreD3.render().createEdgePaths(createEdgePaths);


var svg = d3.select("svg"),
svgGroup = svg.append("g"),
zoom = d3.zoom().on("zoom", function() {
svgGroup.attr("transform", d3.event.transform);
});
svg.call(zoom);

render(svgGroup, g);

function createEdgePaths(selection, g, arrows) {
selection.selectAll("g.edgePath")
.data(g.edges())
.enter()
.append("path")
.attr("d", function(e) {
return calcPoints(g,e);
});
}

function calcPoints(g, e) {
var source = g.node(e.v);
var target = g.node(e.w);
var x0 = source.x + source.width/2;
var x1 = target.x - target.width/2;
var y0 = source.y;
var y1 = target.y;
return linker(x0,y0,x1,y1)
}
function linker(x0,y0,x1,y1) {
var dx = x1 -x0;
var k = dx/3;

var path = d3.path()
path.moveTo(x0,y0)
path.bezierCurveTo(x1-k,y0,x0,y1,x1-k,y1);
path.lineTo(x1,y1);

return path.toString();
}
path {
stroke: #333;
stroke-width: 1.5px;
fill: none;
}
rect {
fill: none;
stroke:black;
stroke-width: 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dagre-d3@0.6.1/dist/dagre-d3.min.js"></script>
<svg width="800" height="600"></svg>

关于d3.js - 在 d3.js 中绘制 bezierCurve,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60293272/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com