2013-04-17 17 views
16

Ho implementato il seguente grafico con i bordi resi con d3.svg.diagonal(). Tuttavia, quando provo a sostituire la diagonale con d3.svg.line(), non sembra che estragga i dati di destinazione e di origine. Cosa mi manca? C'è qualcosa che non capisco su d3.svg.line?D3: Sostituzione di d3.svg.diagonal() con d3.svg.line()

enter image description here

Quello che segue è il codice mi riferisco a, seguito dal codice completo:

var line = d3.svg.line() 
    .x(function(d) { return d.lx; }) 
    .y(function(d) { return d.ly; }); 

...

var link= svg.selectAll("path") 
    .data(links) 
    .enter().append("path") 
    .attr("d",d3.svg.diagonal()) 
    .attr("class", ".link") 
    .attr("stroke", "black") 
    .attr("stroke-width", "2px") 
    .attr("shape-rendering", "auto") 
    .attr("fill", "none"); 

L'intero codice:

var margin = {top: 20, right: 20, bottom: 20, left: 20}, 
    width =1500, 
    height = 1500, 
    diameter = Math.min(width, height), 
    radius = diameter/2; 


var balloon = d3.layout.balloon() 
    .size([width, height]) 
    .value(function(d) { return d.size; }) 
    .gap(50)     

var line = d3.svg.line() 
    .x(function(d) { return d.lx; }) 
    .y(function(d) { return d.ly; }); 


var svg = d3.select("body").append("svg") 
    .attr("width", width + margin.left + margin.right) 
    .attr("height", height + margin.top + margin.bottom) 
    .append("g") 
    .attr("transform", "translate(" + (margin.left + radius) + "," + (margin.top + radius) + ")") 

    root = "flare.json"; 
    root.y0 = height/2; 
    root.x0 = width/2; 

d3.json("flare.json", function(root) { 
    var nodes = balloon.nodes(root), 
     links = balloon.links(nodes); 


var link= svg.selectAll("path") 
    .data(links) 
    .enter().append("path") 
    .attr("d",d3.svg.diagonal()) 
    .attr("class", ".link") 
    .attr("stroke", "black") 
    .attr("stroke-width", "2px") 
    .attr("shape-rendering", "auto") 
    .attr("fill", "none"); 

    var node = svg.selectAll("g.node") 
    .data(nodes) 
    .enter() 
    .append("g") 
    .attr("class", "node"); 

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

    node.append("text") 
     .attr("dx", function(d) { return d.x }) 
     .attr("dy", function(d) { return d.y }) 
     .attr("font-size", "5px") 
     .attr("fill", "white") 
     .style("text-anchor", function(d) { return d.children ? "middle" : "middle"; }) 
     .text(function(d) { return d.name; }) 
}); 

Un confronto di come l'attributo d dello svg scompare quando si utilizza "line". enter image description here enter image description here

+0

Lei non sembrano essere usando 'Line' in qualsiasi parte del codice. L'attributo 'd' del percorso è ancora impostato usando' d3.svg.diagonal'. –

+0

Sì, ma quando sostituisco "line" per "d3.svg.diagonal()" 0 si rompe la vis. Non riesco a capire perché. –

+0

Come si rompe? –

risposta

1

Basta impostare l'attributo d di collegamento alla linea:

.attr("d", line) 
+0

Sì, ma quando sostituisco "line" per "d3.svg.diagonal()" 0 si rompe la vis. –

+0

Puoi creare un piccolo esempio su jsFiddle? –

+0

Ho provato, ma il codice sorgente con il layout del fumetto è su github e non sembra accettarlo. –

1

Ho avuto lo stesso problema ... C'è un jsFiddle here.

Si noti che la modifica di line a diagonal lo farà funzionare.

+0

Il mio suggerimento sarebbe quello di pubblicare il codice da jsFiddle qui perché non è sempre affidabile e attivo. Quindi la risposta specifica sarà disponibile in questa risposta senza dover accedere a un sito Web esterno. – Taryn

+1

@mobeets Devi passare l'input corretto a 'line()'. Puoi fare questo wrap 'line()' su un'altra funzione come recomend @ elusive-code o ritornare a 'line()' i valori di input corretti come puoi vedere su [my mod of your fiddle] (http: // jsfiddle. net/qsEbd/213 /). – jkutianski

2

Forse incapsulare la funzione di diagonale e la modifica dei suoi parametri potrebbe funzionare per voi:

var diagonal = d3.svg.diagonal(); 
var new_diagonal = function (obj, a, b) { 
    //Here you may change the reference a bit. 
    var nobj = { 
     source : { 
      x: obj.source.x, 
      y: obj.source.y 
     }, 
     target : { 
      x: obj.target.x, 
      y: obj.target.y 
     } 
    } 
    return diagonal.apply(this, [nobj, a, b]); 
} 
var link= svg.selectAll("path") 
    .data(links) 
    .enter().append("path") 
    .attr("d",new_diagonal) 
    .attr("class", ".link") 
    .attr("stroke", "black") 
    .attr("stroke-width", "2px") 
    .attr("shape-rendering", "auto") 
    .attr("fill", "none"); 
21

domanda è piuttosto datato, ma dal momento che non vedo una risposta e qualcuno potrebbe trovarsi ad affrontare lo stesso problema, qui è .

Il motivo semplice sostituzione di diagonale con linea non funziona è perché d3.svg.line e d3.svg.diagonal ritorno diversi risultati:

  • d3. svg.diagonal restituisce la funzione che accetta il dato e il relativo indice e lo trasforma in percorso utilizzando la proiezione . In altre parole, diagonal.projection determina come la funzione otterrà le coordinate dei punti dal dato fornito.
  • d3.svg.line restituisce una funzione che accetta una serie di punti della linea e la trasforma in percorso. Metodi line.x e line.y determinano come coordinate del punto recuperato i dal singolo elemento dell'array in dotazione

D3 SVG-Shapes reference

SVG Paths and D3.js

Quindi non è possibile utilizzare risultato della d3.svg.linea direttamente nelle selezioni d3 (almeno quando si desidera disegnare più righe).

È necessario avvolgerlo in un'altra funzione come questa:

var line = d3.svg.line() 
       .x(function(point) { return point.lx; }) 
       .y(function(point) { return point.ly; }); 

function lineData(d){ 
    // i'm assuming here that supplied datum 
    // is a link between 'source' and 'target' 
    var points = [ 
     {lx: d.source.x, ly: d.source.y}, 
     {lx: d.target.x, ly: d.target.y} 
    ]; 
    return line(points); 
} 

// usage: 
var link= svg.selectAll("path") 
    .data(links) 
    .enter().append("path") 
    .attr("d",lineData) 
    .attr("class", ".link") 
    .attr("stroke", "black") 
    .attr("stroke-width", "2px") 
    .attr("shape-rendering", "auto") 
    .attr("fill", "none"); 

Ecco la versione di jsFiddle lavorare mobeets Inviato: jsFiddle

+1

Penso che '.attr (" d ", funzione (d) {linea di ritorno ([{lx: d.target.x, ly: d.target.y}, {lx: d.source.x, ly : d.source.y}]);}); ' è un modo migliore di farlo invece di racchiudere' line() 'in una funzione globale. – jkutianski

+0

Punti extra per fornire una sostituzione drop-in per 'diagonal' per questo contesto, elusive-code, piuttosto che fornire una soluzione alternativa. È più di un anno e mezzo dopo, e come hai detto tu, "qualcuno potrebbe affrontare lo stesso problema" (io). Non avevo trovato questa soluzione in una forma così semplice da nessun'altra parte e ci sono sicuramente un numero di persone che lo desiderano un giorno. – Mars