从分配的SVG大小

时间:2017-03-18 09:53:56

标签: javascript d3.js svg force-layout

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

这是我的代码:

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大小中绘制?

3 个答案:

答案 0 :(得分:1)

"正确"在您所分配的区域内进行模拟拟合的方法是调整模拟中的所有力,例如forceManyBodyforceLinkforceCenter等......

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

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) + ")"
})

以下是演示:

&#13;
&#13;
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;
    })


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

答案 1 :(得分:0)

只需使用.strength函数调整; e.g。

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

答案 2 :(得分:0)

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