11

d3 を使用して強制レイアウトを作成しましたが、うまく機能します。私の初期データは json ファイルから読み込まれ、グラフはこの d3.js の例と同様の手法で描画されます。

ここに画像の説明を入力

グラフが画面に表示されたので、Web ソケット経由で受け取ったデータからその場でノードを追加、更新、および削除する必要があります。add メソッドと remove メソッドは機能していますが、既存のノードのプロパティを更新する正しい方法が見つかりません。

私が行った読書から、データ ソースを変更し、enter() メソッドを使用してチャートを更新するという正しいテクニックを収集しました。

ノードを更新するには、次のことを行っています。

function updateNode(id, word, size, trend, parent_id){    
  var updateNode = nodes.filter(function(d, i) { return d.id == id ? this : null; });
  if(updateNode[0]){   
    updateNode.size = Number(size);
    updateNode.trend = trend;
    nodes[updateNode.index] = updateNode;      
    update();
  }
}

update 関数は、ノードを次のように更新します。

function update(){
  node = vis.selectAll('.node')
  .data(nodes, function(d) {
    return d.id;
  })

  createNewNodes(node.enter());
  node.exit().remove();
  force.start();
}

function createNewNodes(selection){    
  var slct = selection.append('g')
  .attr('class', 'node')
  .call(force.drag);

  slct.append('circle')
    .transition()
    .duration(500)
    .attr('r', function(d) {
      if(d.size){
        return Math.sqrt(sizeScale(d.size)*40);
      }
   })
}

私はこれに対して正しいアプローチを取っていますか?このコードを試してみると、円に半径属性を設定しようとしたときにデータとして取得したノードは、ノード配列の最後のノードです。つまり、単一のノード オブジェクトではなく、階層ノード データを含むものです。

どんなポインタでも大歓迎です、私はこれにあまりにも多くの時間を費やしました:)

4

1 に答える 1

7

必要なポイントは複数あります。あなたの質問から私が得たのは、「再利用可能なパターンをどのように使用するのですか」ということです

この質問に対する簡単な答えは、Mike Bostock によるこの優れたチュートリアルを読むように伝えることです:再利用可能なチャートに向けて

さらに詳しい情報が必要な場合は、次のドキュメントの選択が興味深い場合があります。

ここで、特定の問題に対して私が行う実装のドラフトを次に示します。

function ForceGraph(selector,data) {
   // This is the class that will create a graph

   var _data = data  
   // Local variable representing the forceGraph data 

   svg = d3.select(selector)
      .append('svg')
   // Create the initial svg element and the utilities you will need. 
   // These are the actions that won't be necessary on update. 
   // For example creating the axis objects, your variables, or the svg container

   this.data = function(value) {
      if(!arguments.length) {
         // accessor
         return _data;
      }
      _data = value;
      return this;
      // setter, returns the forceGraph object
   }

   this.draw = function() {
      // draw the force graph using data

      // the method here is to use selections in order to do: 
      // selection.enter().attr(...) // insert new data
      // selection.exit().attr(...) // remove data that is not used anymore
      // selection.attr(...) // 

   }
}

var selector = "#graphId";
var data = {nodes: [...],links: [...]};
myGraph = new ForceGraph(selector,data);
// Create the graph object
// Having myGraph in the global scope makes it easier to call it from a json function or anywhere in the code (even other js files). 
myGraph.draw();
// Draw the graph for the first time 

// wait for something or for x seconds  

var newData = {nodes: [...],links: [...]};
// Get a new data object via json, user input or whatever
myGraph.data(newData);
// Set the graph data to be `newData`
myGraph.draw();
// redraw the graph with `newData`

ご覧のとおり、目的は新しいノードを追加する機能を持たせることではありません。目標は、既存のノードを更新または削除し、新しいノードを追加するだけで、力有向グラフ全体を再描画することです。このように、描画コードは 1 回だけ記述され、その後はデータのみが変更されます。

さらに読むために、この問題に最初に取り組んだとき、この質問は私の金鉱でした: Updating links on a force direct graph from dynamic json data

于 2014-02-12T10:26:34.950 に答える