Javascript 如何使 D3.js 中的力布局图响应屏幕/浏览器大小

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11942500/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 07:46:09  来源:igfitidea点击:

How to make force layout graph in D3.js responsive to screen/browser size

javascriptsvgd3.jsforce-layout

提问by MLister

I have a graph using force layout, but it has a fixed width wand height h:

我有一个使用强制布局的图形,但它具有固定的宽度w和高度h

var svg = d3.select("#viz").append("svg")
            .attr("id", "playgraph")
            .attr("width", w)
            .attr("height", h)

var force = d3.layout.force()
              .nodes(nodes)
              .links(links)
              .charge(-1600)
              .linkDistance(45)
              .size([w, h]); 

which results in a svg graph that does not scale or down despite of changes in screen or browser window size. In order to make it responsive (i.e. automatically resizes itself), I tried using viewBoxand preserveAspectRatioattributes:

尽管屏幕或浏览器窗口大小发生变化,这会导致 svg 图形不会缩放或缩小。为了使其具有响应性(即自动调整自身大小),我尝试使用viewBoxpreserveAspectRatio属性:

var svg = d3.select("#viz").append("svg")
            .attr("id", "playgraph")
            .attr("width", w)
            .attr("height", h)
            .attr("viewBox", "0, 0, 600, 400")
            .attr("preserveAspectRatio", "xMidYMid meet");

Unfortunately, this didn't work as nothing happens when I adjust the browser window size. I wonder if the .size([w, h])of the force graph has anything to do with this.

不幸的是,这不起作用,因为当我调整浏览器窗口大小时没有任何反应。我想知道力图的 是否.size([w, h])与此有关。

Please shed some light on how to use viewBoxand preserveAspectRatioattributes with force layout graphs.

请阐明如何使用力布局图viewBoxpreserveAspectRatio属性。

回答by methodofaction

The problem is not within .size(), it's that you are stating the SVG dimensions in .attr("width", w) .attr("height", h). Remove these two attributes and you'll get it right...

问题不在于内.size(),那就是你陈述SVG尺寸.attr("width", w) .attr("height", h)。删除这两个属性,你会得到正确的......

var svg = d3.select("#viz").append("svg")
            .attr("id", "playgraph")
             //better to keep the viewBox dimensions with variables
            .attr("viewBox", "0 0 " + w + " " + h )
            .attr("preserveAspectRatio", "xMidYMid meet");

http://jsfiddle.net/aaSjd/

http://jsfiddle.net/aaSjd/

回答by Matt Jensen

The solution shown here: http://bl.ocks.org/mbostock/3355967worked well for me!

此处显示的解决方案:http: //bl.ocks.org/mbostock/3355967对我来说效果很好!

window.addEventListener('resize', resize); 

function resize() {
    var width = window.innerWidth, height = window.innerHeight;
    svg.attr("width", width).attr("height", height);
    force.size([width, height]).resume();
}

Make sure to run resize() after you have appended all your lines, nodes etc as well.

确保在附加所有行、节点等之后运行 resize()。

回答by aaaronic

Duopixel is very close to what I needed, except I don't know why he nested two <g>elements and attached the event listeners to the outermost <g>(also requiring an invisible rectangle behind everything to make the g react to events over its whole space).

Duopixel 非常接近我需要的东西,除了我不知道为什么他嵌套了两个<g>元素并将事件侦听器附加到最外面<g>(还需要在所有内容后面有一个不可见的矩形以使 g 对整个空间中的事件做出反应)。

It's easier to attach the listeners to the <svg>itself and then you only need one internal <g>.

将侦听器附加到它<svg>本身会更容易,然后您只需要一个内部<g>.

Here is my full-screen force-directed example:

这是我的全屏力导向示例:

var width = 1000,
    height = 1000;

var color = d3.scale.category20();

var svg = d3.select("body")
    .append("svg")
      .attr({
        "width": "100%",
        "height": "100%"
      })
      .attr("viewBox", "0 0 " + width + " " + height )
      .attr("preserveAspectRatio", "xMidYMid meet")
      .attr("pointer-events", "all")
    .call(d3.behavior.zoom().on("zoom", redraw));

var vis = svg
    .append('svg:g');

function redraw() {
  vis.attr("transform",
      "translate(" + d3.event.translate + ")"
      + " scale(" + d3.event.scale + ")");
}

function draw_graph(graph) {
  var force = d3.layout.force()
      .charge(-120)
      .linkDistance(30)
      .nodes(graph.nodes)
      .links(graph.links)
      .size([width, height])
      .start();

  var link = vis.selectAll(".link")
      .data(graph.links)
      .enter().append("line")
      .attr("class", "link")
      .style("stroke-width", function(d) { return Math.sqrt(d.value); });

  var node = vis.selectAll(".node")
      .data(graph.nodes)
      .enter().append("circle")
      .attr("class", "node")
      .attr("r", 5)
      .style("fill", function(d) { return color(d.group); })
      .call(force.drag);

  node.append("title")
      .text(function(d) { return d.name; });

  force.on("tick", function() {
    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; });
  });
};

draw_graph(data);