私は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
]
}
のように見えます。