データベースからクライアント側に流れ込む処理済みデータの連続ストリームがあり、そこで 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);
}
エラー メッセージは表示されません。それはただのびくびくしたグラフ遷移です。グラフの元の構成を保持し、ノードの半径を既存の位置で更新する必要があります。スムーズな体験をしたい。