2015-06-02 15 views
7

Sto cercando di unire due esempi di Mike: Zoomable Circle Packing + Automatic Text Sizing.Cerchio zoomable Imballaggio con ridimensionamento automatico del testo in D3.js

Funziona quando inizialmente visualizzato al livello superiore. Tuttavia, se si ingrandisce al livello successivo, i caratteri non vengono ridimensionati correttamente.

Non sono sicuro di dover modificare la trasformazione o modificare la parte che calcola la dimensione del carattere.

Ecco la mia codepen: http://codepen.io/anon/pen/GJWqrL

var circleFill = function(d) { 
    if (d['color']) { 
     return d.color; 
    } else { 
     return d.children ? color(d.depth) : '#FFF'; 
    } 
} 

var calculateTextFontSize = function(d) { 
    return Math.min(2 * d.r, (2 * d.r - 8)/this.getComputedTextLength() * 11) + "px"; 
} 

var margin = 20, 
    diameter = 960; 

var color = d3.scale.linear() 
    .domain([-1, 18]) 
    .range(["hsl(0,0%,100%)", "hsl(228,30%,40%)"]) 
    .interpolate(d3.interpolateHcl); 

var pack = d3.layout.pack() 
    .padding(2) 
    .size([diameter - margin, diameter - margin]) 
    .value(function(d) { 
     return d.size; 
    }) 

var svg = d3.select("body").append("svg") 
    .attr("width", window.innerWidth) 
    .attr("height", window.innerHeight) 
    .append("g") 
    .attr("transform", "translate(" + diameter/2 + "," + diameter/2 + ")"); 

var focus = root, 
    nodes = pack.nodes(root), 
    view; 

var circle = svg.selectAll("circle") 
    .data(nodes) 
    .enter().append("circle") 
    .attr("class", function(d) { 
     return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root"; 
    }) 
    .style("fill", circleFill) 
    .on("click", function(d) { 
     if (focus !== d) zoom(d), d3.event.stopPropagation(); 
    }); 

circle.append("svg:title") 
    .text(function(d) { 
     return d.name; 
    }) 

var text = svg.selectAll("text") 
    .data(nodes) 
    .enter().append("text") 
    .attr("class", "label") 
    .style("fill-opacity", function(d) { 
     return d.parent === root ? 1 : 0; 
    }) 
    .style("display", function(d) { 
     return d.parent === root ? null : "none"; 
    }) 
    .text(function(d) { 
     return d.name; 
    }) 
    .style("font-size", calculateTextFontSize) 
    .attr("dy", ".35em"); 

var node = svg.selectAll("circle,text"); 

d3.select("body") 
    .style("background", color(-1)) 
    .on("click", function() { 
     zoom(root); 
    }); 

zoomTo([root.x, root.y, root.r * 2 + margin]); 

function zoom(d) { 
    var focus0 = focus; 
    focus = d; 

    var transition = d3.transition() 
     .duration(d3.event.altKey ? 7500 : 750) 
     .tween("zoom", function(d) { 
      var i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2 + margin]); 
      return function(t) { 
       zoomTo(i(t)); 
      }; 
     }); 

    transition.selectAll("text") 
     .filter(function(d) { 
      return d.parent === focus || this.style.display === "inline"; 
     }) 
     .style("fill-opacity", function(d) { 
      return d.parent === focus ? 1 : 0; 
     }) 
     .each("start", function(d) { 
      if (d.parent === focus) this.style.display = "inline"; 
     }) 
     .each("end", function(d) { 
      if (d.parent !== focus) this.style.display = "none"; 
     }); 
} 

function zoomTo(v) { 
    var k = diameter/v[2]; 
    view = v; 
    node.attr("transform", function(d) { 
     return "translate(" + (d.x - v[0]) * k + "," + (d.y - v[1]) * k + ")"; 
    }); 
    circle.attr("r", function(d) { 
     return d.r * k; 
    }); 
} 

d3.select(self.frameElement).style("height", diameter + "px"); 

Cliccando il più grande sub-cerchio nel cerchio "vis" illustra il problema.

https://dl.dropboxusercontent.com/u/3040414/vis-circle.png

+1

Sembra a me come sta funzionando bene per tutte le sezioni tranne vis al livello più alto. Anche i bambini di vista sono ok. C'è qualcosa di diverso in vis? – couchand

+0

Alcuni dei cerchi secondari sono visualizzati correttamente, ma fai clic su alcuni dei cerchi secondari nella cerchia "Vis" per visualizzare il problema. https://dl.dropboxusercontent.com/u/3040414/vis-circle.png –

+0

Anche nei tuoi dati non c'è il cerchio "Vis" ... se cerco il tuo JS non c'è "Vis". Di cosa stai parlando? –

risposta

3

Prima danno un id al cerchio, qui sto dando nome di testo come ID cerchio in modo che io possa collegare il testo e la sua cerchia tramite nome di testo.

var circle = svg.selectAll("circle") 
    .data(nodes) 
    .enter().append("circle") 
    .attr("class", function(d) { 
    return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root"; 
    }) 
    .style("fill", circleFill) 
    .attr("r", function(d) { 
    return d.r; 
    }) 
    .attr("id", function(d) { 
    return d.name;//setting text name as the ID 
    }) 
    .on("click", function(d) { 
    if (focus !== d) zoom(d), d3.event.stopPropagation(); 
    }); 

In sede di transizione completa di zoom(d) function (cioè quando si fa clic su un cerchio e si ingrandisce) aggiunge una funzione di timeout che si ricalcola la dimensione dei caratteri del testo in base alla zoom.

setTimeout(function() { 
    d3.selectAll("text").filter(function(d) { 
    return d.parent === focus || this.style.display === "inline"; 
    }).style("font-size", calculateTextFontSize);//calculate the font 
}, 500) 

La vostra funzione calculateTextFontSize sarà simile a questa (sto usando il raggio reale DOM per calcolare la dimensione del carattere):

var calculateTextFontSize = function(d) { 
    var id = d3.select(this).text(); 
    var radius = 0; 
    if (d.fontsize){ 
    //if fontsize is already calculated use that. 
    return d.fontsize; 
    } 
    if (!d.computed) { 
    //if computed not present get & store the getComputedTextLength() of the text field 
    d.computed = this.getComputedTextLength(); 
    if(d.computed != 0){ 
     //if computed is not 0 then get the visual radius of DOM 
     var r = d3.selectAll("#" + id).attr("r"); 
     //if radius present in DOM use that 
     if (r) { 
     radius = r; 
     } 
     //calculate the font size and store it in object for future 
     d.fontsize = (2 * radius - 8)/d.computed * 24 + "px"; 
     return d.fontsize; 
    } 
    } 
} 

codice di lavoro here

+0

Grazie per la risposta. Uso interessante del timeout. Ho contrassegnato questa risposta come corretta poiché funziona con i dati di esempio di flare che ho fornito. Sfortunatamente non funziona al 100% per i miei dati reali, che è più grande. Sospetto che abbia a che fare con i tempi. –

+0

se non hai alcun problema nel condividere il tuo set di dati puoi renderlo disponibile in sintesi ti darò un'occhiata. integrandolo con l'esempio corrente. – Cyril

+0

@Cyril Grazie mille, è stato un grande aiuto .. C'è ancora una cosa che voglio fare, volevo mostrare le immagini nei nodi foglia, sto passando quella dai dati di root ma come posso visualizzarla il cerchio? – void

1

Ho anche avuto lo stesso problema come voi e ho provato questo e funziona per me.

D3.js Auto font-sizing based on nodes individual radius/diameter

+0

Sto provando ad applicarlo, tuttavia, il riquadro di delimitazione per i miei nodi di livello superiore è 0 , 0 che rende la scala = Infinito. Hai un codice funzionante da qualche parte online (github, jsfiddle, codepen)? –