用 CSS + JS 写一个可交互的星球图

1,479 阅读3分钟

好久没更新,稀土掘金都开始给我发短信了…… 今年 7 月毕业了,开始挨工作的毒打了,这个文章也是从一个需求中抽象出来的 (不过俺大胆猜测这个需求点会被砍掉)

这个方案有一个超级大的缺陷,就是只确定了运动的起始点和终点,运动过程中点走的是直线,其实应该是一个圆弧。

实现效果

20230820142133_rec_.gif

20230820141320_rec_.gif

(这种不均匀分布的,是不是更有星星的感觉)

用文字描述一下需求:球面上有若干个点,点击一下,这个点就会跑到球正面中心位置,并且球面上的其他点也会做相应的转动。

分析

选择 translate 还是 rotate

CSS 中有两个 transform 类型:

  1. translate 位移,可以将元素由一个三维空间位置,移动到另一个三维空间位置,注意 CSS 中的 z 轴方向是面向屏幕的方向;
  2. rotate 旋转,可以将元素相对指定点、指定轴做旋转;

因为我对这两个类型都不是很熟悉,使用 rotate 的话,元素内容也会发生旋转,所以还是选择了比较好用数学“暴力解决”的 translate。如果其实用 rotate 会更简单,也请和我交流。(带带弟弟.jpg)

点是怎么运动的

再把问题数学抽象一点,当球面上有一个关键点,从 A 位置运动到 B 位置时,在 C 位置上的这个点,会运动到什么位置。

这个方案有一个超级大的缺陷,就是只确定了运动的起始点和终点,运动过程中点走的是直线,其实应该是一个圆弧。

球体运动的两个关键点:

  1. 旋转轴:关键点运动的起始位置 A,结束位置 B 还有球体的球心 O,可以构成一个平面,该平面的法向就是本次旋转的旋转轴,可以通过OA × OB 求得(× 是向量叉乘哦);
  2. 旋转角度:由于向量 OAOB 都垂直于旋转轴,所以OAOB 之间的夹角,就是所有点绕旋转轴的旋转角度,可以通过OA · OB 求得(· 是向量点乘哦);

知道了旋转轴、旋转角度,就可以使用罗德里格旋转公式算出其他点运动后的坐标啦。

罗德里格旋转公式(百度百科):

image.png

矩阵计算

矩阵形式的旋转公式 image.png

实现

代码

这次我是在 codesandbox 上跑的,没有 github 地址,直接把所有代码贴上来吧

tips

一些我在实现中踩到的坑:

  1. 叉乘后需要标准化到长度为 1 的向量,才是旋转平面的法向量,否则所有点会越来越集中;
  2. translate 里 x 轴方向和 y 轴方向平移距离,需要在 x 轴坐标和 y 轴坐标上减去元素的半径;
  3. 如果点击较远的点,运动过程中,球形会看起来像椭球形,这是点是沿直线运动的缺陷导致的;

image.png