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

Matt Miller의 thisismattmiller.com/blog/add-zoom-slider-to-d3-js 예제도 참조하십시오 . 프로세스 끝에 "g"요소 만 추가합니다.
arivero

4
누군가 zui53 (확대 가능한 인터페이스 용 라이브러리)과 d3js를 결합하는 방법을 보여주었습니다 : bl.ocks.org/timelyportfolio/5149102
widged

답변:


97

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의 크기가 효과적으로 조정되므로 이미지를 확대하는 것처럼 획 너비도 조정됩니다.

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


1
@Ogg는 - 나는 확실히 여기에서 의미하지하고있어 - jsFiddle는 iframe에 결과, 사용자의 브라우저하지 어떤 종류의, 그래서 당신은 무엇을보고 선물 입니다 실제 브라우저 동작을. jsFiddle은 body태그 와 같은 몇 가지 사항을 추가 하므로 프레임 소스를보고 누락 된 내용을 확인하는 것이 좋습니다.
nrabinowitz

2
@EricStob-새로운 질문이 될 수 있습니다. 그러나 jsfiddle.net/56RDx/2를 참조하십시오. 이것은 단순히 확대 / 축소 배율의 역으로 ​​글꼴 크기를 다시 조정합니다.
nrabinowitz

1
@ajmartin-참조 zoom.scaleExtent()
nrabinowitz

1
d3 버전 3 을 사용 하는 경우이 예제에서는 개별 노드를 드래그하는 기능이 작동하지 않습니다. 대신 노드를 클릭하지 않은 것처럼 전체 그래프를 이동합니다. 이것은 버전 2 에서 작동 하지만 v3의 기능이 필요합니다. 어떤 아이디어?
Daryl Van Sittert 2014

1
여기 D3 v3의 솔루션입니다 : stackoverflow.com/questions/17953106/...은
데이비드 막스

18

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


1
"viewBox", "preserveAspectRatio"및 "pointer-events"속성을 잃어 버려도 여전히 작동 할 수 있습니까?
notan3xit 2013

@ notan3xit이 맞고, viewBox, preserveAspectRatio 및 포인터 이벤트가 필요하지 않습니다. 키는 적용하는 것입니다 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

제공된 답변은 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/


2

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

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

나머지는 동일합니다.


하지만 사각형없이 : 당신은 이동 (만 확대) 할 수
user1043144

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 에서 확인할 수 있습니다 . 사이트의 언어는 한국어입니다. 그러나 페이지의 세 번째 예에서 결과를 쉽게 찾을 수 있습니다.

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.