[javascript] D3 힘 레이아웃 그래프를 확대하는 방법이 있습니까?

D3에는 여기에 힘 방향 레이아웃이 있습니다 . 이 그래프에 확대 / 축소를 추가하는 방법이 있습니까? 현재 마우스 휠 이벤트를 캡처 할 수 있었지만 다시 그리기 기능 자체를 작성하는 방법을 잘 모르겠습니다. 어떤 제안?

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



답변

2014 년 6 월 4 일 업데이트

D3 v.3의 변경 사항 및 관련 예제여기 에서 Mike Bostock의 답변을 참조하십시오. . 나는 이것이 아마도 아래 대답을 대체한다고 생각합니다.

2014 년 2 월 18 일 업데이트

전체 SVG를 팬 및 확대 / 축소하려면 @ahaarnos의 대답이 더 바람직하다고 생각합니다. g아래 내 대답 의 중첩 요소는 동일한 SVG에 확대되지 않는 요소가있는 경우에만 실제로 필요합니다 (원래 질문의 경우가 아님). 당신이 경우에 A와 동작을 적용 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의 크기가 효과적으로 조정되므로 이미지를 확대하는 것처럼 획 너비도 조정됩니다.

유사한 기술을 보여주는 또 다른 예가 있습니다 .


답변

중첩 된 이유 <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.


답변

제공된 답변은 D3 v2에서 작동하지만 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/


답변

두 번째 “svg : g”추가없이 그래프가 작동하도록했습니다.

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

나머지는 동일합니다.


답변

확대 / 축소 옵션이있는 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 + ")");
}


답변

노드 크기를 변경하지 않고 레이아웃을 확대 / 축소하고 이동하려면 아래를 시도하십시오. 떨림없이 노드를 드래그 할 수도 있습니다. 이 코드는 원래의 힘 레이아웃 예제를 기반으로합니다. 노드 및 링크 데이터는 원본 샘플 데이터를 참조하십시오.http://bl.ocks.org/mbostock/4062045

Plz는 xScale 및 yScale 변수, dragstarted (), dragged () 및 dragended () 함수를 확인합니다. tick () 함수도 변경되었습니다.

결과는 http://steelblue.tistory.com/9 에서 확인할 수 있습니다
. 사이트의 언어는 한국어입니다. 그러나 페이지의 세 번째 예에서 결과를 쉽게 찾을 수 있습니다.

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


    };


답변