2015-06-02 8 views
7

Ich versuche zwei von Mikes Beispielen zusammenzuführen: Zoomable Circle Packing + Automatic Text Sizing.Zoomable Circle Packing mit automatischer Textanpassung in D3.js

Es funktioniert, wenn zunächst auf der obersten Ebene angezeigt wird. Wenn Sie jedoch auf die nächste Ebene zoomen, werden die Schriftarten nicht korrekt sortiert.

Ich bin mir nicht sicher, ob ich die Transformation ändern oder den Teil ändern muss, der die Schriftgröße berechnet.

Hier ist meine 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"); 

Ein Klick auf den größten Teilkreis in der "vis" Kreis veranschaulicht das Problem.

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

+1

Es sieht für mich wie es funktioniert gut für alle Abschnitte außer vis auf der obersten Ebene. Sogar Kinder von Vis sind in Ordnung. Gibt es etwas anderes an vis? – couchand

+0

Einige der Unterkreise erscheinen gut, aber klicken Sie auf einige der Unterkreise im Kreis "Vis", um das Problem zu sehen. https://dl.dropboxusercontent.com/u/3040414/vis-circle.png –

+0

Sogar in Ihren Daten gibt es keinen "Vis" -Kreis ... wenn ich Ihre JS suche, gibt es kein "Vis". Worüber redest du? –

Antwort

3

Zuerst eine ID zu dem Kreis geben, hier bin Text Namen wie der Kreis ID gebe, so dass ich den Text verknüpfen können und sein Kreis über Textnamen.

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(); 
    }); 

Beim Übergang vollständig von zoom(d) function (das heißt, wenn Sie auf einem Kreis klicken und es zoomt) eine Timeout-Funktion hinzufügen, die die Text Schriftgröße auf der Zoom-Basis werden neu berechnet.

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

Ihre calculateTextFontSize Funktion wird wie folgt aussehen (ich die reale DOM Radius bin mit der Schriftgröße berechnen):

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; 
    } 
    } 
} 

Arbeits Code here

+0

Danke für die Antwort. Interessante Verwendung von Timeout. Ich habe diese Antwort als korrekt markiert, da sie mit den von mir bereitgestellten Flare-Sample-Daten arbeitet. Leider funktioniert es nicht 100% für meine tatsächlichen Daten, die größer sind. Ich vermute, es hat mit dem Timing zu tun. –

+0

Wenn Sie bei der Freigabe Ihres Datasets keine Probleme haben, können Sie es auf gist zur Verfügung stellen. Integration mit dem aktuellen Beispiel. – Cyril

+0

@Cyril Vielen Dank, das war eine große Hilfe .. Es gibt noch etwas, was ich tun möchte, ich wollte Bilder in den Blattknoten zeigen, ich übertrage das von den Stammdaten, aber wie kann ich das in anzeigen Der Kreis? – void

1

Ich hatte auch gleiche Problem wie du und ich versuchte dieses und es funktioniert für mich.

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

+0

Ich versuche, dies zu tun, aber die Bounding-Box für meine Top-Level-Knoten ist 0 , 0 was Skala = Unendlichkeit ergibt. Hast du irgendwo einen funktionierenden Code (github, jsfiddle, codepen)? –