簡體   English   中英

有沒有辦法放大D3力布局圖?

[英]Is there a way to zoom into a D3 force layout graph?

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年4月4日更新

另請參閱Mike Bostock關於D3 v.3和相關示例中的更改的答案 我想這可能取代下面的答案。

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,因此它也可以縮放筆畫寬度,例如放大圖像。

還有另一個例子說明了一種類似的技術。

嵌套<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問題: 為什么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/

我的圖表工作沒有第二個“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) + ")";
        });


    };

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM