2017-08-03 16 views
0

私はd3.jsを初めて使用していますが、現在問題が残っています。私は強制的なグラフを使って自分のデータの関係を表示しています。これにより、ユーザーは既存のグラフに新しいノードを追加し、2つ以上のノード間に関係リンクを描くことができます。私の注意点は、私のデータは、私が変数に代入し、グラフを生成する関数に渡すajax呼び出しからデータが取り込まれていることです。データの初期読み込みがうまく機能し、すべてが適切に表示されます。私の問題は、ユーザーがボタンをクリックして新しいノードを追加したときです。そのアクションでは、グラフに追加する新しいリンクされていない関係を取得するためにajax呼び出しを行います。新しい検索データをノード配列に追加し、グラフ全体を再描画しようとします。しかし、x &の属性がNaNに設定されているとエラーが発生します。私はこれがforceSimulationがそれらの値をどのように割り当てるかに関係していると信じています。私は、simulation.reset()を使用しようとしましたが、成功しませんでした。d3 v4有向グラフを強制的に新しいノードを追加する

ここに私のコードの一部があります。

既存のすべての関係を取得するための初期呼び出し。

function getGraphData(){ 
$.ajax({ 
    url: [link to rest uri], 
    type: 'GET', 
    contentType: 'application/json' 
}).done(function(response){ 
    drawGraph(response); 
}) 
}; 

これはこれは私が私のグラフを設定していどのような新しい非連動関係

function getNewRelationshipData(){ 
    $.ajax({ 
    url: [link to second rest uri], 
    type: 'GET' 
    contentType: 'application/json' 
    }).done(function(response){ 
    var newNode = response.nodes; 
    updateGraph(); 
    //---same as getGraphData() 
    $.ajax({ 
     url: [link to rest uri], 
     type: 'GET', 
     contentType: 'application/json' 
    }).done(function(response){ 
     var graphData = response; 
     graphData.nodes[graphData.nodes.length] = newNode[0] 
     //assigned relationship data to graphData and appended the newNode value 
     drawGraph(graphData); 
    }) 
    }); 
}; 

function updateGraph(){ 
// clears out old graph 
d3.selectAll("svg > *").remove(); 
}; 

を取得するための私の2番目の呼び出しです。

function drawGraph(relationships){ 
var svg = d3.select("svg"), 
    w = +svg.attr("width"), 
    h = +svg.attr("height); 
var g = svg.append("g"); 
var color = d3.scaleOrdinal(d3.schemeCategory20); 

var simulation = d3.forceSimulation() 
    .force("link", d3.forceLink().id(function(d) { return d.id; }).distance(60)) 
    .force("charge", d3.forceManyBody()) 
    .force("center", d3.forceCenter(w/2, h/2)) 
    .force("attraceForce",d3.forceManyBody().strength(-900)); 

var opacity = 0.05; 
var transitionPeriod = 500; 
var graph = relationships; 
var link = g.selectAll("line") 
.data(graph.links) 
    .enter().append("line") 
    .style("stroke-width", function(d) { return d.value; }) 
    .style("stroke", "#999") 
    .style("opacity", "1") 
    .attr("group",function(d) {return d.group; }) 
    .on("click", function(d) { 
     // This is to toggle visibility - need to do it on the nodes, links & text 
     d3.selectAll("line:not([group='"+d.group+"'])") 
     .transition().duration(transitionPeriod).style("opacity", function() { 
      var currentDisplay = d3.select(this).style("opacity"); 
      currentDisplay = currentDisplay == "1" ? opacity : "1"; 
      return currentDisplay; 
     }); 
     d3.selectAll("circle:not([group='"+d.group+"'])") 
     .transition().duration(transitionPeriod).style("opacity",function() { 
      var currentDisplay = d3.select(this).style("opacity"); 
      currentDisplay = currentDisplay == "1" ? opacity : "1"; 
      return currentDisplay; 
     }); 
     d3.selectAll("text:not([group='"+d.group+"'])") 
     .transition().duration(transitionPeriod).style("opacity",function() { 
      var currentDisplay = d3.select(this).style("opacity"); 
      currentDisplay = currentDisplay == "1" ? opacity : "1"; 
      return currentDisplay; 
     }); 

    }) 

    var node = g 
    .attr("class", "nodes") 
    .selectAll("circle") 
    .data(graph.nodes) 
    .enter().append("circle") 
    .attr("r", 14) 
    .attr("fill", function(d) { return color(d.group); }) 
    .call(d3.drag() 
      .on("start", dragstarted) 
      .on("drag", dragged) 
      .on("end", dragended)) 

    var images = g.selectAll("image") 
    .data(graph.nodes) 
    .enter().append("image") 
    .attr("xlink:href",function(d){ 
     var type = d.type, 
      typeIcon = "", 
     switch(type){ 
     //assigns an image based on the subject type person, address, phone, ect. 
     } 
     return typeIcon; 
    }) 
    // This is the label for each node 
    var text = g.selectAll("text") 
     .data(graph.nodes) 
     .enter().append("text") 
     .attr("dx",12) 
     .attr("dy",".35m") 
     .text(function(d) { return d.id;}) 
     .attr("text-anchor", "middle") 
     .attr("group",function(d) {return d.group;}) ; 

    node.append("title") 
     .text(function(d) { return d.id; }); 

    simulation 
     .nodes(graph.nodes) 
     .on("tick", ticked); 

    simulation.force("link") 
     .links(graph.links); 

    function ticked() { 
    link 
     .attr("x1", function(d) { return d.source.x; }) 
     .attr("y1", function(d) { return d.source.y; }) 
     .attr("x2", function(d) { return d.target.x; }) 
     .attr("y2", function(d) { return d.target.y; }); 

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



//Used to drag the graph round the screen 
function dragstarted(d) { 
    if (!d3.event.active) simulation.alphaTarget(0.3).restart(); 
    d.fx = d.x; 
    d.fy = d.y; 
} 

function dragged(d) { 
    d.fx = d3.event.x; 
    d.fy = d3.event.y; 
} 

function dragended(d) { 
    if (!d3.event.active) simulation.alphaTarget(0); 
    d.fx = null; 
    d.fy = null; 
} 

// This is the zoom handler 
var zoom_handler = d3.zoom() 
    .scaleExtent([1/4, 4]) 
    .on("zoom", zoom_actions); 

//specify what to do when zoom event listener is triggered 
function zoom_actions(){ 
    g.attr("transform", d3.event.transform); 
} 

// initial scaling on the svg container - this means everything in it is scaled as well 
svg.call(zoom_handler) 
.call(zoom_handler.transform, d3.zoomIdentity.scale(0.9,0.9)) 
; 

zoom_handler(svg); 
}; 

そして、私のAjaxのデータは、私はより多くのd3.jsの経験を持つ誰かが正しい方向に私を指すことを願って、この

{ 
"nodes":[ 
    {"id": "1", "group": "1", "type": "person", "name":"Jon Doe"}, 
    {"id": "2", "group": "1", "type": "person", "name":"Jane Doe"} 
    //ect list of ~50 
], 
"links":[ 
    {"source": "1", "target":"2"}, 
    //ect list of ~50 
] 
} 

のように見えます。

答えて

0

他の人が同じ問題を抱えている場合に備えて、私はこれを投稿しています。 drawGraph関数を小さなウィジェットに分割して私の問題を解決しました。

以下を親スコープに移動しました。

var svg = d3.select("svg"), 
     w = +svg.attr("width"), 
     h = +svg.attr("height), 
     node, 
     link; 

var simulation = d3.forceSimulation(nodes) 
    .force("link", d3.forceLink().id(function(d) { return d.id; }).distance(60)) 
    .force("charge", d3.forceManyBody()) 
    .force("center", d3.forceCenter(w/2, h/2)) 
    .force("attraceForce",d3.forceManyBody().strength(-900)); 

var color = d3.scaleOrdinal(d3.schemeCategory20); 

次に、drawGraph関数内で以下の変更を行いました。

function drawGraph(nodes,links){ 
    var g = svg.append("g"); 
    link = g.selectAll(".link").data(links,function(d){ return d.target.id; }) 
    link = link.enter() 
     .append("line") 
     .attr("class","link") 
     .style("stroke-width", function(d) { return d.value; }) 
     .style("stroke", "#999") 

    node = g.selectAll(".node").data(nodes,function(d){ return d.id; }) 
    node = node.enter() 
     .append("g") 
     .attr("class","node") 
     .call(d3.drag() 
      .on("start", dragstarted) 
      .on("drag", dragged) 
      .on("end", dragended)) 
    node.append("circle").attr("r", 14).attr("fill",function(d){return color(d.group);}) 
    node.append("text").attr("dy", -15) 
     .text(function(d){ return d.id; }) 
     .attr("text-anchor","middle") 
     .style("fill", "#555"); 

    node.append("image") 
     .attr("xlink:href",function(d){ 
      var type = d.type, 
      typeIcon = "", 
      switch(type){ 
      //assigns an image based on the subject type person, address, phone, ect. 
      } 
     return typeIcon; 
     }) 
     .attr("x", -8) 
     .attr("y", -8) 
     .attr("height", 16) 
     .attr("width", 16); 

simulation.nodes(nodes).on("tick", ticked); 
simulation.force("link").links(links); 

function zoom_actions(){ 
    g.attr("transform", d3.event.transform); 
}; 

var zoom_handler = d3.zoom() 
    .scaleExtent([1/4, 4]) 
    .on("zoom", zoom_actions); 

svg.call(zoom_handler).call(zoom_handler.transform, d3.zoomIdentity.scale(0.9,0.9)); 

zoom_handler(svg); 

}; 

function ticked() { 
link 
    .attr("x1", function(d) { return d.source.x; }) 
    .attr("y1", function(d) { return d.source.y; }) 
    .attr("x2", function(d) { return d.target.x; }) 
    .attr("y2", function(d) { return d.target.y; }); 

node 
    .attr("transform", function(d) { 
      return "translate("+ d.x + ", " + d.y + ")"; 
     }); 
}; 

function dragstarted(d) { 
    if (!d3.event.active) simulation.alphaTarget(0.3).restart(); 
    d.fx = d.x; 
    d.fy = d.y; 
} 

function dragged(d) { 
    d.fx = d3.event.x; 
    d.fy = d3.event.y; 
} 

function dragended(d) { 
    if (!d3.event.active) simulation.alphaTarget(0); 
    d.fx = null; 
    d.fy = null; 
} 

次に、データを設定しグラフを描画するために使用される次の関数を追加しました。

次に、drawGraphの代わりにformatGraphDataを使用するようにajax呼び出しが更新されました。

は、私は私のcssファイルに次の追加

.links line{ 
stroke: #999; 
} 
.nodes circle{ 
stroke: #fff; 
stroke-width: 1.5px; 
} 
関連する問題