Javascript D3力模拟图,较大数据集的边无法渲染
EDIT:对于那些对大型数据集的效率感兴趣的人来说,公认的答案是有用的,我无论如何都需要实现它。但正如评论中指出的,问题的更直接原因是db没有发送所有用于大型查询的边缘。所以这是一个X Y问题。 我正在使用d3.forceSimulation在浏览器中创建网络图。该图适用于少量边(参见图1)。对于大量边(近似>500),大多数边开始无法渲染(参见图2)。这当然是不希望出现的行为 到目前为止,我已经尝试增加画布的大小,并将更新调整为只在每20个刻度上运行一次。这些更改都没有改善边缘渲染 如果需要,我愿意牺牲性能(例如,较低的帧率)。重要的是,我能够在图形上显示至少1000个节点。我不知道我可以改变哪些参数来实现这一点,因为我不确定到底是什么导致了问题 下面复制了模拟设置代码。我还包括了下面的drawEdge函数,因为我使用了一个非常手动的过程来制作图形定向(绘制三角形),尤其是arctan函数在过去给了我一些问题。因此,可能存在一个问题。 4. 多谢各位 模拟设置:Javascript D3力模拟图,较大数据集的边无法渲染,javascript,d3.js,graph,Javascript,D3.js,Graph,EDIT:对于那些对大型数据集的效率感兴趣的人来说,公认的答案是有用的,我无论如何都需要实现它。但正如评论中指出的,问题的更直接原因是db没有发送所有用于大型查询的边缘。所以这是一个X Y问题。 我正在使用d3.forceSimulation在浏览器中创建网络图。该图适用于少量边(参见图1)。对于大量边(近似>500),大多数边开始无法渲染(参见图2)。这当然是不希望出现的行为 到目前为止,我已经尝试增加画布的大小,并将更新调整为只在每20个刻度上运行一次。这些更改都没有改善边缘渲染 如果需要,
simulation = d3.forceSimulation()
.force("x", d3.forceX(canvasWidth/2))
.force("y", d3.forceY(canvasHeight/2))
.force("collide", d3.forceCollide(nodeRadius+1))
.force("charge", d3.forceManyBody()
.strength(-90))
.force("link", d3.forceLink()
.id(function (d) { return d.id; }))
.on("tick", queue_update);
simulation.nodes(graph.nodes);
simulation.force("link")
.links(graph.edges);
拉杆功能:
function drawLink(l) {
//Setup for line
ctx.beginPath();
ctx.strokeStyle=colors[l.source.court];
//Draw a line between the nodes
ctx.moveTo(l.source.x, l.source.y);
ctx.lineTo(l.target.x, l.target.y);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = "#000";
//Setup for arrow
var line_angle = Math.atan2(l.source.y - l.target.y, l.source.x - l.target.x);
var x_move = Math.cos(line_angle);
var y_move = Math.sin(line_angle);
var on_line_x = l.target.x + x_move*11;
var on_line_y = l.target.y + y_move*11;
var on_line_x_2 = l.target.x + x_move*6;
var on_line_y_2 = l.target.y + y_move*6;
ctx.moveTo(on_line_x, on_line_y);
ctx.lineTo(on_line_x - y_move, on_line_y + x_move);
ctx.lineTo(on_line_x_2, on_line_y_2);
ctx.lineTo(on_line_x + y_move, on_line_y - x_move);
ctx.lineTo(on_line_x, on_line_y);
ctx.stroke();
}
编辑:这里可以找到最小的示例:有一种优化渲染功能(节点和链接)的方法:仅当它们在视口中可见时渲染,并让D3在所有节点上进行充电/碰撞计算 首先,必须定义视口和代表性矩形的宽度/高度:
const WIDTH = 600;
const HEIGHT = 600;
const viewport = {left: 0, top: 0, right: WIDTH, bottom: HEIGHT}
检查链接是否穿过视口的最基本操作是检查源和目标定义的矩形是否与视口相交:
function intersectRect(r1, r2) {
return !(r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top);
}
function drawLink(l) {
const lineRect = {
left: Math.min(l.source.x, l.target.x),
right: Math.max(l.source.x, l.target.x),
top: Math.min(l.source.y, l.target.y),
bottom: Math.max(l.source.y, l.target.y),
}
// draw only if they intersect
if (intersectRect(lineRect, viewport)) {
//Setup for line
ctx.beginPath();
ctx.strokeStyle = "#000";
//Draw a line between the nodes
ctx.moveTo(l.source.x, l.source.y);
ctx.lineTo(l.target.x, l.target.y);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = "#000";
//Setup for arrow
var line_angle = Math.atan2(l.source.y - l.target.y, l.source.x - l.target.x);
var x_move = Math.cos(line_angle);
var y_move = Math.sin(line_angle);
var on_line_x = l.target.x + x_move*11;
var on_line_y = l.target.y + y_move*11;
var on_line_x_2 = l.target.x + x_move*6;
var on_line_y_2 = l.target.y + y_move*6;
ctx.moveTo(on_line_x, on_line_y);
ctx.lineTo(on_line_x - y_move, on_line_y + x_move);
ctx.lineTo(on_line_x_2, on_line_y_2);
ctx.lineTo(on_line_x + y_move, on_line_y - x_move);
ctx.lineTo(on_line_x, on_line_y);
ctx.stroke();
}
}
函数intersectRect(r1,r2){
返回!(r2.左>r1.右| |
r2.右r1.底部||
r2.底部
渲染时,可以对节点执行相同的操作
function drawNode(d) {
if (d.x > 0 && d.x< WIDTH && d.y> 0 && d.y< HEIGHT){
ctx.beginPath();
ctx.fillStyle = "#666";
fill_node(d)
}
}
function fill_node(d) {
if (d.x > 0 && d.x < WIDTH && d.y > 0 && d.y < HEIGHT){
ctx.moveTo(d.x, d.y);
ctx.arc(d.x, d.y, nodeRadius, 0, 2*Math.PI);
ctx.fill();
}
}
功能绘图节点(d){
如果(d.x>0&&d.x0&&d.y0&&d.x0&&d.y
这里可能存在的不仅仅是渲染问题-尝试对充电和碰撞功能进行评论,看看是否有改进。可能需要实现更高性能的自定义布局功能好的,谢谢,我现在就试试。试着设置一个演示该问题的工具。去掉所有花哨的颜色、不同的半径、记号笔、标签等等,把它减到最低限度,。。。让它足以重现你的问题。“这将使其他人更容易帮助你。”科内尔斯特凡纳什评论“充电和碰撞”似乎解决了边缘问题。关于如何实现更高性能的自定义布局功能,您有什么建议吗。@Neil此演示的修改版本将所有未连接的节点都涂成红色,这清楚地显示了您的问题: