如何使用 CSS 定位节点 Force Directed Graph D3?
How to position nodes Force Directed Graph D3 with CSS?
我正在用 D3 制作一个力定向图,并让它与节点的 svg 圆一起工作。但是,当我将 div 与 CSS left 和 top 属性结合使用时,节点就错位了。我不知道我在这里做错了什么。我使用强制 D3 生成的 x 和 y 坐标作为 left 和 top 属性,但也许这不是正确的方法?
这是我的 JS:
var url = "https://raw.githubusercontent.com/DealPete/forceDirected/master/countries.json";
d3.json(url, function(json){
var data = json;
var margin = {top: 40, right: 40, bottom: 40, left: 40};
var w = 1000 - margin.left - margin.right;
var h = 1000 - margin.top - margin.bottom;
var svg = d3.select("#chart")
.append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var nodes = data.nodes;
var links = data.links;
//Create a force layout object and define its properties
var force = d3.layout.force()
.size([w,h])
.nodes(nodes)
.links(links);
force.linkDistance(h/20);
force.charge(-120)
var link = svg.selectAll(".link")
.data(links)
.enter()
.append("line")
.attr("class", "link");
var node = d3.select("#chart").selectAll(".node")
.data(nodes)
.enter()
.append("div")
force.on("end", function(){
//set node and link position attributes once force calculations have finished
//position the nodes
node.style("left", function(d){
return d.x + "px";
})
.style("top", function(d){
return d.y + "px";
})
.attr("class", function(d){
return "flag flag-" + d.code + " node";
})
.attr("src", "https://res.cloudinary.com/dettjqo9j/image/upload/v1485942660/flags_xf9dde.png");
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;
})
})//force.on
force.start();
//let the force start its calculations
})
我的css:
svg {
background-color: white;
box-shadow: 0 0 10px #888888;
}
.link {
stroke: #2c3e50;
stroke-width: 2px;
}
.flag {
display: inline-block;
position:absolute;
width: 16px;
height: 11px;
background: url('https://res.cloudinary.com/dettjqo9j/image/upload/v1485942660/flags_xf9dde.png') no-repeat;
}
.flag.flag-ml {
background-position: -224px -88px;
}
到目前为止在 codepen 上的图表:
考虑 SVG 中的链接与 window 的偏移量:它们向上移动了 margin.left
,向下移动了 margin.top
,并且还向下移动了高度<h1>
和 <h2>
(加上填充)。
例如,在我的浏览器中,使用以下代码可以正确定位标志:
node.style("left", function(d){
return d.x + margin.left + 150 + "px";
})
.style("top", function(d){
return d.y + margin.top + "px";
})
请注意,这是因为 <div>
标志元素的默认 left
和 top
属性为 0,即使它们的 parent 是 <div#chart>
.我有 hard-coded 150,但您也可以设计一种动态计算方法。
你使用 <circle>
而不是 <div>
的原因是圆是 SVG 元素和 <svg>
的 children,所以它们已经在正确的位置起始位置。可能有另一种解决方案,您可以将标志保留在 SVG 中:将节点添加为 <g>
或 <rect>
而不是 <div>
,x
和 y
的属性代替 left
和 top
,<svg>
的 children 代替 <div#chart>
。但是,我还没有探索如何实现将标志分配给每个节点,因为您没有为每个标志文件指向不同的 URL。
谢谢大家,
我最终使用 Element.getBoundingClientRect() 获得了图表的 SVG g 元素的位置,并使用它的左上角位置来定位所有节点。
//Get position of g element of the chart
var position = document.getElementById("area").getBoundingClientRect();
force.on("tick", function(){
node.style("left", function(d){
return d.x + position.left + "px";
})
.style("top", function(d){
return d.y + position.top + "px";
})
.attr("class", function(d){
return "flag flag-" + d.code + " node";
})
.attr("src", "https://res.cloudinary.com/dettjqo9j/image/upload/v1485942660/flags_xf9dde.png")
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;
})
})
我正在用 D3 制作一个力定向图,并让它与节点的 svg 圆一起工作。但是,当我将 div 与 CSS left 和 top 属性结合使用时,节点就错位了。我不知道我在这里做错了什么。我使用强制 D3 生成的 x 和 y 坐标作为 left 和 top 属性,但也许这不是正确的方法?
这是我的 JS:
var url = "https://raw.githubusercontent.com/DealPete/forceDirected/master/countries.json";
d3.json(url, function(json){
var data = json;
var margin = {top: 40, right: 40, bottom: 40, left: 40};
var w = 1000 - margin.left - margin.right;
var h = 1000 - margin.top - margin.bottom;
var svg = d3.select("#chart")
.append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var nodes = data.nodes;
var links = data.links;
//Create a force layout object and define its properties
var force = d3.layout.force()
.size([w,h])
.nodes(nodes)
.links(links);
force.linkDistance(h/20);
force.charge(-120)
var link = svg.selectAll(".link")
.data(links)
.enter()
.append("line")
.attr("class", "link");
var node = d3.select("#chart").selectAll(".node")
.data(nodes)
.enter()
.append("div")
force.on("end", function(){
//set node and link position attributes once force calculations have finished
//position the nodes
node.style("left", function(d){
return d.x + "px";
})
.style("top", function(d){
return d.y + "px";
})
.attr("class", function(d){
return "flag flag-" + d.code + " node";
})
.attr("src", "https://res.cloudinary.com/dettjqo9j/image/upload/v1485942660/flags_xf9dde.png");
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;
})
})//force.on
force.start();
//let the force start its calculations
})
我的css:
svg {
background-color: white;
box-shadow: 0 0 10px #888888;
}
.link {
stroke: #2c3e50;
stroke-width: 2px;
}
.flag {
display: inline-block;
position:absolute;
width: 16px;
height: 11px;
background: url('https://res.cloudinary.com/dettjqo9j/image/upload/v1485942660/flags_xf9dde.png') no-repeat;
}
.flag.flag-ml {
background-position: -224px -88px;
}
到目前为止在 codepen 上的图表:
考虑 SVG 中的链接与 window 的偏移量:它们向上移动了 margin.left
,向下移动了 margin.top
,并且还向下移动了高度<h1>
和 <h2>
(加上填充)。
例如,在我的浏览器中,使用以下代码可以正确定位标志:
node.style("left", function(d){
return d.x + margin.left + 150 + "px";
})
.style("top", function(d){
return d.y + margin.top + "px";
})
请注意,这是因为 <div>
标志元素的默认 left
和 top
属性为 0,即使它们的 parent 是 <div#chart>
.我有 hard-coded 150,但您也可以设计一种动态计算方法。
你使用 <circle>
而不是 <div>
的原因是圆是 SVG 元素和 <svg>
的 children,所以它们已经在正确的位置起始位置。可能有另一种解决方案,您可以将标志保留在 SVG 中:将节点添加为 <g>
或 <rect>
而不是 <div>
,x
和 y
的属性代替 left
和 top
,<svg>
的 children 代替 <div#chart>
。但是,我还没有探索如何实现将标志分配给每个节点,因为您没有为每个标志文件指向不同的 URL。
谢谢大家,
我最终使用 Element.getBoundingClientRect() 获得了图表的 SVG g 元素的位置,并使用它的左上角位置来定位所有节点。
//Get position of g element of the chart
var position = document.getElementById("area").getBoundingClientRect();
force.on("tick", function(){
node.style("left", function(d){
return d.x + position.left + "px";
})
.style("top", function(d){
return d.y + position.top + "px";
})
.attr("class", function(d){
return "flag flag-" + d.code + " node";
})
.attr("src", "https://res.cloudinary.com/dettjqo9j/image/upload/v1485942660/flags_xf9dde.png")
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;
})
})