有没有办法放大 D3 力布局图?

IT技术 javascript jquery d3.js zooming force-layout
2021-03-14 22:51:42

D3在这里有一个力导向布局有没有办法向这个图形添加缩放?目前,我能够捕获鼠标滚轮事件,但不确定如何编写重绘函数本身。有什么建议?

    var vis = d3.select("#graph")
        .append("svg:svg")
        .call(d3.behavior.zoom().on("zoom", redraw)) // <-- redraw function
        .attr("width", w)
        .attr("height", h);
6个回答

2014 年 6 月 4 日更新

有关D3 v.3 和相关示例中的更改,另请参阅Mike Bostock 的回答我认为这可能会取代下面的答案。

2014 年 2 月 18 日更新

如果您希望整个 SVG 平移和缩放,我认为 @ahaarnos 的答案更可取。g如果您在同一个 SVG 中有非缩放元素(原始问题中不是这种情况),那么下面我的回答中的嵌套元素才是真正必要的。如果您确实将行为应用于g元素,则需要背景rect或类似元素以确保g接收指针事件。

原答案

我根据zoom-pan-transform示例得到了这个工作- 你可以在这里看到我的 jsFiddle:http : //jsfiddle.net/nrabinowitz/QMKm3/

它比我希望的要复杂一点——你必须嵌套几个g元素才能让它工作,将 SVG 的pointer-events属性设置all,然后附加一个背景矩形来接收指针事件(否则它只能在指针结束时工作一个节点或链接)。redraw功能较为简单,只需设置一个转换的最里面g

var vis = d3.select("#chart")
  .append("svg:svg")
    .attr("width", w)
    .attr("height", h)
    .attr("pointer-events", "all")
  .append('svg:g')
    .call(d3.behavior.zoom().on("zoom", redraw))
  .append('svg:g');

vis.append('svg:rect')
    .attr('width', w)
    .attr('height', h)
    .attr('fill', 'white');

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

这有效地缩放了整个 SVG,因此它也会缩放笔触宽度,就像放大图像一样。

还有另一个示例说明了类似的技术。

@EricStob - 这可能是一个新问题。但请参阅jsfiddle.net/56RDx/2 - 这只是通过缩放比例的倒数重新缩放字体大小。
2021-04-20 22:51:42
@Ogg - 我不确定你在这里的意思 - jsFiddle 只是在 iFrame 中呈现你的结果,而不是某种自定义浏览器,所以你看到的真实的浏览器行为。jsFiddle 确实添加了一些东西,例如body标签,所以我建议查看框架源并查看您缺少什么。
2021-04-24 22:51:42
使用d3 的第 3 版时,在此示例中无法拖动单个节点。相反,它会平移整个图形,就好像您没有单击节点一样。这适用于版本 2,但我需要 v3 上的功能。有任何想法吗?
2021-04-27 22:51:42
这是 D3 v3 的解决方案:stackoverflow.com/questions/17953106/...
2021-04-27 22:51:42
@ajmartin - 见 zoom.scaleExtent()
2021-05-11 22:51:42

为什么是嵌套<g>的?

下面的这段代码对我来说效果很好(只有一个<g>,没有随机的大白色<rect>

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

然后将 svg 中的所有元素附加到vis元素。

将缩放行为添加到 SVG 元素的完美想法,我不知道您可以这样做,因此总是求助于使用烦人的背景矩形。在 SVG 上添加行为至少适用于 Chrome、FF 和 Opera 的现代版本。
2021-04-16 22:51:42
可能是您丢失了属性“viewBox”、“preserveAspectRatio”和“pointer-events”,它仍然可以工作吗?
2021-04-19 22:51:42
@notan3xit 是对的,不需要 viewBox、preserveAspectRatio 和 pointer-events。关键是应用transformation上的属性g元素,没有了上svg元素。
2021-04-22 22:51:42
似乎不适用于 D3 v3,或者说缩放功能仍然有效,但移动单个节点的能力丢失了。@nrabinowitz 解决方案也存在同样的问题。这是 nrabinowitz 的小提琴更新以使用 ahaarnos 的解决方案:jsfiddle.net/QMKm3/716,这里的小提琴更新为使用 D3v3 来说明问题:jsfiddle.net/QMKm3/717
2021-05-05 22:51:42

提供的答案适用于 D3 v2,但不适用于 v3。我已将响应合成为一个干净的解决方案,并使用此处提供的答案解决了 v3 问题:为什么 d3.js v3 在实现缩放时会破坏我的力图,而 v2 没有?

首先是主要代码。这是@ahaarnos 回答的清理版本:

    var svg = d3.select("body")
        .append("svg")
        .attr("width", width)
        .attr("height", height)
            .call(d3.behavior.zoom().on("zoom", redraw))
        .append('g');

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

现在您有了平移和缩放功能,但您将无法拖动节点,因为平移功能将覆盖拖动功能。所以我们需要这样做:

var drag = force.stop().drag()
.on("dragstart", function(d) {
    d3.event.sourceEvent.stopPropagation(); // to prevent pan functionality from 
                                            //overriding node drag functionality.
    // put any other 'dragstart' actions here
});

这是@nrabinowitz' fiddle 修改为使用这种更清晰的缩放实现,但说明了 D3v3 如何打破节点拖动:http : //jsfiddle.net/QMKm3/718/

这是修改为与 D3v3 一起使用的相同小提琴:http : //jsfiddle.net/QMKm3/719/

我让我的图表在没有第二个“svg:g”附加的情况下工作。

[...].attr("pointer-events", "all")
     .attr("width", width2)
     .attr("height", height2)
     .append('svg:g')
     .call(d3.behavior.zoom().on("zoom", redraw));

其余的都是一样的。

但没有矩形:你不能平移(只能缩放)
2021-04-21 22:51:42

我得到了带有缩放选项的 D3 力有向图的解决方案。

    var m = [40, 240, 40, 240],
    width = 960,
    height = 700,
    root;
var svg = d3.select("body").append("svg")
    .attr("class", "svg_container")
    .attr("width", width)
    .attr("height", height)
    .style("overflow", "scroll")
    .style("background-color", "#EEEEEE")
    .append("svg:g")
    .attr("class", "drawarea")
    .append("svg:g")
    .attr("transform", "translate(" + m[3] + "," + m[0] + ")");

//applying zoom in&out for svg
d3.select("svg") 
.call(d3.behavior.zoom()
    .scaleExtent([0.5, 5])
    .on("zoom", zoom));

//zooming 
function zoom() { //zoom in&out function 
    var scale = d3.event.scale,
        translation = d3.event.translate,
        tbound = -height * scale,
        bbound = height * scale,
        lbound = (-width + m[1]) * scale,
        rbound = (width - m[3]) * scale;
    // limit translation to thresholds
    translation = [
        Math.max(Math.min(translation[0], rbound), lbound),
        Math.max(Math.min(translation[1], bbound), tbound)
    ];
    d3.select(".drawarea")
        .attr("transform", "translate(" + translation + ")" +
            " scale(" + scale + ")");
}