<!DOCTYPE html>
<html>
<head>
<title>three.js css3d - periodic table</title>
<meta charset="utf-8" />
<!-- 控制网页为全屏幕大小,手机页面常用 -->
<!-- 属性效果分别为 device-width :设备的宽度 user-scalable:是否可对页面进行缩放,no 禁止缩放-->
<!-- minimum-scale 允许用户缩放到的最小比例 maximum-scale - 允许用户缩放到的最大比例 -->
<meta
name="viewport"
content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"
/>
</head>
<body>
<script src="build/three.js"></script>
<script src="examples/js/libs/tween.min.js"></script>
<script src="examples/js/controls/TrackballControls.js"></script>
<script src="examples/js/renderers/CSS3DRenderer.js"></script>
<div id="info">
<a href="http://threejs.org" target="_blank" rel="noopener"
>three.js css3d</a
>
- periodic table.
<a
href="https://plus.google.com/113862800338869870683/posts/QcFk5HrWran"
target="_blank"
rel="noopener"
>info</a
>.
</div>
<div id="container"></div>
<div id="menu">
<button id="table">TABLE</button>
<button id="sphere">SPHERE</button>
<button id="helix">HELIX</button>
<button id="grid">GRID</button>
</div>
<script>
var table = [
"H",
"Hydrogen",
"1.00794",
1,
1,
"He",
"Helium",
"4.002602",
18,
1,
"Li",
"Lithium",
"6.941",
1,
2,
"Be",
"Beryllium",
"9.012182",
2,
2,
"B",
"Boron",
"10.811",
13,
2,
"C",
"Carbon",
"12.0107",
14,
2,
"N",
"Nitrogen",
"14.0067",
15,
2,
"O",
"Oxygen",
"15.9994",
16,
2,
"F",
"Fluorine",
"18.9984032",
17,
2,
"Ne",
"Neon",
"20.1797",
18,
2,
"Na",
"Sodium",
"22.98976...",
1,
3,
"Mg",
"Magnesium",
"24.305",
2,
3,
"Al",
"Aluminium",
"26.9815386",
13,
3,
"Si",
"Silicon",
"28.0855",
14,
3,
"P",
"Phosphorus",
"30.973762",
15,
3,
"S",
"Sulfur",
"32.065",
16,
3,
"Cl",
"Chlorine",
"35.453",
17,
3,
"Ar",
"Argon",
"39.948",
18,
3,
"K",
"Potassium",
"39.948",
1,
4,
"Ca",
"Calcium",
"40.078",
2,
4,
"Sc",
"Scandium",
"44.955912",
3,
4,
"Ti",
"Titanium",
"47.867",
4,
4,
"V",
"Vanadium",
"50.9415",
5,
4,
"Cr",
"Chromium",
"51.9961",
6,
4,
"Mn",
"Manganese",
"54.938045",
7,
4,
"Fe",
"Iron",
"55.845",
8,
4,
"Co",
"Cobalt",
"58.933195",
9,
4,
"Ni",
"Nickel",
"58.6934",
10,
4,
"Cu",
"Copper",
"63.546",
11,
4,
"Zn",
"Zinc",
"65.38",
12,
4,
"Ga",
"Gallium",
"69.723",
13,
4,
"Ge",
"Germanium",
"72.63",
14,
4,
"As",
"Arsenic",
"74.9216",
15,
4,
"Se",
"Selenium",
"78.96",
16,
4,
"Br",
"Bromine",
"79.904",
17,
4,
"Kr",
"Krypton",
"83.798",
18,
4,
"Rb",
"Rubidium",
"85.4678",
1,
5,
"Sr",
"Strontium",
"87.62",
2,
5,
"Y",
"Yttrium",
"88.90585",
3,
5,
"Zr",
"Zirconium",
"91.224",
4,
5,
"Nb",
"Niobium",
"92.90628",
5,
5,
"Mo",
"Molybdenum",
"95.96",
6,
5,
"Tc",
"Technetium",
"(98)",
7,
5,
"Ru",
"Ruthenium",
"101.07",
8,
5,
"Rh",
"Rhodium",
"102.9055",
9,
5,
"Pd",
"Palladium",
"106.42",
10,
5,
"Ag",
"Silver",
"107.8682",
11,
5,
"Cd",
"Cadmium",
"112.411",
12,
5,
"In",
"Indium",
"114.818",
13,
5,
"Sn",
"Tin",
"118.71",
14,
5,
"Sb",
"Antimony",
"121.76",
15,
5,
"Te",
"Tellurium",
"127.6",
16,
5,
"I",
"Iodine",
"126.90447",
17,
5,
"Xe",
"Xenon",
"131.293",
18,
5,
"Cs",
"Caesium",
"132.9054",
1,
6,
"Ba",
"Barium",
"132.9054",
2,
6,
"La",
"Lanthanum",
"138.90547",
4,
9,
"Ce",
"Cerium",
"140.116",
5,
9,
"Pr",
"Praseodymium",
"140.90765",
6,
9,
"Nd",
"Neodymium",
"144.242",
7,
9,
"Pm",
"Promethium",
"(145)",
8,
9,
"Sm",
"Samarium",
"150.36",
9,
9,
"Eu",
"Europium",
"151.964",
10,
9,
"Gd",
"Gadolinium",
"157.25",
11,
9,
"Tb",
"Terbium",
"158.92535",
12,
9,
"Dy",
"Dysprosium",
"162.5",
13,
9,
"Ho",
"Holmium",
"164.93032",
14,
9,
"Er",
"Erbium",
"167.259",
15,
9,
"Tm",
"Thulium",
"168.93421",
16,
9,
"Yb",
"Ytterbium",
"173.054",
17,
9,
"Lu",
"Lutetium",
"174.9668",
18,
9,
"Hf",
"Hafnium",
"178.49",
4,
6,
"Ta",
"Tantalum",
"180.94788",
5,
6,
"W",
"Tungsten",
"183.84",
6,
6,
"Re",
"Rhenium",
"186.207",
7,
6,
"Os",
"Osmium",
"190.23",
8,
6,
"Ir",
"Iridium",
"192.217",
9,
6,
"Pt",
"Platinum",
"195.084",
10,
6,
"Au",
"Gold",
"196.966569",
11,
6,
"Hg",
"Mercury",
"200.59",
12,
6,
"Tl",
"Thallium",
"204.3833",
13,
6,
"Pb",
"Lead",
"207.2",
14,
6,
"Bi",
"Bismuth",
"208.9804",
15,
6,
"Po",
"Polonium",
"(209)",
16,
6,
"At",
"Astatine",
"(210)",
17,
6,
"Rn",
"Radon",
"(222)",
18,
6,
"Fr",
"Francium",
"(223)",
1,
7,
"Ra",
"Radium",
"(226)",
2,
7,
"Ac",
"Actinium",
"(227)",
4,
10,
"Th",
"Thorium",
"232.03806",
5,
10,
"Pa",
"Protactinium",
"231.0588",
6,
10,
"U",
"Uranium",
"238.02891",
7,
10,
"Np",
"Neptunium",
"(237)",
8,
10,
"Pu",
"Plutonium",
"(244)",
9,
10,
"Am",
"Americium",
"(243)",
10,
10,
"Cm",
"Curium",
"(247)",
11,
10,
"Bk",
"Berkelium",
"(247)",
12,
10,
"Cf",
"Californium",
"(251)",
13,
10,
"Es",
"Einstenium",
"(252)",
14,
10,
"Fm",
"Fermium",
"(257)",
15,
10,
"Md",
"Mendelevium",
"(258)",
16,
10,
"No",
"Nobelium",
"(259)",
17,
10,
"Lr",
"Lawrencium",
"(262)",
18,
10,
"Rf",
"Rutherfordium",
"(267)",
4,
7,
"Db",
"Dubnium",
"(268)",
5,
7,
"Sg",
"Seaborgium",
"(271)",
6,
7,
"Bh",
"Bohrium",
"(272)",
7,
7,
"Hs",
"Hassium",
"(270)",
8,
7,
"Mt",
"Meitnerium",
"(276)",
9,
7,
"Ds",
"Darmstadium",
"(281)",
10,
7,
"Rg",
"Roentgenium",
"(280)",
11,
7,
"Cn",
"Copernicium",
"(285)",
12,
7,
"Nh",
"Nihonium",
"(286)",
13,
7,
"Fl",
"Flerovium",
"(289)",
14,
7,
"Mc",
"Moscovium",
"(290)",
15,
7,
"Lv",
"Livermorium",
"(293)",
16,
7,
"Ts",
"Tennessine",
"(294)",
17,
7,
"Og",
"Oganesson",
"(294)",
18,
7
];
var camera, scene, renderer;
var controls;
var objects = [];
var targets = {
table: [],
sphere: [],
helix: [],
grid: []
};
init();
animate();
function init() {
// PerspectiveCamera(fov, aspect, near, far)
// Fov – 相机的视锥体的垂直视野角 越大越远
// 我们把视角由45度变为60度,发现立方体变小了,很容易理解,视角变大之后,可以看到的范围变大了
// Aspect – 相机视锥体的长宽比 通常设置为canvas元素的高宽比。
// Near – 相机视锥体的近平面
// Far – 相机视锥体的远平面
// 只有离相机的距离大于near值,小于far值,且在相机的可视角度之内,才能被相机投影到
camera = new THREE.PerspectiveCamera(
40,
window.innerWidth / window.innerHeight,
1,
10000
);
//相机得位置 在(0,0,3000)
camera.position.z = 3000;
//得到一个场景
//场景就是一个三维空间
scene = new THREE.Scene();
// table
for (var i = 0; i < table.length; i += 5) {
//得到一个div
var element = document.createElement("div");
//给她class值
element.className = "element";
//给他一个背景颜色
element.style.backgroundColor =
"rgba(0,127,127," + (Math.random() * 0.5 + 0.25) + ")";
var number = document.createElement("div");
number.className = "number";
//给一个文本内容
//元素的排序
number.textContent = i / 5 + 1;
//将这个div加入到上面的div
element.appendChild(number);
var symbol = document.createElement("div");
symbol.className = "symbol";
//从上面数组拿到元素的缩写
//textContent类似于innerHTML
symbol.textContent = table[i];
//也加到上面
element.appendChild(symbol);
var details = document.createElement("div");
details.className = "details";
//得到元素的全拼 和 序号
//<br>换行符
details.innerHTML = table[i + 1] + "<br>" + table[i + 2];
element.appendChild(details);
//一个完整的元素块
var object = new THREE.CSS3DObject(element);
object.position.x = Math.random() * 4000 - 2000;
object.position.y = Math.random() * 4000 - 2000;
object.position.z = Math.random() * 4000 - 2000;
//这边x,y,z坐标随机 是刚进入时元素块会随机出现
//添加到场景
scene.add(object);
//将object保存下来
//方便找到
//并且把所以的耽搁元素都已经做好的 保存到objects里面方便后面用到
objects.push(object);
//得到一个3D对象吧 和上面类似 只不过上面那个更精确
//正常排列
var object = new THREE.Object3D();
object.position.x = table[i + 3] * 140 - 1330;
object.position.y = -(table[i + 4] * 180) + 990;
//保存到table标签里 点击回到正常排列
targets.table.push(object);
}
// sphere
//获得一个3维向量
var vector = new THREE.Vector3();
for (var i = 0, l = objects.length; i < l; i++) {
//acos() 方法可返回一个数的反余弦
var phi = Math.acos(-1 + (2 * i) / l);
//sqrt() 方法可返回一个数的平方根。
var theta = Math.sqrt(l * Math.PI) * phi;
var object = new THREE.Object3D();
//球坐标 利用球坐标 表示一个点 p 在三维空间的位置的三维正交坐标系
object.position.setFromSphericalCoords(800, phi, theta);
//猜测所有属性乘2 multiply 相乘 scalar 数量
vector.copy(object.position).multiplyScalar(2);
//将对想看向该目标点
//应该是通过循环将每个元素块的3维向量更改 而且好像是连属性改 上面坐标3维坐标 下面为球坐标 类型都换了
object.lookAt(vector);
//每一个循环 将坐标放入
targets.sphere.push(object);
}
// helix
var vector = new THREE.Vector3();
for (var i = 0, l = objects.length; i < l; i++) {
var theta = i * 0.175 + Math.PI;
var y = -(i * 8) + 450;
var object = new THREE.Object3D();
//柱坐标 r、φ、z x=rcosφ y=rsinφ z=z
object.position.setFromCylindricalCoords(900, theta, y);
//存入的是柱坐标 取x,y,z取得是转化后的x,y,z还是柱坐标
//但是如果是柱坐标 就没有必要乘2 直接给好 所以推断 应该是转化后的 x,y,z
//那为什么废那么大劲求柱坐标呢?
vector.x = object.position.x * 2;
vector.y = object.position.y;
vector.z = object.position.z * 2;
object.lookAt(vector);
targets.helix.push(object);
}
// grid
for (var i = 0; i < objects.length; i++) {
var object = new THREE.Object3D();
object.position.x = (i % 5) * 400 - 800;
//Math.floor() 返回小于或等于一个给定数字的最大整数。
object.position.y = -(Math.floor(i / 5) % 5) * 400 + 800;
object.position.z = Math.floor(i / 25) * 1000 - 2000;
targets.grid.push(object);
}
//
//渲染器
renderer = new THREE.CSS3DRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
//把渲染器的所以结点添加到container(第二个div)里面
document.getElementById("container").appendChild(renderer.domElement);
//
//THREE.TrackballControls()轨迹球控件,最常用的控件,可以使用鼠标轻松的移动、平移,缩放场景。
controls = new THREE.TrackballControls(camera, renderer.domElement);
//rotateSpeed 旋转速度
//zoomSpeed 缩放速度
//minDistance 最小视角
//maxDistance 最大视角 Infinity 无穷大
//controls.staticMoving 默认false 静止移动,为 true 则没有惯性
///controls.dynamicDampingFactor 阻尼系数 越小 则滑动越大
controls.rotateSpeed = 0.5;
controls.minDistance = 500;
controls.maxDistance = 6000;
//添加方法 渲染
controls.addEventListener("change", render);
//给table点击方法
var button = document.getElementById("table");
button.addEventListener(
"click",
function() {
//让每个元素移到达个数组里保存的坐标
transform(targets.table, 2000);
},
false
);
var button = document.getElementById("sphere");
button.addEventListener(
"click",
function() {
transform(targets.sphere, 2000);
},
false
);
var button = document.getElementById("helix");
button.addEventListener(
"click",
function() {
transform(targets.helix, 2000);
},
false
);
var button = document.getElementById("grid");
button.addEventListener(
"click",
function() {
transform(targets.grid, 2000);
},
false
);
//这个应该是才开始将位置从随机乱序变成正常的位置
transform(targets.table, 2000);
//
window.addEventListener("resize", onWindowResize, false);
}
function transform(targets, duration) {
//清除所有东西
TWEEN.removeAll();
for (var i = 0; i < objects.length; i++) {
var object = objects[i];
var target = targets[i];
//tween.js是一款可生成平滑动画效果的js动画库。
//只需要给她一个起点和终点 过程自己会生成
new TWEEN.Tween(object.position)
.to(
{
x: target.position.x,
y: target.position.y,
z: target.position.z
},
Math.random() * duration + duration
)
//为了平滑动画效果,你需要在同一个循环动画中调用TWEEN.update方法。
//easing函数仅在每个tween每次被更新时调用,而不管有多少属性被改变。结果随后会被用于初始值:
.easing(TWEEN.Easing.Exponential.InOut)
.start();
//rotation 旋转
new TWEEN.Tween(object.rotation)
.to(
{
x: target.rotation.x,
y: target.rotation.y,
z: target.rotation.z
},
Math.random() * duration + duration
)
.easing(TWEEN.Easing.Exponential.InOut)
.start();
}
//上面是单个元素块
new TWEEN.Tween(this)
.to({}, duration * 2)
.onUpdate(render)
.start();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
//时刻保持渲染器大小
renderer.setSize(window.innerWidth, window.innerHeight);
render();
}
//应该是优化动画
function animate() {
//requestAnimationFrame的方式的优势如下:
// 1.经过浏览器优化,动画更流畅
// 2.窗口没激活时,动画将停止,省计算资源
requestAnimationFrame(animate);
TWEEN.update();
controls.update();
}
//轨迹球控件的方法
//render(file,option),模板引擎就能自己渲染出视图,将视图模板的文件位置放入file,将传入的模板数据放入option对象中,
function render() {
renderer.render(scene, camera);
}
</script>
</body>
</html>