文字星球
Published on 20th January 2025
Benjamin Robinet 有个网页作品令我印象深刻,它被发表在 X 上。
中国的网友可能无法查看,我私自将视频展示到下方,如有侵权请给我发邮件(Eamil: [email protected]),我会将其删除。
抛开醒目的大号文字不谈,位于屏幕中间的文字似乎在围绕鼠标排列,以弹簧动画驱动。
它是如何实现的?
我们虚构一个星系,光标是恒星,它周围的单词是行星,值得注意的是,引力不适用该星系。离恒星越近,受到的斥力越大,到达某个距离后,斥力衰弱为 0。
有了此认知模型,便可编写代码。
1. 向量
将星系看作一个平面直角坐标系,光标是原点,原点到元素的向量的模可以由下述公式计算:
如果你对该公式感到抽象,没关系,回忆一次勾股定理。
const c = Math.sqrt(a * a + b * b)
斜边 c 的长度等于向量 v 的模。
2. 元素的偏移量
设定从圆心开始,200 范围内的元素都遵循该原则发生偏移:离圆心越近,偏移量越大,达到 200 后衰减为 0,最大偏移距离为 100。
设光标为圆心,坐标为 px, py,元素的坐标为 ex, ey,则 dx = ex - px, dy = ey - py
,向量的模 v = Math.sqrt(dx * dx + dy * dy)
则缩放比例为:
const scale = Math.max(0, 1 - v / 200)
发生偏移后,向量在 x, y 轴上的投影分别为:
const moveX = (dx / v) * scale * 100
const moveY = (dy / v) * scale * 100
计算在轴上的投影用到了向量归一化(英文:vector normalization),这是游戏里用来计算角色移动的方法之一,如果你对它陌生,请自行查阅相关资料,这超出了本文范围。
3. 性能优化
为了将动画尽可能的维持在 60fps,我做了不少工作,你可以在代码里查看 Word Galaxy,这可能不是最优解。值得一提的是,尽可能地避免密集使用 getBoundingClientRect
,该 API 引发浏览器 reflow
,可能会严重损耗性能。