2013-02-10 5 views
10

Ich versuche, mich um d3 Pack Layout (http://bl.ocks.org/4063530).Aktualisieren eines Layout.Pack in d3.js

Ich habe das grundlegende Layout funktioniert, aber ich möchte es mit neuen Daten aktualisieren. d. h. neue Daten sammeln, an das aktuelle layout.pack binden und entsprechend aktualisieren (update/exit/enter).

sind Meine Versuche, hier (http://jsfiddle.net/emepyc/n4xk8/14/):

var bPack = function(vis) { 
    var pack = d3.layout.pack() 
    .size([400,400]) 
    .value(function(d) {return d.time}); 

    var node = vis.data([data]) 
    .selectAll("g.node") 
    .data(pack.nodes) 
    .enter() 
    .append("g") 
    .attr("class", function(d) { return d.children ? "node" : "leaf node"; }) 
    .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); 

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

    node.filter(function(d) { return !d.children; }).append("text") 
    .attr("text-anchor", "middle") 
    .attr("dy", ".3em") 
    .text(function(d) { return d.analysis_id }); 

    bPack.update = function(new_data) { 
     console.log("UPDATE"); 

     node 
     .data([new_data]) 
     .selectAll("g.node") 
     .data(pack.nodes); 

     node 
     .transition() 
     .duration(1000) 
     .attr("class", function(d) { return d.children ? "node" : "leaf node" }) 
    .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")" }); 

     node.selectAll("circle") 
     .data(new_data) 
     .transition() 
    .duration(1000) 
    .attr("r", function(d) { return d.r; }); 

    }; 

Spezifische Fragen ...

Wie binde ich die Daten? (Da die Daten keine komplexe Struktur und kein Array von Daten sind)

Wie können neue Knoten/Blätter zum Layout hinzugefügt werden? Und alte entfernt?

Zeiger zu einem Arbeitsbeispiel würden sehr geschätzt werden.

+0

Ich weiß, dass es eine Weile her ist, seit Sie die Frage gestellt haben, aber könnten Sie vielleicht meine Lösung überprüfen? Ich bin neugierig, ob es die richtige Antwort für Ihre Dilemmata ist. Und vielleicht sind andere daran interessiert, wie Ihre Frage gelöst wird, wenn sie gelöst ist ... :) – VividD

+0

Ja, die Antwort ist, das Pack-Layout die ganze Arbeit für Sie erledigen zu lassen. Dies war nicht offensichtlich, als ich anfing, daran zu arbeiten, aber ich fand die Lösung in einem anderen Beispiel (Aktualisierung eines Baumlayouts). Danke für das Arbeitsbeispiel. – emepyc

+0

Froh, dass Sie das Problem gelöst haben. Es ist oft der Fall, dass die endgültige Lösung einfach ist, aber nicht offensichtlich, wenn Sie das Problem zuerst angehen. Ich mag diese Fälle sehr. – VividD

Antwort

10

Arbeitsbeispiel ist here.

Grundsätzlich gibt es einen Code für die Erstladung, bei dem alle Kreise, QuickInfos usw. an den ursprünglichen Stellen erstellt und positioniert werden. Ebenso wird das Layout (Pack) erstellt.

Dann werden bei jedem Tastendruck neue Daten in das Paket geladen und das Paket wird neu berechnet.Der entscheidende Code ist hier:

Hier können Sie binden (Last) jetzt Daten in Pack Layout: (in meinem Beispiel seiner Zufallsdaten, natürlich werden Sie Ihre Daten aus json oder Code oder ähnlichem haben):

pack.value(function(d) { return 1 + 
      Math.floor(Math.random()*501); }); 

Hier wird das neue Layout berechnet:

pack.nodes(data); 

Danach werden Elemente auf neue Positionen übergegangen ist, und dessen Attribute geändert werden, wie Sie bestimmen.

Ich möchte nur betonen, dass ich nicht enter/update/exit Muster oder Transformationen (die Sie in anderen Lösungen sehen können) verwenden, da ich glaube, dass dies unnötige Komplexität für solche Beispiele einführt.

Hier sind einige Bilder mit Übergang in Aktion:

Start:

start

Transition:

transition

Ende:

end

+0

Ich kämpfe mit der Komplexität, die Sie in Ihrem Vorbehalt erwähnt haben, dass Sie nicht die Methoden 'enter()'/'exit()' verwenden. Ich versuche, das zum Laufen zu bringen und frage mich, ob Sie ein wenig über die Nuancen der zusätzlichen Komplexität erklären können. Sehr schätzen Sie Ihr Beispiel hier! – Brian

+0

Wissen Sie, ob dies in D3 v4 möglich ist? Ich sehe nicht die gleiche Funktionalität. – gwg

+0

@gwg Ich habe leider keine Ahnung. Vielleicht würde ich etwas versuchen, aber ehrlich gesagt, habe ich gerade jetzt und in naher Zukunft keine Zeit. Ich weiß, dass es Unterschiede zwischen dem Kreispack D3 v3 und D3 v4 gibt. Laut Murphy Law funktioniert das nicht und ist in D3 v4 nicht möglich und wird in keiner zukünftigen D3-Version möglich sein;). Aber ich werde dich wissen lassen, wenn ich etwas Ähnliches und Nützliches finde. – VividD

3

Relevant, wenn Sie nicht bereits überprüft:
http://bl.ocks.org/3808218 - Allgemeines Update-Muster, ich
http://bl.ocks.org/3808221 - Allgemeines Update-Muster, II
http://bl.ocks.org/3808234 - Allgemeines Update-Muster, III

Dieses Beispiel Geige hat keine Übergänge, aber hier ist mindestens ein Ansatz für die Aktualisierung der Daten.

http://jsfiddle.net/jmKH6/

// VISUALIZATION 
var svg = d3.select("#kk") 
    .append("svg") 
    .attr("width", 500) 
    .attr("height", 600) 
    .attr("class", "pack"); 

var g = svg.append("g") 
    .attr("transform", "translate(2,2)"); 

var pack = d3.layout.pack() 
     .size([400,400]) 
     .value(function(d) {return d.time}); 

function update(data) { 

    var nodeStringLenth = d3.selectAll("g.node").toString().length; 
    if (nodeStringLenth > 0) { 
     d3.selectAll("g.node") 
      .remove(); 
    } 

    var node = g.data([data]).selectAll("g.node") 
      .data(pack.nodes); 

     node.enter() 
      .append("g") 
      .attr("class", function(d) { return d.children ? "node" : "leaf node"; }) 
      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); 

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

     node.filter(function(d) { return !d.children; }).append("text") 
      .attr("text-anchor", "middle") 
      .attr("dy", ".3em") 
      .text(function(d) { return d.analysis_id }); 

     node 
      .exit() 
      .remove(); 
} 


var myData = [data1, data2, data3]; 
update(data1); 
setInterval(function() { 
    update(myData[Math.floor(Math.random() * myData.length)]); // http://stackoverflow.com/questions/4550505/getting-random-value-from-an-array?lq=1 
}, 1500); 
+4

Danke für den Kommentar. Was Sie hier tun, ist, alle Knoten zu entfernen und neue bei jedem Update zu erstellen, nicht was ich will. Ich bin daran interessiert, die Daten zu binden und einen Übergang zu verwenden (oder vielleicht sollte ich einfach die Knoten "an Ort und Stelle" mit den neuen Werten/Knoten ändern, ohne zu binden?). – emepyc

4

hatte ich das gleiche Problem vor kurzem, und kam in den General-Update-Muster und Lektionen. Diese dienten nicht meinem Zweck. Ich hatte ein paar hundert DOM-Elemente in einem Diagramm (ForceLayout), und ich erhielt REST-Daten mit Eigenschaften für jeden einzelnen Knoten zurück. Die Aktualisierung durch erneute Datenbindung führte zur Rekonstruktion des gesamten Graphen, wie Sie als Antwort auf den Vorschlag von mg1075 gesagt haben. Es dauert einige Minuten, bis das DOM in meinem Fall aktualisiert wurde.

Ich habe schließlich eindeutige IDs zu Elementen zugeordnet, die später aktualisiert werden müssen, und ich habe sie mit JQuery ausgewählt. Mein gesamtes Graph-Setup verwendet D3, aber meine Updates nicht. Das fühlt sich schlecht an, aber es funktioniert gut. Anstatt Minuten zu verbrauchen, um die meisten meiner DOM zu zerstören und neu zu erstellen, dauert es ungefähr 3 Sekunden (das Timing für REST-Aufrufe wird weggelassen). Ich sehe keinen Grund, warum in D3 so etwas wie Property-Updates nicht möglich sein sollte.

Vielleicht, wenn Mike Bostock eine remove() - oder richtige Unterauswahlfunktion zur enter() - Auswahl hinzugefügt hat, könnten wir einem reinen D3-Muster folgen, um Aktualisierungen vorzunehmen. Während ich das herausgefunden habe, habe ich versucht, eine Teilmenge von Daten zu binden, die Daten mit den neuen Eigenschaften, und dann Subselektion, um Elemente zu erhalten, die aktualisiert werden müssen, aber es hat nicht funktioniert, aufgrund der begrenzten und spezifischen Art der Eingabe() Auswahl.

+0

Ich denke, Mike sollte nur eine transparente, einfache Möglichkeit zum Übergang zwischen verschiedenen Daten in Kreisen Pack Diagramm hinzufügen. Ich habe eine Grafik, die ich brauche, um einen Drilldown durchzuführen (Doppelklick auf einen Kreis "taucht" runter) und ich bekomme nur eine Stufe vom Server, also jeden Doppelklick Ich fordere vom Server die Daten dieser Ebene an Ich möchte einen schön animierten Drilldown dazu haben. – vsync