वहाँ एक D3 बल लेआउट ग्राफ में ज़ूम करने का एक तरीका है?


80

डी 3 में बल निर्देशित लेआउट है । क्या इस ग्राफ़ में ज़ूमिंग जोड़ने का कोई तरीका है? वर्तमान में, मैं माउस व्हील इवेंट को कैप्चर करने में सक्षम था, लेकिन वास्तव में यह सुनिश्चित नहीं है कि रीड्रा फ़ंक्शन को कैसे लिखा जाए। कोई सुझाव?

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

यह भी देखें इस उदाहरण thisismattmiller.com/blog/add-zoom-slider-to-d3-js मैट मिलर द्वारा। यह केवल प्रक्रिया के अंत में एक "जी" तत्व जोड़ता है।
एरिवेरो

4
किसी ने दिखाया कि zui53 (ज़ूम करने योग्य इंटरफेस के लिए एक पुस्तकालय) और d3js को कैसे संयोजित करें: bl.ocks.org/timelyportfolio/5149102
9

जवाबों:


97

अपडेट 6/4/14

D3 v.3 में बदलाव और संबंधित उदाहरण के लिए यहां माइक बॉस्कोक का जवाब भी देखें । मुझे लगता है कि यह शायद नीचे दिए गए उत्तर को प्रभावित करेगा।

अपडेट 2/18/2014

मुझे लगता है कि @ अहानारोस का जवाब बेहतर है यदि आप पूरे एसवीजी को पैन और ज़ूम करना चाहते हैं। gनीचे दिए गए मेरे उत्तर में निहित तत्व वास्तव में केवल आवश्यक हैं यदि आपके पास उसी एसवीजी में गैर-ज़ूमिंग तत्व हैं (मूल प्रश्न में मामला नहीं)। यदि आप करते हैं एक को व्यवहार लागू gतत्व है, तो एक पृष्ठभूमि rectया इसी तरह के तत्व यह सुनिश्चित करें कि आवश्यक है gसूचक घटनाओं प्राप्त करता है।

मूल उत्तर

मुझे यह काम ज़ूम-पैन-ट्रांसफ़ॉर्म उदाहरण के आधार पर मिला - आप मेरी jsFiddle को यहाँ देख सकते हैं: http://jsfiddle.net/nrabinowitz/QMKm3/

यह उम्मीद की तुलना में थोड़ा अधिक जटिल था - आपको gइसे काम करने के लिए कई तत्वों को घोंसला बनाना होगा, एसवीजी की 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 + ")");
}

यह प्रभावी रूप से पूरे एसवीजी को मापता है, इसलिए यह स्ट्रोक की चौड़ाई को भी बढ़ाता है, जैसे कि एक छवि को ज़ूम इन करना।

एक और उदाहरण है जो एक समान तकनीक दिखाता है।


1
@ ऑग - मुझे यकीन नहीं है कि आपका यहां क्या मतलब है - jsFiddle सिर्फ आपके परिणामों को आईफ्रेम में प्रस्तुत करता है, किसी प्रकार के कस्टम ब्राउज़र में नहीं, इसलिए जो आप देखते हैं वह वास्तविक ब्राउज़र व्यवहार है। jsFiddle कुछ चीजों को जोड़ता है, जैसे एक bodyटैग, इसलिए मैं फ्रेम स्रोत को देखने और यह देखने की सलाह देता हूं कि आप क्या याद कर रहे हैं।
nrabinowitz

2
@ EricStob - यह एक नया प्रश्न हो सकता है। लेकिन jsfiddle.net/56RDx/2 देखें - यह केवल ज़ूम स्केल के व्युत्क्रम से फ़ॉन्ट आकार को बचाता है।
nrabinowitz

1
@ajmartin - देखेंzoom.scaleExtent()
nrabinowitz

1
डी 3 के संस्करण 3 का उपयोग करते समय , एक व्यक्तिगत नोड को खींचने की क्षमता इस उदाहरण में काम नहीं करती है। इसके बजाय यह पूरे ग्राफ को छोड़ देता है जैसे कि आपने नोड पर क्लिक नहीं किया है। यह संस्करण 2 पर काम करता है, लेकिन मुझे v3 पर एक सुविधा की आवश्यकता है। कोई विचार?
डेरिल वान सिटर्ट

1
यहाँ डी 3 वी 3 के लिए समाधान है: 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" और "पॉइंटर-इवेंट्स" विशेषताओं को खो सकते हैं और यह अभी भी काम करेगा?
notan3xit

@ notan3xit सही है, viewBox, preserveAspectRatio और पॉइंटर-इवेंट आवश्यक नहीं हैं। तत्व transformationपर गुण को लागू करना है g, तत्व पर नहींsvg
लेकेनस्टाइन

डी 3 वी 3 के साथ काम करने के लिए प्रतीत नहीं होता है, या बल्कि ज़ूम सुविधा अभी भी काम करती है लेकिन व्यक्तिगत नोड्स को स्थानांतरित करने की क्षमता खो जाती है। @nrabinowitz समाधान उसी समस्या को प्रदर्शित करता है। यहाँ nrabinowitz 'फिडेल को ahaarnos' समाधान का उपयोग करने के लिए अद्यतन किया गया है: jsfiddle.net/QMKm3/716 और यहाँ समस्या का वर्णन करने के लिए D3v3 का उपयोग करने के लिए उसी फ़िडेल को अद्यतन किया गया है: jsfiddle.net
डेविड मार्क्स

एसवीजी तत्व में ज़ूम व्यवहार को जोड़ने के लिए बिल्कुल सही विचार, मुझे नहीं पता था कि आप ऐसा कर सकते हैं और कष्टप्रद पृष्ठभूमि आयतों का उपयोग करने के लिए हमेशा सहारा लिया। एसवीजी पर व्यवहार को जोड़ना कम से कम क्रोम, एफएफ और ओपेरा के आधुनिक संस्करणों में काम करता है।
rcijvat

14

प्रदान किए गए उत्तर D3 v2 में काम करते हैं लेकिन v3 में नहीं। मैंने प्रतिक्रियाओं को एक स्वच्छ समाधान में संश्लेषित किया है और यहां दिए गए उत्तर का उपयोग करके v3 मुद्दे को हल किया है: v3 नहीं होने पर ज़ूमिंग को लागू करते समय 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

मुझे जूमिंग विकल्प के साथ डी 3 बल निर्देशित ग्राफ के लिए एक समाधान मिला।

    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 पर ध्यान दें, फ़ंक्शन ड्रैगस्टार्ट (), ड्रैग (), और ड्रैग्ड ()। समारोह टिक () भी बदल गया था।

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


    };

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.