我是新來的d3.js,我目前被困在一個問題上。我正在使用強制有向圖來顯示我的數據關係。這應該允許用戶將新節點添加到現有圖形並繪製2個或更多節點之間的關係鏈接。我的警告是我的數據正從ajax調用中填充,我將其分配給一個變量並將其傳遞給生成該圖的函數。數據的初始負載很好,一切都正常顯示。我的問題是當用戶點擊一個按鈕來添加新節點。在這個動作中,我正在調用ajax來檢索新的未鏈接關係以添加到圖中。我將新檢索的數據添加到節點數組,並嘗試重新繪製整個圖形。但是,我在x & y屬性被設置爲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();
};
這是我怎麼設置我的圖表。
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數據看起來像這樣
{
"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
]
}
我希望有人與更多的d3.js經驗可以點我在正確的方向。