使用x1,y1和x2,y2时如何使用d3.line().curve?
How to use d3.line().curve when using x1, y1, and x2, y2?
我是 d3 的新手,想使用弯头连接节点。在线搜索后,我找到了一种与所需解决方案类似的解决方案 ,但该解决方案不适用于 d3 v4+。
此外,我从 d3 中找到了一个可行的方法,名为 d3.line().curve(d3.curveStepAfter) (我不确定这是否是正确的用法)可以看到一个例子here。但是我找不到一种方法来为我当前使用 x1、y1 和 x2、y2 的设置实现它。
数据
var data = {
"nodes": [
{
"name": "Node 1",
fx: 50,
fy: 50
},
{
"name": "Node 2",
fx: 50,
fy: 100
},
{
"name": "Node 3",
fx: 200,
fy: 50
},
{
"name": "Node 4",
fx: 350,
fy: 50
},
{
"name": "Node 5",
fx: 200,
fy: 150
}].map(function(d, i) { return (d.fixed = true, d) }),
"links": [
{
"source": 0,
"target": 2
},
{
"source": 1,
"target": 2
},
{
"source": 2,
"target": 3
},
{
"source": 2,
"target": 4
}]
}
代码
var width = 560
var height = 500;
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var force = self.force = d3.forceSimulation(data.nodes)
.force("link", d3.forceLink(data.links))
.force("collide", d3.forceCollide())
.force("center", d3.forceCenter(width / 2, height / 2))
.on("tick", ticked);
var link = svg.selectAll("line.link")
.data(data.links)
.enter()
.append("line")
.style("stroke", "black")
.attr("x1", function (d) { return d.source.x; })
.attr("y1", function (d) { return d.source.y; })
.attr("x2", function (d) { return d.target.x; })
.attr("y2", function (d) { return d.target.y; })
var node = svg.selectAll("g.node")
.data(data.nodes)
.enter()
.append("g")
.attr("class", "node")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
d3.selectAll(".node")
.append("circle")
.style("fill", "red")
.attr("r", 15);
function ticked() {
link
.attr("x1", function (d) { return d.source.x; })
.attr("y1", function (d) { return d.source.y; })
.attr("x2", function (d) { return d.target.x; })
.attr("y2", function (d) { return d.target.y; })
node.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
};
function dragstarted(event) {
if (!event.active) force.alphaTarget(0.3).restart();
event.subject.fx = event.subject.x;
event.subject.fy = event.subject.y;
}
function dragged(event) {
event.subject.fx = Math.ceil(event.x/5)*5;
event.subject.fy = Math.ceil(event.y/5)*5;
}
function dragended(event) {
if (!event.active) force.alphaTarget(0);
}
代码呈现节点并用直线连接它们,目标是添加 curveStepAfter 以创建弯头连接,因为它看起来更适合我需要的图表类型。
感谢任何帮助。
这是一个完整的例子。
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<script>
const data = {
nodes: [
{ name: "Node 1", x: 50, y: 50 },
{ name: "Node 2", x: 50, y: 100 },
{ name: "Node 3", x: 200, y: 50 },
{ name: "Node 4", x: 350, y: 50 },
{ name: "Node 5", x: 200, y: 150 },
],
links: [
{ source: 0, target: 2 },
{ source: 1, target: 2 },
{ source: 2, target: 3 },
{ source: 2, target: 4 },
],
};
const segments = data.links.map(({ source, target }) => [
data.nodes[source],
data.nodes[target],
]);
const width = 560
const height = 500;
const svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
const line = d3.line()
.x(d => d.x)
.y(d => d.y)
.curve(d3.curveStep);
const link = svg.selectAll("path.link")
.data(segments)
.join("path")
.attr("d", line)
.attr("stroke", "black")
.attr("fill", "none")
const node = svg.selectAll("g.node")
.data(data.nodes)
.join("g")
.attr("class", "node")
.attr("transform", d => `translate(${d.x},${d.y})`)
.call(d3.drag()
.on("drag", dragged));
node.append("circle")
.style("fill", "red")
.attr("r", 15);
function dragged(event, d) {
d.x = Math.ceil(event.x / 5) * 5;
d.y = Math.ceil(event.y / 5) * 5;
link.attr("d", line);
d3.select(this)
.attr("transform", `translate(${d.x},${d.y})`)
}
</script>
</body>
</html>
主要思想是
const segments = data.links.map(({ source, target }) => [
data.nodes[source],
data.nodes[target],
]);
是网络中的线段数组。我们可以将每个段传递给一个 d3.line()
来为该段创建一个 <path>
。我还删除了对 d3-force
的依赖,这不是必需的。
我是 d3 的新手,想使用弯头连接节点。在线搜索后,我找到了一种与所需解决方案类似的解决方案
此外,我从 d3 中找到了一个可行的方法,名为 d3.line().curve(d3.curveStepAfter) (我不确定这是否是正确的用法)可以看到一个例子here。但是我找不到一种方法来为我当前使用 x1、y1 和 x2、y2 的设置实现它。
数据
var data = {
"nodes": [
{
"name": "Node 1",
fx: 50,
fy: 50
},
{
"name": "Node 2",
fx: 50,
fy: 100
},
{
"name": "Node 3",
fx: 200,
fy: 50
},
{
"name": "Node 4",
fx: 350,
fy: 50
},
{
"name": "Node 5",
fx: 200,
fy: 150
}].map(function(d, i) { return (d.fixed = true, d) }),
"links": [
{
"source": 0,
"target": 2
},
{
"source": 1,
"target": 2
},
{
"source": 2,
"target": 3
},
{
"source": 2,
"target": 4
}]
}
代码
var width = 560
var height = 500;
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var force = self.force = d3.forceSimulation(data.nodes)
.force("link", d3.forceLink(data.links))
.force("collide", d3.forceCollide())
.force("center", d3.forceCenter(width / 2, height / 2))
.on("tick", ticked);
var link = svg.selectAll("line.link")
.data(data.links)
.enter()
.append("line")
.style("stroke", "black")
.attr("x1", function (d) { return d.source.x; })
.attr("y1", function (d) { return d.source.y; })
.attr("x2", function (d) { return d.target.x; })
.attr("y2", function (d) { return d.target.y; })
var node = svg.selectAll("g.node")
.data(data.nodes)
.enter()
.append("g")
.attr("class", "node")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
d3.selectAll(".node")
.append("circle")
.style("fill", "red")
.attr("r", 15);
function ticked() {
link
.attr("x1", function (d) { return d.source.x; })
.attr("y1", function (d) { return d.source.y; })
.attr("x2", function (d) { return d.target.x; })
.attr("y2", function (d) { return d.target.y; })
node.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
};
function dragstarted(event) {
if (!event.active) force.alphaTarget(0.3).restart();
event.subject.fx = event.subject.x;
event.subject.fy = event.subject.y;
}
function dragged(event) {
event.subject.fx = Math.ceil(event.x/5)*5;
event.subject.fy = Math.ceil(event.y/5)*5;
}
function dragended(event) {
if (!event.active) force.alphaTarget(0);
}
代码呈现节点并用直线连接它们,目标是添加 curveStepAfter 以创建弯头连接,因为它看起来更适合我需要的图表类型。
感谢任何帮助。
这是一个完整的例子。
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<script>
const data = {
nodes: [
{ name: "Node 1", x: 50, y: 50 },
{ name: "Node 2", x: 50, y: 100 },
{ name: "Node 3", x: 200, y: 50 },
{ name: "Node 4", x: 350, y: 50 },
{ name: "Node 5", x: 200, y: 150 },
],
links: [
{ source: 0, target: 2 },
{ source: 1, target: 2 },
{ source: 2, target: 3 },
{ source: 2, target: 4 },
],
};
const segments = data.links.map(({ source, target }) => [
data.nodes[source],
data.nodes[target],
]);
const width = 560
const height = 500;
const svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
const line = d3.line()
.x(d => d.x)
.y(d => d.y)
.curve(d3.curveStep);
const link = svg.selectAll("path.link")
.data(segments)
.join("path")
.attr("d", line)
.attr("stroke", "black")
.attr("fill", "none")
const node = svg.selectAll("g.node")
.data(data.nodes)
.join("g")
.attr("class", "node")
.attr("transform", d => `translate(${d.x},${d.y})`)
.call(d3.drag()
.on("drag", dragged));
node.append("circle")
.style("fill", "red")
.attr("r", 15);
function dragged(event, d) {
d.x = Math.ceil(event.x / 5) * 5;
d.y = Math.ceil(event.y / 5) * 5;
link.attr("d", line);
d3.select(this)
.attr("transform", `translate(${d.x},${d.y})`)
}
</script>
</body>
</html>
主要思想是
const segments = data.links.map(({ source, target }) => [
data.nodes[source],
data.nodes[target],
]);
是网络中的线段数组。我们可以将每个段传递给一个 d3.line()
来为该段创建一个 <path>
。我还删除了对 d3-force
的依赖,这不是必需的。