2017-01-25 1 views
4

Ich mache ein interaktives Blasendiagramm und ich arbeite an der Funktionalität, um die Daten in zwei Gruppen zu teilen, die sich auf die gegenüberliegenden Seiten des Bildschirms bewegen. Ich verwende eine Zentrierungskraft für meine Simulation, weil ich denke, dass sie eine viel schönere und konsistentere Darstellung der Daten liefert als die Verwendung von forceX und forceY. Ich habe jedoch Probleme mit der Aufteilung meiner Daten.d3.js: Übergeben Sie die anonyme Funktion als Parameter für die Zentrierungskraft?

Ich hatte die Idee, dass, weil Sie eine anonyme Funktion als Parameter forceX übergeben können, um zu bestimmen, ob ein Knoten nach links oder rechts bewegt, könnten Sie theoretisch das gleiche für den x-Wert in einer zentrierenden Kraft tun. Mein Center Kraft-Code sieht wie folgt aus:

var forceCenterSplit = d3.forceCenter(function(d) { 
      if (d[splitParameter] >= splitVal) 
       return 3*width/4; 
      else 
       return width/4; 
     }, height/2) 

Zum Vergleich hier ist der Code für die forceX, die das gleiche erreicht:

var forceXsplit = d3.forceX(function(d) { 
       if (d[splitParameter] >= splitVal) 
        return 3*width/4; 
       else 
        return width/4; 
      }).strength(.05);  

Leider ist die Konsole sagt „Unerwarteter Wert NaN cx Parsen Attribut." wenn ich die Zentrierungskraft starte und alle Daten auf cx = 0 (den Standardwert) schiebe.

Fehle ich etwas Grundlegendes hier? Können Sie keine anonyme Funktion als Parameter für die Zentrierungskraft übergeben? Wenn nicht, gibt es einen besseren Weg, dies zu tun?

Danke!

Start state

After split

// nicer looking splitting forces that use forceCenter 
     var forceCenterCombine = d3.forceCenter(width/2, height/2); 

     var forceCenterSplit = d3.forceCenter(function(d) { 
      if (d[splitParameter] >= splitVal) 
       return 3*width/4; 
      else 
       return width/4; 
     }, height/2); 

     // simple splitting forces that only use forceX 
     var forceXSplit = d3.forceX(function(d) { 
      if (d[splitParameter] >= splitVal) 
       return 3*width/4; 
      else 
       return width/4; 
     }).strength(.05); 

     var forceXCombine = d3.forceX(width/2).strength(.05); 

     // collision force to stop the bubbles from hitting each other 
     var forceCollide = d3.forceCollide(function(d){ 
      console.log("forceCollide"); 
      return radiusScale(d[radiusParam]) + 1; 
     }).strength(.75) 

     // This code is for the simulation that combines all the forces 
     var simulation = d3.forceSimulation() 
      .force("center", forceCenterCombine) 
      .force("collide", forceCollide) 
      .on('end', function(){console.log("Simulation ended!");}); 

     function ticked() { 
      circles 
       .attr("cx", function(d){ 
        return d.x; 
       }) 
       .attr("cy", function(d){ 
        return d.y; 
       }) 
     } 

var splitFlag = false; 

     // dynamically divide the bubbles into two (or probably more later on) groups 
     $scope.split = function() { 
      // split them apart 
      if (!splitFlag){ 
       console.log("splitForce"); 
       simulation.force("center", forceXSplit) 
        .force("y", d3.forceY(height/2).strength(.05)) 
        .alphaTarget(.25) 
        .restart(); 
       splitFlag = true; 
      } 
      // bring them back together 
      else { 
       console.log("combineForce"); 
       simulation.force("center", forceCenterCombine) 
        .alphaTarget(.25) 
        .restart(); 
       splitFlag = false; 
      } 
     }; 

enter image description here

+1

Aufgrund der Natur von 'd3.forceCenter' ist das nicht möglich. Die API sagt: * "Die Zentrierkraft übersetzt Knoten gleichmäßig, so dass die mittlere Position von ** allen Knoten ** (der Massenschwerpunkt, wenn alle Knoten gleiches Gewicht haben) an der gegebenen Position ⟨x, y⟩ liegt." *, Betonung meiner. Somit ist hier kein Platz für eine Accessor-Funktion. 'forceX' und' forceY' hingegen setzen * den Koordinaten-Accessor auf die angegebene Zahl oder ** function ** "* (betonung wieder meine). –

+0

Ah, das ist nervig.Wie ich im Originalbeitrag erwähnt habe, zeigen forceX und forceY eine wesentlich harmlosere Darstellung als das forceCenter - Knoten kollidieren endlos, bleiben in Clustern anderer Knoten stecken, bewegen sich nicht so weit, wie sie sollen, usw. Ich nehme an der einzige Weg, wie ich zwei verschiedene Massenzentren haben könnte, wäre, verschiedene Simulationen zu haben, die auf zwei verschiedenen Knotengruppen laufen? Danke für die Antwort von der Art und Weise –

+1

Aber, wenn Sie 2 Simulationen haben, wie würden Sie 'kollidieren' verwenden, um überlappende Knoten zu vermeiden? Es sei denn, die Knoten sind sehr voneinander getrennt. –

Antwort

2

Leider scheint die Antwort kein zu sein.

Aufgrund der Natur von d3.forceCenter, das ("eine anonyme Funktion als Parameter übergeben") ist nicht möglich. Die API sagt:

Die Zentrierkraft Knoten einheitlich übersetzt, so dass die mittlere Position des alle Knoten (das Zentrum der Masse, wenn alle Knoten der gleiche Gewicht haben) an der gegebenen Position ⟨x ist, y⟩. (Hervorhebung von mir)

Somit gibt es hier keinen Platz für eine Accessor-Funktion. forceXforceY und, auf der anderen Seite ...

eingestellt den Accessor auf die angegebene Anzahl Koordinate oder Funktion. (Betonung wieder meine)

... und kann Ihnen am besten passen.

Verwandte Themen