繁体   English   中英

如何将节点从一个模拟移动到另一个模拟

[英]How to move a node from one simulation to another

我正在尝试将节点从一个forceSimulation移动到另一个,并且我希望节点离开一个集群并转移到另一个集群。 然而,似乎一旦模拟进入稳定模式,力就会停止施加。

这是代码笔:迁移节点

和一个片段:

 const width = 600; const height = 200; var nodes; var simulations; function loaded() { d3.select("svg").attr("width", width).attr("height", height) test(); } function test() { nodes = []; nodes[0] = d3.range(50).map(function() { return { radius: 4, color: "blue" }; }) nodes[1] = d3.range(50).map(function() { return { radius: 4, color: "red" }; }) simulations = [null, null]; update(0); update(1); setTimeout(startMigration, 1000); } function update(index) { simulations[index] = d3.forceSimulation(nodes[index]).force('charge', d3.forceManyBody().strength(10)).force('x', d3.forceX().x(function(d) { return width * (index + 1) / 3; })).force('y', d3.forceY().y(function(d) { return height / 2; })).force('collision', d3.forceCollide().radius(function(d) { return d.radius; })).on('tick', ticked); function ticked() { var u = d3.select('svg').selectAll('.circle' + index).data(nodes[index]).join('circle').attr('class', 'circle' + index).attr('r', function(d) { return d.radius; }).style('fill', function(d) { //return colorScale(d.category); return d.color; }).attr('cx', function(d) { return dx; }).attr('cy', function(d) { return dy; }); } } function startMigration() { setInterval(function() { if (nodes[1].length > 10) { nodes[0].push(nodes[1].pop()); d3.select('svg').selectAll('.circle0').data(nodes[0]); simulations[0].nodes(nodes[0]); d3.select('svg').selectAll('.circle1').data(nodes[1]); simulations[1].nodes(nodes[1]); } }, 250); }
 <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <script src="https://d3js.org/d3.v5.min.js"></script> </head> <body onload="loaded()"> <div id='layout'> <div id='container'> <svg id="graph" /> </div> </div> </body> </html>

nodes是两个数据集的数组,而simulations是两个模拟的数组。

这是我创建forceSimulation的地方:

function update(index) {
    
    simulations[index] = d3.forceSimulation(nodes[index])
        .force('charge', d3.forceManyBody().strength(10))
        .force('x', d3.forceX().x(function(d) {
            return width * (index + 1) / 3;
        }))
        .force('y', d3.forceY().y(function(d) {
            return height/2;
        }))
        .force('collision', d3.forceCollide().radius(function(d) {
            return d.radius;
        }))
        .on('tick', ticked);

    function ticked() {
        var u = d3.select('svg')
            .selectAll('.circle' + index)
            .data(nodes[index])
            .join('circle')
            .attr('class', 'circle' + index)
            .attr('r', function(d) {
                return d.radius;
            })
            .style('fill', function(d) {
                //return colorScale(d.category);
                return d.color;
            })
            .attr('cx', function(d) {
                return d.x;
            })
            .attr('cy', function(d) {
                return d.y;
            });
    }

}

这是在模拟开始将节点从一个模拟移动到另一个模拟后 1000 毫秒开始定期调用的代码:

nodes[0].push(nodes[1].pop());
            
d3.select('svg')
   .selectAll('.circle0')
   .data(nodes[0]);
simulations[0].nodes(nodes[0]);
            
d3.select('svg')
   .selectAll('.circle1')
   .data(nodes[1]);
simulations[1].nodes(nodes[1]);

我希望的效果是节点会离开红色集群并漂移加入蓝色集群。 为什么他们会减速并停下来? 初始加载后等待的时间越长,问题就越严重。 我觉得我不理解有关forceSimulation的一些基本知识。 我本以为他们会尽可能接近他们所属的模拟的( forceXforceY )。

第二个问题是上面代码片段中的所有步骤是否都是必要的。 我是否需要将数据重新分配给两个选择,并将节点重新分配给两个模拟?

在使用simulation.alpha(n).restart()进行拖动操作期间,通过用户交互进行的大量力模拟“重新加热”模拟。 例如,请参阅此可观察对象。

您可以在setMigration function 中无需用户交互来执行此操作,以保持模拟 animation 更新(可以说保持“温暖”),直到足够的圆圈从“红色”移动到“蓝色”。 要添加的两行是:

simulations[0].alpha(0.15).restart();
simulations[1].alpha(0.15).restart();

如果增加 0.15(最多 1),您会发现两种模拟在迁移发生时都更“容易兴奋”。 0.15 对我来说似乎是一种愉快的视觉体验。 这似乎在没有.restart()的情况下也能正常工作,因此您很可能会根据等待启动setMigration的时间来使用它。

对于你的第二个问题 - 因为每个模拟都被初始化为nodes[0]nodes[1]那么d3.select('svg').selectAll('.circleN')可以被注释掉,因为你已经改变了数组内容nodes[0].push(nodes[1].pop())

下面的工作示例:

 const width = 600; const height = 200; var nodes; var simulations; function loaded() { d3.select("svg").attr("width", width).attr("height", height) test(); } function test() { nodes = []; nodes[0] = d3.range(50).map(function() { return { radius: 4, color: "blue" }; }) nodes[1] = d3.range(50).map(function() { return { radius: 4, color: "red" }; }) simulations = [null, null]; update(0); update(1); setTimeout(startMigration, 1000); } function update(index) { simulations[index] = d3.forceSimulation(nodes[index]).force('charge', d3.forceManyBody().strength(10)).force('x', d3.forceX().x(function(d) { return width * (index + 1) / 3; })).force('y', d3.forceY().y(function(d) { return height / 2; })).force('collision', d3.forceCollide().radius(function(d) { return d.radius; })).on('tick', ticked); function ticked() { var u = d3.select('svg').selectAll('.circle' + index).data(nodes[index]).join('circle').attr('class', 'circle' + index).attr('r', function(d) { return d.radius; }).style('fill', function(d) { //return colorScale(d.category); return d.color; }).attr('cx', function(d) { return dx; }).attr('cy', function(d) { return dy; }); } } function startMigration() { setInterval(function() { if (nodes[1].length > 10) { nodes[0].push(nodes[1].pop()); //d3.select('svg') //.selectAll('.circle0') //.data(nodes[0]); simulations[0].nodes(nodes[0]); //d3.select('svg') //.selectAll('.circle1') //.data(nodes[1]); simulations[1].nodes(nodes[1]); // reheat the simulations simulations[0].alpha(0.15).restart(); simulations[1].alpha(0.15).restart(); } }, 250); }
 <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <script src="https://d3js.org/d3.v5.min.js"></script> </head> <body onload="loaded()"> <div id='layout'> <div id='container'> <svg id="graph" /> </div> </div> </body> </html>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM