2012-08-13 4 views
45

Ho un grafico utilizzando layout di forza, ma ha una larghezza fissa w ed altezza h:Come rendere grafico di layout vigore nel d3.js sensibile alle dimensioni dello schermo/navigatore

var svg = d3.select("#viz").append("svg") 
      .attr("id", "playgraph") 
      .attr("width", w) 
      .attr("height", h) 

var force = d3.layout.force() 
       .nodes(nodes) 
       .links(links) 
       .charge(-1600) 
       .linkDistance(45) 
       .size([w, h]); 

che si traduce in uno svg grafico che non si ridimensiona o diminuisce nonostante le modifiche apportate allo schermo o alle dimensioni della finestra del browser. Al fine di rendere più reattivo (vale a dire si ridimensiona automaticamente), ho provato ad utilizzare viewBox e preserveAspectRatio attributi:

var svg = d3.select("#viz").append("svg") 
      .attr("id", "playgraph") 
      .attr("width", w) 
      .attr("height", h) 
      .attr("viewBox", "0, 0, 600, 400") 
      .attr("preserveAspectRatio", "xMidYMid meet"); 

Purtroppo, questo non ha funzionato come non succede nulla quando ho regolare le dimensioni della finestra del browser. Mi chiedo se lo .size([w, h]) del grafico delle forze abbia qualcosa a che fare con questo.

Si prega di fare luce su come utilizzare gli attributi viewBox e preserveAspectRatio con i grafici di imposizione forzata.

+0

Si consiglia di allegare la funzione di ridisegno a 'window.onresize' – Wex

+0

Questa domanda è abbastanza vecchia, ma per coloro che la trovano utile, si potrebbe anche considerare di limitare anche i nodi a una casella limitata. Al ridimensionamento, i nodi rimarranno sullo schermo. Esempio: http://bl.ocks.org/mbostock/1129492 – joshfindit

risposta

50

Il problema non è compreso tra .size(), è che si stanno indicando le dimensioni SVG in .attr("width", w) .attr("height", h). Rimuovere questi due attributi e si otterrà nel modo giusto ...

var svg = d3.select("#viz").append("svg") 
      .attr("id", "playgraph") 
      //better to keep the viewBox dimensions with variables 
      .attr("viewBox", "0 0 " + w + " " + h) 
      .attr("preserveAspectRatio", "xMidYMid meet"); 

http://jsfiddle.net/aaSjd/

+0

grazie! Così ora l'immagine svg viene ridimensionata. Tuttavia, senza impostare 'attr (" width ", ...)' e 'attr (" height ", ...)', la larghezza/altezza dell'immagine sembra essere la larghezza/altezza della finestra del browser corrente. C'è un modo per impostare queste due dimensioni dell'elemento 'svg' da qualche altra parte, senza influenzare gli attributi' viewBox' e 'preserveAspectRatio'? – MLister

+3

' 'dovrebbe iniziare. – Duopixel

4

Duopixel è molto vicino a quello che mi serviva, tranne che non so perché ha nidificato due <g> elementi e collegato il ascoltatori di eventi al più esterno <g> (anche richiedendo un rettangolo invisibile dietro tutto per far reagire il g agli eventi su tutto lo spazio).

È più semplice collegare gli ascoltatori allo <svg> e quindi è necessario solo uno interno <g>.

Ecco il mio pieno schermo forza-diretto Esempio:

var width = 1000, 
    height = 1000; 

var color = d3.scale.category20(); 

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

function draw_graph(graph) { 
    var force = d3.layout.force() 
     .charge(-120) 
     .linkDistance(30) 
     .nodes(graph.nodes) 
     .links(graph.links) 
     .size([width, height]) 
     .start(); 

    var link = vis.selectAll(".link") 
     .data(graph.links) 
     .enter().append("line") 
     .attr("class", "link") 
     .style("stroke-width", function(d) { return Math.sqrt(d.value); }); 

    var node = vis.selectAll(".node") 
     .data(graph.nodes) 
     .enter().append("circle") 
     .attr("class", "node") 
     .attr("r", 5) 
     .style("fill", function(d) { return color(d.group); }) 
     .call(force.drag); 

    node.append("title") 
     .text(function(d) { return d.name; }); 

    force.on("tick", function() { 
    link.attr("x1", function(d) { return d.source.x; }) 
     .attr("y1", function(d) { return d.source.y; }) 
     .attr("x2", function(d) { return d.target.x; }) 
     .attr("y2", function(d) { return d.target.y; }); 

    node.attr("cx", function(d) { return d.x; }) 
     .attr("cy", function(d) { return d.y; }); 
    }); 
}; 

draw_graph(data); 
8

La soluzione mostrata qui: http://bl.ocks.org/mbostock/3355967 funzionato bene per me!

window.addEventListener('resize', resize); 

function resize() { 
    var width = window.innerWidth, height = window.innerHeight; 
    svg.attr("width", width).attr("height", height); 
    force.size([width, height]).resume(); 
} 

Assicurati di eseguire ridimensiona() dopo aver aggiunto tutte le linee, i nodi ecc.