2017-01-25 8 views
4

私はインタラクティブなバブルチャートを作成しています。私は、画面の反対側に移動する2つのグループにデータを分割する機能について取り組んでいます。私はシミュレーションのためにセンタリング力を使用しています。なぜなら、それはforceXとforceYを使用するよりもずっと素敵でより一貫性のあるデータ表示を与えると思うからです。しかし、データの分割に問題があります。d3.js:パラメータとして匿名関数をセンタリング力に渡しますか?

匿名関数をforceXに渡してノードが左右に動くかどうかを判断することができるので、理論的には同じことを芯出しの力で行うことができます。マイ中央力コードは次のようになります、コンソールが予期しない値NaNでCXを解析する」と言っている残念ながら

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

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

、ここで同じことを実現FORCEXためのコードがあります属性。"センタリングを実行して、すべてのデータをcx = 0(デフォルト値)にプッシュしています。

ここで基本的なものはありませんか?匿名の関数をセンタリング力のパラメータとして渡すことはできませんか?そうでない場合は、これを行うより良い方法はありますか?

ありがとうございます!

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

「d3.forceCenter」の性質上、これは不可能です。 APIは次のように述べています:「センタリング力はノードを均等に変換して、すべてのノードの平均位置**(すべてのノードが等しい重みを持つ場合の質量の中心)が与えられた位置⟨x、y⟩にある」*私の強調。したがって、アクセサー関数のためのスペースはここにありません。一方、「アクセサーを指定された数に設定するか、** function **」*(強調するもう一度)を実行します。 –

+0

ああ、それは迷惑だ。私が元の記事で述べたように、forceXとforceYはforceCenterよりもはるかに細かい表示をしています - ノードは無限に衝突し、他のノードのクラスタに詰まったり、移動したりしません。 2つの異なる質量中心を持つことができる唯一の方法は、2つの異なるノードセットで異なるシミュレーションを実行することです。 返信ありがとうございました –

+1

しかし、2つのシミュレーションがある場合、重複ノードを避けるために 'collide'をどのように使いますか?ノードが非常に離れている場合を除きます。 –

答えて

2

残念ながら、答えはノーのようです。

非常に性質がd3.forceCenterであるため、("パラメータとして無名関数を渡す")は不可能です。 APIは言う:すべてのノードの平均位置(重心すべてのノードが同じ重みを持っている場合)は、所与の位置⟨x、y⟩になるよう

センタリング力が均一にノードを変換します。

したがって、アクセサー機能のためのスペースはありません。 forceXforceYは、一方...

は、指定された数または機能に座標アクセサを設定しました。 (強調するもう一度)

...あなたに最も適しているかもしれません。

関連する問題