我想用力()和碰撞沿着带有一个圆的内容散布具有内容的正方形,所以这些正方形和主圆不会重叠。 有什么想法怎么做?我应该使用链接来做到这一点吗? 这是一个小提琴http://jsfiddle.net/benderlio/usbq839m/3/ 有时它可以很好地扩展正方形,但是大多数情况下,正方形会像img上那样移动。
var force = d3.forceSimulation(nodes)
.force("charge", d3.forceManyBody(1130))
// .force('link', d3.forceLink().links(links))
.on("tick", function () {
var k = this.alpha(),
kg = k * .02,
spaceAround = 0.04;
//console.log('', nodes);
nodes.forEach(function (a, i) {
...
});
svg.selectAll("rect")
.style("fill", function (d) {
return "#ccc"
})
.attr("x", function (d) {
return d.x - d.width / 2;
})
.attr("y", function (d) {
return d.y - d.height / 2;
});
svg.selectAll("line")
.attr("x2", function (d) {
return d.x;
})
.attr("y2", function (d) {
return d.y;
})
svg.selectAll("circle.end")
.attr("cx", function (d) {
return d.x;
})
.attr("cy", function (d) {
return d.y;
})
});
谢谢。
UPD:
答案 0 :(得分:2)
我不知道解决此问题的一般方法,但是以下是一些更好的解决方法:
为矩形重力算法定义“目标点”时,使其不位于圆的边界上,而是相距一定距离。
x = ((150 + radius) * Math.cos(angle)) + (width / 2) + offset; // Calculate the x position of the element.
y = ((150 + radius) * Math.sin(angle)) + (width / 2) + offset; // Calculate the y position of the element.
如果希望矩形不与圆碰撞,则需要自定义力。由于矩形与直线碰撞的确切公式并不简单,因此,将矩形视为圆形就足够了,因此请在nodes.forEach(...)
之后添加:
nodes.forEach(function(a) {
const diag = Math.sqrt(a.width ** 2 + a.height ** 2) / 2;
const rad = 150;
const [cx, cy] = [500, 500];
const [dx, dy] = [a.x - cx, a.y - cy];
const dist = Math.sqrt(dx ** 2 + dy ** 2);
const shift = Math.max(0, rad + diag - dist);
a.x += shift * dx / dist;
a.y += shift * dy / dist;
})
答案 1 :(得分:1)
您的碰撞力太大。减少一点。
lx *= 0.3;
ly *= 0.3;
中心矩形可以添加
nodes.push( { x:500, y:500, width:300, height:300, fx:500, fy:500, center: true });
现在应该过滤矩形的绘画
var g = svg.selectAll("g")
.data(nodes.filter(d => !d.center))
.enter()
.append("g")
如果还绘制中心矩形,则必须添加一个类
g.append("rect")
.attr("opacity", 0.5)
.attr("class", "node")
.attr("fill", "#ccc" )
.attr("width", d => d.width )
.attr("height", d => d.height )
.attr("rx", 10)
.attr("ry", 10);
然后在带有类的rect的tick函数过滤器中
svg.selectAll("rect.node")
.attr("x", d => d.x - d.width / 2 )
.attr("y", d => d.y - d.height / 2 );
添加测试以忽略中心rect
if (a.center) return;
更新的部队代码
nodes.forEach(function (a, i) {
if (a.center) return; // ignore this node
// Apply gravity forces.
a.x += (a.gravity.x - a.x) * kg;
a.y += (a.gravity.y - a.y) * kg;
nodes.slice(i + 1).forEach(function (b) {
dx = (a.x - b.x)
dy = (a.y - b.y)
adx = Math.abs(dx)
ady = Math.abs(dy)
mdx = (1 + spaceAround) * (a.width + b.width) / 2
mdy = (1 + spaceAround) * (a.height + b.height) / 2
if (adx < mdx && ady < mdy) {
l = Math.sqrt(dx * dx + dy * dy)
lx = (adx - mdx) / l * k
ly = (ady - mdy) / l * k
lx *= 0.3;
ly *= 0.3;
// choose the direction with less overlap
if (lx > ly && ly > 0) lx = 0;
else if (ly > lx && lx > 0) ly = 0;
dx *= lx
dy *= ly
a.x -= dx
a.y -= dy
b.x += dx
b.y += dy
}
});
});
修改
一种修改方式是使移动独立于矩形中心的距离。只能沿另一个中心的相反方向移动一定量。
当前方法将列表中稍后的节点已更改为新位置,并将下一个节点的碰撞基于这些新位置。更好的方法是首先根据时间N的所有节点计算运动,最后应用该运动。在力仿真中,这是通过计算/修改节点的速度(d.vx
,d.vy
)来完成的。模拟会将速度应用在刻度上。