我特别感兴趣的是“气泡”的圆形形状以及点到达气泡点(黑色箭头)的流体动力学压缩.
我的想法是通过.fx和.fy(黑点)创建(三个)固定节点,并将所有其他节点链接到相应的固定节点.结果看起来非常凌乱,并且当我降低力时,气泡甚至不会在它们的中心节点周围形成,因此动画运行速度稍慢.
const simulation = d3.forceSimulation(nodes) .force("collide",d3.forceCollide((n,i) => i < 3 ? 0 : 7)) .force("links",d3.forceLink(links).strength(.06))
关于力量设置的任何想法会产生更美观的结果吗?
我确实理解我将不得不随着时间的推移动画小组作业以获得’涓流’效果(否则所有的点都会聚集到他们的目的地),但我想从一个良好的圆形稳定状态开始模拟.
编辑
我确实检查了源代码,它只是重放预先录制的模拟数据,我想是出于性能原因.
解决方法
我认为避免过度熵的关键点之一是指定速度衰减 – 这将有助于避免超出所需位置.太慢,你不会在流量停止,速度过快的情况下增加密度,并且你的节点要么过于混乱,要么超出目的地,在太远和太短之间振荡.
许多体力在这里是有用的 – 它可以保持节点间隔(而不是碰撞力),节点之间的排斥力被每个簇的定位力抵消.下面我使用了两个居中点和一个节点属性来确定使用哪一个.这些力量必须相当弱 – 强大的力量很容易导致过度修正.
我使用simulation.find()函数而不是使用计时器,每个tick都从一个集群中选择一个节点并切换它被吸引到哪个中心.在1000个滴答之后,下面的模拟将停止:
var canvas = d3.select("canvas"); var width = +canvas.attr("width"); var height = +canvas.attr("height"); var context = canvas.node().getContext('2d'); // Key variables: var nodes = []; var strength = -0.25; // default repulsion var centeringStrength = 0.01; // power of centering force for two clusters var velocityDecay = 0.15; // velocity decay: higher value,less overshooting var outerRadius = 250; // new nodes within this radius var innerRadius = 100; // new nodes outside this radius,initial nodes within. var startCenter = [250,250]; // new nodes/initial nodes center point var endCenter = [710,250]; // destination center var n = 200; // number of initial nodes var cycles = 1000; // number of ticks before stopping. // Create a random node: var random = function() { var angle = Math.random() * Math.PI * 2; var distance = Math.random() * (outerRadius - innerRadius) + innerRadius; var x = Math.cos(angle) * distance + startCenter[0]; var y = Math.sin(angle) * distance + startCenter[1]; return { x: x,y: y,strength: strength,migrated: false } } // Initial nodes: for(var i = 0; i < n; i++) { nodes.push(random()); } var simulation = d3.forceSimulation() .force("charge",d3.forceManyBody().strength(function(d) { return d.strength; } )) .force("x1",d3.forceX().x(function(d) { return d.migrated ? endCenter[0] : startCenter[0] }).strength(centeringStrength)) .force("y1",d3.forceY().y(function(d) { return d.migrated ? endCenter[1] : startCenter[1] }).strength(centeringStrength)) .alphaDecay(0) .velocityDecay(velocityDecay) .nodes(nodes) .on("tick",ticked); var tick = 0; function ticked() { tick++; if(tick > cycles) this.stop(); nodes.push(random()); // create a node this.nodes(nodes); // update the nodes. var migrating = this.find((Math.random() - 0.5) * 50 + startCenter[0],(Math.random() - 0.5) * 50 + startCenter[1],10); if(migrating) migrating.migrated = true; context.clearRect(0,width,height); nodes.forEach(function(d) { context.beginPath(); context.fillStyle = d.migrated ? "steelblue" : "orange"; context.arc(d.x,d.y,3,Math.PI*2); context.fill(); }) }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <canvas width="960" height="500"></canvas>
这是一个block view(片段是更好的整页,参数是它的意思).初始节点与后来的节点形成在同一个环中(因此在get get中有一些争用,但这很容易解决).在每个tick上,创建一个节点,并尝试将中间点附近的节点迁移到另一侧 – 这样就创建了一个流(与任何随机节点相对).
对于流体,未链接的节点可能是最好的(我一直用它来进行风力模拟) – 链接节点非常适合结构材料,如网或布.而且,和Gerardo一样,我也是Nadieh工作的粉丝,但是未来也必须关注Shirley的工作.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。