Есть ли способ увеличить график расположения сил D3? - PullRequest
80 голосов
/ 24 октября 2011

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 ]

97 голосов
/ 26 октября 2011

Обновление 6/4/14

См. Также Ответ Майка Бостока здесь об изменениях в D3 v.3 и связанном примере . Я думаю, что это, вероятно, заменяет ответ ниже.

Обновление 2/18/2014

Я думаю, что ответ @ ahaarnos предпочтительнее, если вы хотите, чтобы весь SVG панорамировал и масштабировал. Вложенные g элементы в моем ответе ниже действительно необходимы только в том случае, если у вас есть элементы без масштабирования в том же SVG (не так, как в первоначальном вопросе). Если вы do примените поведение к элементу g, тогда фон rect или аналогичный элемент необходим для того, чтобы g получал события указателя.

Оригинальный ответ

Я получил эту работу, основываясь на примере zoom-pan-transform - мой jsFiddle вы можете увидеть здесь: http://jsfiddle.net/nrabinowitz/QMKm3/

Это было немного сложнее, чем я надеялся - вам нужно вложить несколько элементов g, чтобы заставить его работать, установите атрибут pointer-events SVG 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, поэтому также масштабирует ширину обводки, как увеличение изображения.

Существует еще один пример , иллюстрирующий аналогичную технику.

18 голосов
/ 08 марта 2013

Почему вложенные <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.

14 голосов
/ 04 июня 2014

Предоставленные ответы работают в 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 ', модифицированный для использования этой более чистой реализации масштабирования, но иллюстрирующий, как D3v3 прерывает перетаскивание узла: http://jsfiddle.net/QMKm3/718/

А вот та же скрипка, модифицированная для работы с D3v3: http://jsfiddle.net/QMKm3/719/

2 голосов
/ 15 апреля 2013

Мой график работает без второго добавления "svg: g".

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

Остальное тоже самое.

0 голосов
/ 27 ноября 2014

Если вы хотите увеличить масштаб и панорамировать макет без изменения размера узла, попробуйте ниже. Вы также можете перетаскивать узлы без дрожания. Этот код основан на оригинальном примере раскладки силы. Что касается данных узлов и ссылок, пожалуйста, обратитесь к исходным образцам данных. http://bl.ocks.org/mbostock/4062045

Пожалуйста, обратите внимание на переменные 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) + ")";
        });


    };

0 голосов
/ 29 мая 2014

Я получил решение для силового ориентированного графа 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 + ")");
}
...