玩转元素周期表:从2D表格到3D DNA螺旋的炫酷前端实现


元素周期表是化学的基石,118个元素蕴含着物质世界的奥秘。而在前端开发中,将这张表以动态、可交互的3D形式呈现出来,不仅是对数据可视化的挑战,更是一次技术与创意的碰撞。本文将带你逐步实现四种不同风格的元素周期表特效:2D网格表格3D球体分布螺旋弹簧结构DNA双螺旋以及排队纵深矩阵。最终所有特效均使用 Three.js + CSS2DRenderer 实现,保证文字清晰且性能优良。

一、基础先行:标准2D周期表

在开始3D特效之前,一个可靠的数据源和规整的2D表格是基石。我们使用 grid 布局模拟传统周期表。

技术要点

  • 将118个元素按周期和族放置在7行18列的网格中(空缺位置用占位符填充)。

  • 每个卡片包含:原子序数、符号、中文名、原子量、状态标识(气/液/固)、合成元素标记。

  • 根据元素族类(碱金属、过渡金属等)应用不同的背景色。

    image.png

核心代码示意

// 数据存储
const elementsData = {};
function addElement(z, symbol, nameZh, mass, category, state, synthetic) { ... }

// 网格布局 (7x18)
const grid = Array(7).fill().map(() => Array(18).fill(null));
function placeElement(z, row, col) { grid[row-1][col-1] = elementsData[z]; }

// 渲染时动态创建卡片DOM
const card = createCardElement(elem);
periodicGrid.appendChild(card);

这种方式生成的2D表格适配移动端和PC,是所有3D特效的数据基础。

二、3D球体:让元素环绕地球

将118个元素均匀分布在球面上,用户可通过鼠标拖拽旋转观察每个角落。

image.png

核心算法:斐波那契球体算法(Fibonacci Sphere),保证点分布均匀无极点聚集。

const radius = 5.0;
const phiGolden = Math.PI * (3 - Math.sqrt(5));
for (let i = 0; i < total; i++) {
    const y = 1 - (i / (total - 1)) * 2;
    const radiusAtY = Math.sqrt(1 - y*y);
    const theta = i * phiGolden * 2;
    const x = Math.cos(theta) * radiusAtY;
    const z = Math.sin(theta) * radiusAtY;
    positions.push(new THREE.Vector3(x * radius, y * radius, z * radius));
}

将每个卡片包装为 CSS2DObject 并设置位置,添加 OrbitControls 后即可交互。若需要自转,只需每帧旋转包含所有卡片的 Group

三、螺旋弹簧结构:像弹簧一样旋转

螺旋结构能清晰地展示元素的顺序(按原子序数递增),视觉上酷似弹簧或螺丝。

image.png

参数方程

const radius = 2.2, startY = -3.5, endY = 3.5, turns = 2.2;
for (let i = 0; i < total; i++) {
    const t = i / (total - 1);
    const angle = t * Math.PI * 2 * turns;
    const y = startY + t * (endY - startY);
    const x = radius * Math.cos(angle);
    const z = radius * Math.sin(angle);
    positions.push(new THREE.Vector3(x, y, z));
}

为了让螺旋更明显,可以添加一条半透明的 TubeGeometry 沿着路径,加强视觉引导。并且可以设置整个组绕 Y 轴自转,产生“弹簧旋转”的动感。

四、DNA双螺旋:科学感十足

DNA双螺旋结构是生命科学的象征,用来展示元素周期表别有一番风味。我们将118个元素分成两条链(各59个),相位差180度,中间用圆柱体或线条连接形成碱基对。

image.png

关键步骤

  1. 定义螺旋线函数 getHelixPosition(t, phaseOffset)

  2. 将元素按索引交错分配到两条链上(或直接前后半切分)。

  3. 计算两条链上每个卡片的位置。

  4. 对于每一对对应高度的卡片,创建圆柱体或线条连接。

// 创建连接柱
const pA = posChainA[i];
const pB = posChainB[i];
const direction = new THREE.Vector3().subVectors(pB, pA);
const length = direction.length();
const center = new THREE.Vector3().addVectors(pA, pB).multiplyScalar(0.5);
const cylinder = new THREE.Mesh(new THREE.CylinderGeometry(0.08, 0.08, length, 6), material);
cylinder.position.copy(center);
cylinder.quaternion.setFromUnitVectors(new THREE.Vector3(0,1,0), direction.clone().normalize());

为了增强视觉效果,可以添加两条彩色光带(TubeGeometry)沿着两条螺旋线,并加入漂浮粒子。最终效果非常惊艳。

五、排队纵深矩阵:正面整齐,侧面有惊喜

这种特效模拟了“队列”的感觉:正面看去只有5行4列共20个元素,旋转到侧面才发现后面还有多层(共6层,118个元素)。适合演示“遮挡与纵深”概念。

image.png

布局计算

  • 设定每层5行 x 4列 = 20个元素。

  • 层数 = ceil(118 / 20) = 6。

  • 层间距 spacingZ 设为 1.2,行间距 1.0,列间距 0.9。

  • 正面(Z轴负方向)看到的是第一层(layer=0),后面的层依次排列。

let idx = 0;
for (let layer = 0; layer < layers; layer++) {
    for (let row = 0; row < rows; row++) {
        for (let col = 0; col < cols; col++) {
            if (idx >= total) break;
            const x = (col - cols/2) * spacingX;
            const y = (rows/2 - row) * spacingY;
            const z = - layer * spacingZ;
            targetPositions.push(new THREE.Vector3(x, y, z));
            idx++;
        }
    }
}

通用技术栈

  • Three.js + CSS2DRenderer:确保文字清晰。

  • OrbitControls:提供拖拽、缩放交互。

  • Tween.js:平滑动画过渡。

通过这些实现,不仅可以做出炫酷的元素周期表,还能将任何数据集以同样的方式可视化。



本文最后更新时间 2026-05-27
文章链接地址:
https://yrajsh.cn/index.php/archives/137/
本站文章除注明[转载|引用|原文]出处外,均为本站原生内容,转载前请注明出处

文章附件
  • 暂无附件
希望可以帮助到你

留言