【问题标题】:Force directed graph drawn out of the allocated SVG size强制从分配的 SVG 大小绘制有向图
【发布时间】:2017-08-09 21:59:33
【问题描述】:

我正在尝试创建像 this 这样的力有向图。当我使用示例数据时,它画得很好。但是当我使用自己的数据时,节点似乎是从 svg 大小中提取出来的。 这是我得到的:

这是我的代码:

var nodes = createFDGNodes(stopsByLine);
var links = createFDGLinks(stopsByLine);

var simulation = d3.forceSimulation()
                    .force("link", d3.forceLink()
                        .id(function(d) { return d.id; })
                    )
                    .force("charge", d3.forceManyBody()
                        .distanceMin(function(d) {return 1; })
                    )
                    .force("center", d3.forceCenter(960/2, 500/2));

const circleGroup = d3.select("div.transit-network")
                    .append("svg")
                    .attr("width", 960)
                    .attr("height", 500)
                    .append("g")
                    .attr("class","fdg");

var color = d3.scaleOrdinal(d3.schemeCategory20);

var link = circleGroup.append("g")
            .attr("class", "links")
            .selectAll("line")
            .data(links)
            .enter().append("line")
                .attr("stroke", "black")
                .attr("stroke-width", 1);

var node = circleGroup.append("g")
            .attr("class", "nodes")
            .selectAll("circle")
            .data(nodes)
            .enter().append("circle")
                .attr("r", 5)
                .attr("class", function(d) {return "line-"+d.lineId+" stop-"+d.id;})
                .attr("fill", function(d){
                    return color(d.lineId);
                });

simulation.nodes(nodes)
    .on("tick", ticked);

simulation.force("link")
    .links(links);

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("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });
}

如何制作图表,使其在分配的 svg 大小内绘制?

【问题讨论】:

  • 使用适合您的数据集的 viewBox

标签: javascript d3.js svg force-layout


【解决方案1】:

使您的模拟适合您分配的区域的“正确”方法是调整模拟中的所有力,例如forceManyBodyforceLinkforceCenter 等...

但是,您可以强制模拟(没有双关语)以适应给定的区域。例如,在下面的演示中,模拟将被限制在一个 100 x 100 像素的小区域内,使用 tick 函数中的 this:

node.attr("transform", (d) => {
    return "translate(" + (d.x < 10 ? dx = 10 : d.x > 90 ? d.x = 90 : d.x) +
        "," + (d.y < 10 ? d.y = 10 : d.y > 90 ? d.y = 90 : d.y) + ")"
})

这里是演示:

var width = 100;
var height = 100;

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

var nodes = [{
  "id": "foo"
}, {
  "id": "bar"
}, {
  "id": "baz"
}, {
  "id": "foobar"
}];

var edges = [{
  "source": 0,
  "target": 1
}, {
  "source": 0,
  "target": 2
}, {
  "source": 0,
  "target": 3
}];

var simulation = d3.forceSimulation()
  .force("link", d3.forceLink())
  .force("charge", d3.forceManyBody().strength(-1000))
  .force("center", d3.forceCenter(width / 2, height / 2));

var links = svg.selectAll("foo")
  .data(edges)
  .enter()
  .append("line")
  .style("stroke", "#ccc")
  .style("stroke-width", 1);

var color = d3.scaleOrdinal(d3.schemeCategory20);

var node = svg.selectAll("foo")
  .data(nodes)
  .enter()
  .append("g");

var nodeCircle = node.append("circle")
  .attr("r", 5)
  .attr("stroke", "gray")
  .attr("stroke-width", "2px")
  .attr("fill", "white");

simulation.nodes(nodes);
simulation.force("link")
  .links(edges);

simulation.on("tick", function() {

  node.attr("transform", (d) => {
    return "translate(" + (d.x < 10 ? dx = 10 : d.x > 90 ? d.x = 90 : d.x) + "," + (d.y < 10 ? d.y = 10 : d.y > 90 ? d.y = 90 : d.y) + ")"
  })

  links.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;
    })


});
svg{
   background-color: lemonchiffon;
}
&lt;script src="https://d3js.org/d3.v4.min.js"&gt;&lt;/script&gt;

【讨论】:

    【解决方案2】:

    Mike Bostock 的Bounded force layout 也可以使用,您可以设置半径以匹配您的节点。

    node.attr("cx", function(d) { return d.x = Math.max(radius, Math.min(width - radius, d.x)); }) .attr("cy", function(d) { return d.y = Math.max(radius, Math.min(height - radius, d.y)); });

    【讨论】:

      【解决方案3】:

      只需使用 .strength 函数进行调整;例如

               .force("charge", d3.forceManyBody().strength(-5) )
      

      【讨论】:

        猜你喜欢
        • 2015-03-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多