javascript - 如何在气泡之间均匀分布?
问题描述
我在 D3 中有一个气泡图。我让它可以显示大约 1,000 个气泡,但我想让它显示 2 甚至 3000 个气泡。我在这里从Shirley Wu与 Guardian 的惊人可视化中获得灵感。
我的气泡分布不均匀,其中更多的气泡向中心填充。
我想得到它,这样它们就可以均匀地分布在整个空间中,就像这样。
这些是我一直试图操纵的组件。
// Forces
const radius = 1.5
const padding1 = 15;
const padding2 = 5;
const strength = .3
const alpha = .1
const alpha_decay = 0
const alpha_min = 0.001
const alpha_Collision = .03;
const charge_strength = -.5
const charge_theta = .9
const veloc_decay = .5
这是定义我的力量的代码。
// Circle for each node.
const circle = svg.append("g")
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("fill", d => d.color)
.attr("r", d => d.r);
// Forces
const simulation = d3.forceSimulation(nodes)
.force("x", d => d3.forceX(d.x))
.force("y", d => d3.forceY(d.y))
.force("cluster", forceCluster())
.force("collide", forceCollide())
.force("charge", d3.forceManyBody().strength(charge_strength).theta(charge_theta))
.alpha(alpha)
.alphaDecay(alpha_decay)
.alphaMin(alpha_min)
.velocityDecay(veloc_decay);
// Adjust position of circles.
simulation.on("tick", () => {
circle
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("fill", d => groups[d.group].color);
});
// Force to increment nodes to groups.
function forceCluster() {
let nodes;
function force(alpha) {
const l = alpha * strength;
for (const d of nodes) {
d.vx -= (d.x - groups[d.group].x) * l;
d.vy -= (d.y - groups[d.group].y) * l;
}
}
force.initialize = _ => nodes = _;
return force;
}
// Force for collision detection.
function forceCollide() {
let nodes;
let maxRadius;
function force() {
const quadtree = d3.quadtree(nodes, d => d.x, d => d.y);
for (const d of nodes) {
const r = d.r + maxRadius;
const nx1 = d.x - r, ny1 = d.y - r;
const nx2 = d.x + r, ny2 = d.y + r;
quadtree.visit((q, x1, y1, x2, y2) => {
if (!q.length) do {
if (q.data !== d) {
const r = d.r + q.data.r + (d.group === q.data.group ? padding1 : padding2);
let x = d.x - q.data.x, y = d.y - q.data.y, l = Math.hypot(x, y);
if (l < r) {
l = (l - r) / l * alpha_Collision;
d.x -= x *= l, d.y -= y *= l;
q.data.x += x, q.data.y += y;
}
}
} while (q = q.next);
return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
});
}
}
force.initialize = _ => maxRadius = d3.max(nodes = _, d => d.r) + Math.max(padding1, padding2);
return force;
}
我在这里上传了代码。部分问题在于中心的气泡不断移动。就好像他们想找个地方安顿下来,但空间的宽度不够大(除非我把它弄大,整个blob就变得太大了)。
我不知道如何停止运动。当我设置为时它看起来更好alpha_decay
,.1
但气泡在可视化上的位置从unaware
到aware
并且它们不会移动如果alpha_decay > 0
。
如何使气泡均匀分布而不聚集在中心,如示例所示?
解决方案
您可以使用本机 d3 force 方法来实现它。只需使用不同的冲锋、中心和碰撞力即可。
height = 300;
width = 300;
const nodes = [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, ];
const simulation = d3.forceSimulation(nodes)
.force('charge', d3.forceManyBody().strength(0.4))
.force('center', d3.forceCenter(width / 2, height / 2))
.force('collision', d3.forceCollide().radius(6))
.on('tick', ticked);
function ticked() {
var u = d3.select('svg')
.selectAll('circle')
.data(nodes)
u.enter()
.append('circle')
.attr('r', 5)
.merge(u)
.attr('cx', function(d) {
return d.x
})
.attr('cy', function(d) {
return d.y
});
u.exit().remove()
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="300" height="300"></svg>
推荐阅读
- c# - EWS FindItems 与 FindAppointments 不同的数据返回?
- qt - 为什么 Qt Configure 在交叉编译时无法在目标上找到正确的 MySQL 安装?
- android - SAP WEB IDE 中的移动应用程序构建从移动服务中提取了错误的应用程序 ID
- qt - 如何让我在 BeagleBone Black 上的 Qt 应用程序检测插件“socketcan”
- powerbi - 通过 Postman 访问组和 power bi 报告
- php - 如何创建一个条件来显示 json 文件中的多个元素?
- highcharts - 标记应跟随光标
- image - 如何将eps文件的图层导出到单独的文件中
- graphql - 如何跳过查询条件片段中的空对象?
- swift - 我应该如何从 UserDefaults 更新对象值?