最省事路径是用three.js搭配THREE.TextGeometry或troika-three-text;需用Fibonacci球面采样均匀布词、手动设置quaternion使文字正对摄像机、加载JSON字体、词超50个时关闭阴影。

用 Three.js 实现球形词云最省事的路径
直接用 three.js + THREE.TextGeometry 或 troika-three-text 是目前唯一能稳定控制每个词位置、大小、朝向且保持可读性的方案。纯 CSS 3D 或 Canvas 手搓球面投影,要么文字扭曲严重,要么交互卡顿,还容易在 Safari 上失焦。
关键不是“怎么转起来”,而是“怎么让每个词真正贴在球面上且正对摄像机”。默认的球面坐标映射只是把文字放在球表面,不调整旋转,结果全是歪的、倒的、侧躺的。
- 必须手动计算每个词的
position和quaternion(或用lookAt) - 字体不能用浏览器默认字体——
TextGeometry依赖FontLoader加载 JSON 字体(如helvetiker_bold.typeface.json),否则报错TypeError: font.generateShapes is not a function - 词多于 50 个时,建议关掉阴影、禁用
castShadow和receiveShadow,不然帧率掉到 10fps 以下
词的位置怎么均匀分布在球面上
别用随机 Math.random() 生成经纬度——会聚堆在两极。要用“Fibonacci sphere sampling”算法,它能逼近均匀分布,代码不到 10 行:
function fibonacciSphere(samples) {
const points = [];
const phi = Math.PI * (3 - Math.sqrt(5)); // 黄金角
for (let i = 0; i < samples; i++) {
const y = 1 - (i / (samples - 1)) * 2;
const radius = Math.sqrt(1 - y * y);
const theta = phi * i;
points.push({
x: Math.cos(theta) * radius,
y,
z: Math.sin(theta) * radius
});
}
return points;
}返回的每个点已经是单位球面上的归一化坐标,直接赋给 mesh.position.set(x, y, z) 即可。注意:后续调用 mesh.lookAt(0, 0, 0) 会让文字背面朝外,得改成 mesh.lookAt(new THREE.Vector3().negate()) 或直接设 mesh.rotation.copy(new THREE.Euler().setFromQuaternion(q))。
立即学习“前端免费学习笔记(深入)”;
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
为什么不用 D3.js + SVG 做球形词云
因为 SVG 没有真正的 3D 渲染管线。所谓“球形”,只是用 transform: rotateX() rotateY() 模拟,本质还是平面投影。问题非常明显:
- 文字重叠无法深度排序(
z-index在 3D transform 下失效) - 缩放时字体边缘发虚(SVG 被当位图拉伸)
- 滚动或切换 Tab 后,
requestAnimationFrame容易中断,旋转突然卡住 - 手机端 touchmove 事件和
transform冲突,拖拽一顿一顿
如果你只需要静态图,用 Python 的 wordcloud 库导出球面 UV 展开图再 PS 合成更快。但要真旋转、可交互、支持点击词跳转?绕不开 WebGL。
移动端适配和性能踩坑点
在 iOS Safari 上,three.js 默认启用抗锯齿(antialias: true)会导致内存暴涨,尤其词超过 30 个时,页面直接崩溃。必须显式关掉:
const renderer = new THREE.WebGLRenderer({ antialias: false });另外两个硬性限制:
- 字体大小别设
0.1这种小数——iOS 对 subpixel rendering 支持差,文字糊成一片;建议最小用0.2,并统一乘以devicePixelRatio - 不要监听
window.resize后立刻调用renderer.setSize(),需加防抖,否则快速横竖屏切换时触发多次 resize,Three.js 内部 buffer 重建失败,报错WebGL: INVALID_OPERATION: bindBuffer: object not from this context
球面词云真正的难点不在“转”,而在每个词的法线对齐、远近缩放一致性、以及低功耗设备上的帧率兜底——这些细节没压住,看起来就是廉价动画。


















