我有一个连续的处理数据流从数据库流入客户端,在客户端我使用 D3 渲染一个力导向图。
经过多次尝试,图表似乎正在更新。基本上,圆半径现在从新数据更新。
然而,每次simulation.nodes(nodes_data) 接收到nodes_data 时,整个图都会重新初始化并最终成为一个跳跃的过渡。
我试过改变不同的 force.alphaTarget 值。
这是我用来初始化模拟的函数。
function simulation_routine(simulation, nodes_data, links_data, width, height){
simulation.nodes(nodes_data);
var link_force = d3.forceLink(links_data)
.id(function(d) {
return d.event_id;
})
.strength(function(d){
prob_value = d.prob_value;
return 2*prob_value;
})
.distance(100);
var charge_force = d3.forceManyBody()
.strength(-100);
var center_force = d3.forceCenter(width / 2, height / 2);
simulation
.force("charge_force", charge_force)
.force("center_force", center_force)
.force("links",link_force)
;
simulation.alphaTarget(0.3).restart();
console.log("Restarted Simulation");
return simulation;
}
这是我用来用新的nodes_data 更新模拟的函数。
function simulation_update(simulation, nodes_data, links_data, node, link){
simulation.nodes(nodes_data);
var link_force = d3.forceLink(links_data)
.id(function(d) {
return d.event_id;
})
.strength(function(d){
prob_value = d.prob_value;
return 2*prob_value;
})
.distance(100);
simulation.force("links", link_force);
simulation.alphaTarget(0.3);
return simulation;
}
这是节点更新功能
function nodes_update(simulation, nodes_data, links_data){
var svg = d3.select("svg");
var g = svg.selectAll(".everything");
var node = g.selectAll(".nodes").selectAll('g');
var link = g.selectAll(".links").selectAll('line');
nodes_routine(node, link, nodes_data, links_data, simulation);
}
function nodes_routine(node, link, nodes_data, links_data, simulation){
var t = d3.transition().duration(750);
node = node.data(nodes_data, function(d){return d.event_id;});
node.exit().remove();
var newNodes = node.enter().append("g");
node = newNodes
.attr('id',function(d){
return "node_id_"+d.event_id.toString();
})
.merge(node)
;
newNodes.append("circle")
.attr("r", function(d){
return d.event_radius-0.75;
})
.style("fill", function(d, i) {
return "url(#grad" + i + ")";
})
.on('mouseover.fade', fade(0.1))
.on('mouseover', function(d){
mouseover_event(d.event_name);
})
.on('mouseout.fade', fade(1))
;
node.select("circle")
.attr("r", function(d) {
return d.event_radius;
})
.style("fill", function(d, i) {
return "url(#grad" + i + ")";
});
newNodes.append("text")
.text(function(d) {
return d.event_name.toUpperCase();
})
.attr('dy', "0.35em")
.attr("dx", function(d) {
return d.event_radius+5||min_base_radius+5;}
)
.attr('fill','maroon')
;
newNodes.append("title")
.text(function(d) { return d.event_name; });
// Find connected nodes
const linkedByIndex = {};
links_data.forEach(d => {
linkedByIndex[`${d.source.index},${d.target.index}`] = 1;
});
//add drag capabilities
var drag_handler = d3.drag()
.on("start", drag_start)
.on("drag", drag_drag)
.on("end", drag_end);
drag_handler(node);
function fade(opacity) {
return d => {
node.style('stroke-opacity', function (o) {
const thisOpacity = isConnected(d, o) ? 1 : opacity;
this.setAttribute('fill-opacity', thisOpacity);
return thisOpacity;
});
link.style('stroke-opacity', o => (o.source === d || o.target === d ? 1 : opacity));
link.attr("marker-end", function(o) {
return opacity === 1 || o.source === d || o.target === d
? 'url(#end-arrow)' : 'url(#end-arrow-fade)';
});
};
}
function isConnected(a, b) {
return linkedByIndex[`${a.index},${b.index}`] || linkedByIndex[`${b.index},${a.index}`] || a.index === b.index;
}
//Drag functions
//d is the node
function drag_start(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
//make sure you can't drag the circle outside the box
function drag_drag(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function drag_end(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
return node;
}
这是用于更新链接的功能
function links_routine(link, links_data){
link = link.data(links_data);
link.exit().remove();
var newLinks = link.enter().append("line");
link = newLinks
.attr("stroke-width", 2)
.attr("stroke-dasharray", function(d){
if(d.exists){
return 0;
}else{
return 5;
}
})
.style("stroke", linkColour)
.attr("marker-end", "url(#end-arrow)")
.merge(link);
function linkColour(d){
return "black";
}
return link;
}
function links_update(links_data){
var svg = d3.select("svg");
var g = svg.selectAll(".everything");
var link = g.selectAll(".links").selectAll('line');
links_routine(link, links_data);
}
我没有收到任何错误消息。这只是一个跳跃的图形转换。我希望图表保留其原始配置并更新现有位置的节点半径。我想有一个流畅的体验。