用一条线连接两个圆圈(有 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
我认为当球跑得快时线的长度变短是一个时间问题。很可能您是在该帧的球中心尚未更新时计算段的长度和位置的。
我正在努力用一条线连接两个圆圈。我正在使用 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
我认为当球跑得快时线的长度变短是一个时间问题。很可能您是在该帧的球中心尚未更新时计算段的长度和位置的。