用一条线连接两个圆圈(有 DOM 个元素)

Connect two circles with a line (with DOM elements)

我正在努力用一条线连接两个圆圈。我正在使用 famo.us 库。

DEMO on Codepen

a.k.a。 "Two balls, one line."


问题

直线的角度和长度是正确的,但是位置是错误的


第一次尝试

重要的部分应该是第114-116行:

connection.origin = [.5, .5];
connection.align = [.5, .5];
connection.body.setPosition([
    Math.min(sourcePos.x, targetPos.x),
    Math.min(sourcePos.y, targetPos.y)
]);

显然我在数学上做错了。使用这些值可以得到各种结果,但没有什么是接近正确的。


预期的解决方案

(1) 最小的解决方案是用直线连接圆心。

(2) 更好的解决方案是一条线只接触两个圆的表面而不是到达中心。

(3) 理想的解决方案是在线的每一端都有箭头,看起来像有向图。

这修复了它:

connection.body.setPosition([
    sourcePos.x * Math.cos(angle) + sourcePos.y * Math.sin(angle),
    sourcePos.x * Math.sin(-angle)+ sourcePos.y * Math.cos(angle)
]);
  • 您的线段由其在 source 的边界以及到 target 的角度和距离定义,因此您必须将其原点设置为 source
  • 旋转好像不仅旋转了物体,还旋转了原点坐标,所以我旋转了-angle来补偿。

可能有更 famo.us 的方式来做到这一点(也许你可以在设置位置之前让它旋转,或者将位置设为 0,0 并将坐标作为平移添加到转换)。


为了获得更好的解决方案,仍然主要是数学,您可以保留相同的代码,但是

  • r球的半径source,移去[r * distX / distance, r * distY / distance]到线段的坐标,使其与球的外部接触
  • 从距离中移除两个球的半径

这样,我们得到:

var distX = sourcePos.x - targetPos.x;
var distY = sourcePos.y - targetPos.y;
var norm = Math.sqrt(distX * distX + distY * distY);
var distance = norm - (source.size[0]+target.size[0])/2;
var angle = -Math.atan2(-distY, distX);
connection.angle = angle;
connection.size = [distance, 2, 0];
connection.align = [.5, .5];
connection.origin = [.5, .5];
var posX = sourcePos.x - source.size[0]/2 * (distX / norm);
var posY = sourcePos.y - source.size[0]/2 * (distY / norm);
connection.body.setPosition([
  posX * Math.cos(angle) + posY * Math.sin(angle),
  posX * Math.sin(-angle)+ posY * Math.cos(angle)
]);

这个分支的结果:http://codepen.io/anon/pen/qEjPLg

我认为当球跑得快时线的长度变短是一个时间问题。很可能您是在该帧的球中心尚未更新时计算段的长度和位置的。