【发布时间】:2021-03-16 22:38:58
【问题描述】:
我正在尝试通过两个节点之间的连接来实现基本的 d3 网络,并且我希望连接在目标节点的边缘结束(因此结束标记正确定位)而不是中心它。我使用来自Svg draw connection line between two rectangles 的getIntersection()。
在 Y 轴上,链接的终点似乎具有正确的值,但在 X 轴上,当 I 远离原点时,会出现偏移。
下面是失败的代码:
graph = {
"nodes": [{id: 0},{id: 1}],
"links": [{source: 0,target: 1}]
}
const width = 800, height = 600
const nodeWidth = 80, nodeHeight = 20
const arrowDepth = 10
var svg = d3.select("#svg-body").append("svg").attr("viewBox", [0, 0, width, height])
svg.append("svg:defs").selectAll("marker")
.data(["end"])
.enter().append("svg:marker")
.attr("id", String)
.attr("viewBox", `0 -5 ${arrowDepth} ${arrowDepth}`)
.attr("refX", 0)
.attr("refY", -0.5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("svg:polyline")
.attr("points", `0,-5 ${arrowDepth},0 0,5`)
;
let link = svg
.selectAll(".link")
.data(graph.links)
.join("line")
.classed("link", true)
.attr("marker-end", "url(#end)")
const node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.classed("node", true)
.on("click", click)
.call(
d3.drag()
.on("start", dragstart)
.on("drag", dragged)
)
node.append("rect")
.attr("height", nodeHeight)
.attr("width", nodeWidth);
const simulation = d3
.forceSimulation()
.nodes(graph.nodes)
.force("charge_force",
d3.forceManyBody().strength(-100))
.force("center_force",
d3.forceCenter(width / 2, height / 2))
.force("links",
d3.forceLink(graph.links)
.distance(80)
)
.on("tick", tick)
.tick(100)
function getIntersection(dx, dy, cx, cy, w, h) {
// Hit vertical edge of box1
if (Math.abs(dy / dx) < h / w) {
return [cx + (dx > 0 ? w : -w), cy + dy * w / Math.abs(dx)];
} else {
// Hit horizontal edge of box1
return [cx + dx * h / Math.abs(dy), cy + (dy > 0 ? h : -h)];
}
};
function tick() {
link
.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => getIntersection(
d.source.x-d.target.x,
d.source.y-d.target.y,
d.target.x,
d.target.y,
nodeWidth,
nodeHeight
)[0])
.attr("y2", d => getIntersection(
d.source.x-d.target.x,
d.source.y-d.target.y,
d.target.x,
d.target.y,
nodeWidth,
nodeHeight
)[1]);
node.attr("transform", function(d) { return `translate(${d.x - nodeWidth/2}, ${d.y - nodeHeight/2})`; });
}
function click(event, d) {
delete d.fx;
delete d.fy;
d3.select(this).classed("fixed", false);
simulation.alpha(1).restart()
}
function clamp(x, lo, hi) {
return x < lo ? lo : x > hi ? hi : x;
}
function dragstart() {
d3.select(this).classed("fixed", true);
}
function dragged(event, d) {
d.fx = clamp(event.x, 0, width);
d.fy = clamp(event.y, 0, height);
simulation.alpha(1).restart()
}
.link {
stroke: #000;
stroke-width: 1.5px;
}
.node {
cursor: move;
fill: #ccc;
stroke: #000;
stroke-width: 1.5px;
}
.node.fixed {
fill: #f00;
}
<script src="http://d3js.org/d3.v6.min.js"></script>
<div id="svg-body"></div>
【问题讨论】:
标签: javascript svg d3.js graph