2013-11-21 20 views
8

In che modo D3.js può regolare automaticamente la dimensione dei caratteri per ciascun nodo in base al raggio/diametro individuale?D3.js Ridimensionamento automatico dei caratteri in base al raggio/diametro individuale dei nodi

Io uso uno stile che permette di aumento automatico insize

node.append("text") 
     .attr("dy", ".3em") 
     .style("text-anchor", "middle") 
     .text(function(d) { return d.className.substring(0, d.r/3); }) 
     .style("font-size", "10px") // initial guess 
//This is what gives it increased size... 
     .style("font-size", function(d) { return (2 * d.r - 10)/this.getComputedTextLength() * 10 + "px"; }) 

; * 10 + "px"; })

Questo effetto rimuove il testo dai nodi più piccoli. Ho anche una funzione di zoom che posso aumentare un punto che in origine copre 12 px per coprire l'intero schermo.

.call(d3.behavior.zoom().scaleExtent([1, 200]).on("zoom", zoom)) 

C'è un modo per formattare automaticamente nodo-font singolarmente; scrivere in dimensioni appropriate in modo che quando si ingrandisce il carattere del nodo chiamato apparirà proporzionato alla dimensione del nodo rispetto a una singola dimensione carattere adatta a tutti?

enter image description here

Il destro elenca Circles: NOME (SIZE)
Mi piacerebbe un esempi di lavoro da cui imparare. Quindi, alla dimensione dell'immagine, il piccolo punto verde a nord del cerchio guida accanto alla P avrebbe parole nere illeggibili fino a quando non si ingrandisce per vedere cosa è scritto sul cerchio. L'obiettivo è quello di avere un font proporzionato leggibile quando viene ingrandito ..?

risposta

13

È possibile farlo impostando dinamicamente la dimensione del testo in base alle dimensioni del contenitore. Per fare questo, devi aggiungere il testo, ottenere il riquadro di delimitazione, ottenere il riquadro di delimitazione dell'elemento contenitore e ricavare la dimensione del carattere corretta in base alla dimensione del carattere corrente e a quelle caselle di delimitazione.

Il codice sarebbe simile a questo.

// ... 
    .append("text") 
    .text("text") 
    .style("font-size", "1px") 
    .each(getSize) 
    .style("font-size", function(d) { return d.scale + "px"; }); 

function getSize(d) { 
    var bbox = this.getBBox(), 
     cbbox = this.parentNode.getBBox(), 
     scale = Math.min(cbbox.width/bbox.width, cbbox.height/bbox.height); 
    d.scale = scale; 
} 
+0

Opere eccellente ... C'è una semplice correzione per ottenere spazio prima e dopo la parola o ridurre la dimensione della parola a pochi passi più piccoli? – Understood

+0

È tutto nel modo in cui 'cscale' è determinato - è possibile aggiungere un fattore lì o aggiungere un offset costante a' bbox.width' per uno spazio. –

+0

potrebbe essere questo getBBox() creare un problema su FF !!! –

1

Grazie alla OP & risposta accettata (entrambi upvoted); Ho finito per farlo un po 'diversamente perché il mio testo era sfalsato all'interno di un cerchio, piuttosto che correre lungo il suo diametro. Il nodo di testo ha un valore dy per spostarlo verso l'alto o verso il basso all'interno del cerchio, e io lo uso per capire l'accordo che devo misurare sul cerchio per fare in modo che il mio testo si adatti automaticamente allo spostamento di altezza desiderato. Inoltre, è servito meglio alle mie esigenze per archiviare la dimensione calcolata in un attributo di dati sull'elemento di testo, piuttosto che modificare i dati di origine. Ho pensato che potrebbe essere utile a chiunque si imbatta in questo in futuro.

jsfiddle

function appendScaledText(parentGroup, textVal, dyShift) { 
    parentGroup 
    .append("text") 
    .attr("dy", dyShift) 
    .attr("text-anchor", "middle") 
    .attr("dominant-baseline", "central") 
    .attr("font-family", "sans-serif") 
    .attr("fill", "white") 
    .text(textVal) 
    .style("font-size", "1px") 
    .each(getSize) 
    .style("font-size", function() { 
     return d3.select(this).attr("data-scale") + "px"; 
    }); 
} 

function getSize() { 
    var d3text = d3.select(this); 
    var circ = d3.select(this.previousElementSibling); // in other cases could be parentElement or nextElementSibling 
    var radius = Number(circ.attr("r")); 
    var offset = Number(d3text.attr("dy")); 
    var textWidth = this.getComputedTextLength(); // TODO: this could be bounding box instead 
    var availWidth = chordWidth(Math.abs(offset), radius); // TODO: could adjust based on ratio of dy to radius 
    availWidth = availWidth * 0.85; // fixed 15% 'padding' for now, could be more dynamic/precise based on above TODOs 
    d3text.attr("data-scale", availWidth/textWidth); // sets the data attribute, which is read in the next step 
} 

function chordWidth(dFromCenter, radius) { 
    if (dFromCenter > radius) return Number.NaN; 
    if (dFromCenter === radius) return 0; 
    if (dFromCenter === 0) return radius * 2; 

    // a^2 + b^2 = c^2 
    var a = dFromCenter; 
    var c = radius; 
    var b = Math.sqrt(Math.pow(c, 2) - Math.pow(a, 2)); // 1/2 of chord length 

    return b * 2; 
} 
Problemi correlati