D3力レイアウトグラフにズームインする方法はありますか?


80

D3には、ここに力指向のレイアウトがあります。このグラフにズームを追加する方法はありますか?現在、マウスホイールイベントをキャプチャすることはできましたが、再描画関数自体の記述方法がよくわかりません。助言がありますか?

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

MattMillerによるこの例thisismattmiller.com/blog/add-zoom-slider-to-d3-jsも参照してください。プロセスの最後に「g」要素を追加するだけです。
arivero 2012年

4
誰かがzui53(ズーム可能なインターフェース用のライブラリ)とd3jsを組み合わせる方法を示しました:bl.ocks.org/timelyportfolio/5149102
2013年

回答:


97

2014年6月4日更新

D3 v.3の変更点と関連する例については、MikeBostockの回答も参照してください。これはおそらく以下の答えに取って代わると思います。

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全体が効果的に拡大縮小されるため、画像を拡大するように、ストローク幅も拡大縮小されます。

同様の手法を説明する別のがあります。


1
@ Ogg-ここで何を意味するのかわかりません-jsFiddleは、ある種のカスタムブラウザーではなく、iFrameで結果を表示するだけなので、実際のブラウザーの動作表示されます。jsFiddleはbodyタグなどのいくつかのものを追加するので、フレームソースを調べて、不足しているものを確認することをお勧めします。
nrabinowitz 2011

2
@ EricStob-それは新しい質問かもしれません。ただし、jsfiddle.net / 56RDx / 2を参照してください。これは、ズームスケールの逆数でフォントサイズを再スケーリングするだけです。
nrabinowitz 2012年


1
d3のバージョン3を使用する場合、この例では個々のノードをドラッグする機能は機能しません。代わりに、ノードをクリックしていないかのようにグラフ全体をパンします。これはバージョン2で機能しますが、v3の機能が必要です。何か案は?
Daryl Van Sittert 2014

1
D3 v3のソリューションは次のとおりです。stackoverflow.com
David Marx

18

なぜネストされた<g>のですか?

以下のこのコードは私にとってはうまくいきました(<g>ランダムな大きな白がなく、1つだけです<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ます。


1
属性「viewBox」、「preserveAspectRatio」、「pointer-events」を失っても、それでも機能する可能性がありますか?
notan3xit 2013

@ notan3xitは正しいです、viewBox、preserveAspectRatioおよびpointer-eventsは必要ありません。キーは、適用することですtransformation上の属性をg、要素ではないsvg要素。
Lekensteyn 2014年

D3 v3では機能しないようです。または、ズーム機能は引き続き機能しますが、個々のノードを移動する機能は失われます。@nrabinowitzソリューションでも同じ問題が発生します。ahaarnosのソリューションを使用するように更新されたnrabinowitzのフィドル:jsfiddle.net/QMKm3/716および問題を説明するためにD3v3を使用するように更新された同じフィドル:jsfiddle.net/QMKm3/717
David Marx

SVG要素にズーム動作を追加するのに最適なアイデアです。それができるとは思っていなかったため、常に迷惑な背景の長方形を使用することにしました。SVGに動作を追加することは、少なくともChrome、FF、およびOperaの最新バージョンで機能します。
rcijvat 2015年

14

提供された回答はD3v2で機能しますが、v3では機能しません。応答をクリーンなソリューションに統合し、ここで提供される回答を使用してv3の問題を解決しました:v2が実装されていないのに、ズームを実装すると、d3.js v3がフォースグラフを破損するのはなぜですか?

まずメインコード。これは@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のフィドルですが、D3v3がノードドラッグをどのように壊すかを示しています:http://jsfiddle.net/QMKm3/718/

そして、これがD3v3で動作するように変更された同じフィドルです:http://jsfiddle.net/QMKm3/719/


2

2番目の「svg:g」を追加せずにグラフを機能させました。

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

残りは同じです。


ただし、長方形がないと、パンできません(ズームのみ)
user1043144 2013年

0

ズームオプションを使用した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 + ")");
}

0

ノードサイズを変更せずにフォースレイアウトをズームおよびパンしたい場合は、以下を試してください。震えることなくノードをドラッグすることもできます。このコードは、元の力のレイアウトの例に基づいています。ノードとリンクのデータについては、元のサンプルデータを参照してください。http://bl.ocks.org/mbostock/4062045

Plzは、変数xScaleとyScale、関数dragstarted()、dragged()、およびdragended()に注意してください。関数tick()も変更されました。

結果はhttp://steelblue.tistory.com/9で確認できます 。サイトの言語は韓国語です。ただし、ページの3番目の例で結果を簡単に見つけることができます。

var graph = {
    "nodes": [
      { "name": "Myriel", "group": 1 },
      { "name": "Napoleon", "group": 1 },
      // ......
      { "name": "Mme.Hucheloup", "group": 8 }
    ],
    "links": [
      { "source": 1, "target": 0, "value": 1 },
      { "source": 2, "target": 0, "value": 8 },
    // .......
      { "source": 76, "target": 58, "value": 1 }
    ]
};
var width = 640,
    height = 400;
 var color = d3.scale.category20();



var xScale = d3.scale.linear()
        .domain([0, width])
         .range([0, width]);

var yScale = d3.scale.linear()
    .domain([0, height])
   .range([0, height]);
var zoomer = d3.behavior.zoom().x(xScale).y(yScale).scaleExtent([0.1, 8]).on("zoom", zoom);
function zoom() {

    tick(); 
};

var drag = d3.behavior.drag()
        .origin(function (d) { return d; })
         .on("dragstart", dragstarted)
        .on("drag", dragged)
        .on("dragend", dragended);

function dragstarted(d) {
    d3.event.sourceEvent.stopPropagation();

    d.fixed |= 2;         
}
function dragged(d) {

    var mouse = d3.mouse(svg.node());
    d.x = xScale.invert(mouse[0]);
    d.y = yScale.invert(mouse[1]);
    d.px = d.x;         
    d.py = d.y;
    force.resume();
}

function dragended(d) {

    d.fixed &= ~6;           }

var force = d3.layout.force()
    .charge(-120)
    .linkDistance(30)
    .size([width, height]);

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

svg.call(zoomer);

    force
        .nodes(graph.nodes)
        .links(graph.links)
        .start();

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

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

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

    force.on("tick",tick);

function tick(){            
        link.attr("x1", function (d) { return  xScale(d.source.x); })
            .attr("y1", function (d) { return yScale(d.source.y);  })
            .attr("x2", function (d) { return xScale(d.target.x); })
            .attr("y2", function (d) { return yScale(d.target.y); });

        node.attr("transform", function (d) {
            return "translate(" + xScale(d.x) + "," + yScale(d.y) + ")";
        });


    };

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.