769 lines
27 KiB
HTML
769 lines
27 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>氯化钠晶胞结构 - 高中化学交互教学</title>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.min.js"></script>
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
|
||
}
|
||
|
||
body {
|
||
display: flex;
|
||
background: linear-gradient(135deg, #1a2a6c, #2c3e50);
|
||
color: #fff;
|
||
min-height: 100vh;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* 左侧控制面板样式 */
|
||
.control-panel {
|
||
width: 320px;
|
||
background: rgba(25, 35, 65, 0.85);
|
||
padding: 20px;
|
||
box-shadow: 5px 0 15px rgba(0, 0, 0, 0.4);
|
||
backdrop-filter: blur(10px);
|
||
overflow-y: auto;
|
||
height: 100vh;
|
||
z-index: 10;
|
||
}
|
||
|
||
.panel-title {
|
||
text-align: center;
|
||
margin-bottom: 25px;
|
||
padding-bottom: 15px;
|
||
border-bottom: 2px solid #3498db;
|
||
color: #4ecdc4;
|
||
font-size: 24px;
|
||
text-shadow: 0 0 10px rgba(78, 205, 196, 0.5);
|
||
}
|
||
|
||
.panel-description {
|
||
text-align: center;
|
||
margin-bottom: 20px;
|
||
color: #bdc3c7;
|
||
font-size: 16px;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.control-section {
|
||
margin-bottom: 25px;
|
||
padding: 15px;
|
||
background: rgba(30, 40, 70, 0.6);
|
||
border-radius: 10px;
|
||
border: 1px solid rgba(52, 152, 219, 0.3);
|
||
}
|
||
|
||
.section-title {
|
||
color: #3498db;
|
||
margin-bottom: 15px;
|
||
font-size: 18px;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.section-title i {
|
||
margin-right: 10px;
|
||
font-size: 20px;
|
||
}
|
||
|
||
.control-group {
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
label {
|
||
display: block;
|
||
margin-bottom: 8px;
|
||
color: #ecf0f1;
|
||
font-weight: 500;
|
||
}
|
||
|
||
input[type="range"] {
|
||
width: 100%;
|
||
margin-top: 5px;
|
||
height: 6px;
|
||
background: #2c3e50;
|
||
border-radius: 3px;
|
||
outline: none;
|
||
-webkit-appearance: none;
|
||
}
|
||
|
||
input[type="range"]::-webkit-slider-thumb {
|
||
-webkit-appearance: none;
|
||
width: 18px;
|
||
height: 18px;
|
||
background: #3498db;
|
||
border-radius: 50%;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.value-display {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
color: #bdc3c7;
|
||
font-size: 14px;
|
||
margin-top: 5px;
|
||
}
|
||
|
||
.checkbox-group {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.checkbox-group input {
|
||
margin-right: 10px;
|
||
width: 18px;
|
||
height: 18px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.checkbox-group label {
|
||
margin-bottom: 0;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.btn-group {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
margin-top: 15px;
|
||
}
|
||
|
||
button {
|
||
flex: 1;
|
||
min-width: 120px;
|
||
padding: 12px 15px;
|
||
background: linear-gradient(to right, #3498db, #2980b9);
|
||
color: white;
|
||
border: none;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
font-weight: 600;
|
||
transition: all 0.3s ease;
|
||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
|
||
}
|
||
|
||
button:hover {
|
||
background: linear-gradient(to right, #2980b9, #2573a7);
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.3);
|
||
}
|
||
|
||
button:active {
|
||
transform: translateY(1px);
|
||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||
}
|
||
|
||
.axis-btn-group {
|
||
display: flex;
|
||
gap: 10px;
|
||
}
|
||
|
||
.axis-btn-group button {
|
||
flex: 1;
|
||
padding: 10px;
|
||
min-width: auto;
|
||
}
|
||
|
||
/* 右侧主展示区样式 */
|
||
.main-display {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
position: relative;
|
||
padding: 20px;
|
||
}
|
||
|
||
.display-header {
|
||
text-align: center;
|
||
margin-bottom: 20px;
|
||
z-index: 5;
|
||
}
|
||
|
||
.main-title {
|
||
font-size: 32px;
|
||
color: #4ecdc4;
|
||
margin-bottom: 10px;
|
||
text-shadow: 0 0 15px rgba(78, 205, 196, 0.7);
|
||
}
|
||
|
||
.main-description {
|
||
font-size: 18px;
|
||
color: #ecf0f1;
|
||
max-width: 800px;
|
||
margin: 0 auto;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
#crystal-container {
|
||
flex: 1;
|
||
border-radius: 12px;
|
||
overflow: hidden;
|
||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
|
||
background: rgba(10, 20, 40, 0.4);
|
||
border: 1px solid rgba(52, 152, 219, 0.2);
|
||
}
|
||
|
||
.interaction-hint {
|
||
text-align: center;
|
||
padding: 15px;
|
||
background: rgba(25, 35, 65, 0.7);
|
||
border-radius: 8px;
|
||
margin-top: 20px;
|
||
color: #bdc3c7;
|
||
font-size: 16px;
|
||
border: 1px solid rgba(52, 152, 219, 0.3);
|
||
}
|
||
|
||
.legend {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 30px;
|
||
margin-top: 20px;
|
||
padding: 10px;
|
||
}
|
||
|
||
.legend-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.legend-color {
|
||
width: 20px;
|
||
height: 20px;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.na-color {
|
||
background: #3498db;
|
||
}
|
||
|
||
.cl-color {
|
||
background: #2ecc71;
|
||
}
|
||
|
||
.lattice-color {
|
||
background: #e74c3c;
|
||
width: 25px;
|
||
height: 3px;
|
||
border-radius: 0;
|
||
}
|
||
|
||
/* 响应式设计 */
|
||
@media (max-width: 1024px) {
|
||
body {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.control-panel {
|
||
width: 100%;
|
||
height: auto;
|
||
max-height: 50vh;
|
||
}
|
||
|
||
.main-display {
|
||
height: 50vh;
|
||
}
|
||
}
|
||
|
||
/* 装饰元素 */
|
||
.science-icon {
|
||
position: absolute;
|
||
opacity: 0.05;
|
||
font-size: 200px;
|
||
color: #3498db;
|
||
z-index: 0;
|
||
}
|
||
|
||
.icon-1 { top: 10%; left: 35%; }
|
||
.icon-2 { top: 40%; left: 70%; }
|
||
.icon-3 { top: 70%; left: 20%; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<!-- 左侧控制面板 -->
|
||
<div class="control-panel">
|
||
<h1 class="panel-title">岩盐结构</h1>
|
||
<p class="panel-description">NaCl晶体模型交互演示</p>
|
||
|
||
<!-- 离子半径设置 -->
|
||
<div class="control-section">
|
||
<h2 class="section-title">离子半径设置</h2>
|
||
<div class="control-group">
|
||
<label for="na-radius">钠离子半径</label>
|
||
<input type="range" id="na-radius" min="0.1" max="0.5" step="0.01" value="0.3">
|
||
<div class="value-display">
|
||
<span>0.1</span>
|
||
<span id="na-value">0.3</span>
|
||
<span>0.5</span>
|
||
</div>
|
||
</div>
|
||
<div class="control-group">
|
||
<label for="cl-radius">氯离子半径</label>
|
||
<input type="range" id="cl-radius" min="0.1" max="0.7" step="0.01" value="0.45">
|
||
<div class="value-display">
|
||
<span>0.1</span>
|
||
<span id="cl-value">0.45</span>
|
||
<span>0.7</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 视图控制 -->
|
||
<div class="control-section">
|
||
<h2 class="section-title">视图控制</h2>
|
||
<div class="checkbox-group">
|
||
<input type="checkbox" id="show-ions" checked>
|
||
<label for="show-ions">显示/隐藏离子</label>
|
||
</div>
|
||
<div class="checkbox-group">
|
||
<input type="checkbox" id="show-lattice" checked>
|
||
<label for="show-lattice">显示/隐藏晶胞</label>
|
||
</div>
|
||
|
||
<div class="btn-group">
|
||
<button id="show-octa">显示八面体</button>
|
||
<button id="only-octa">仅显示八面体</button>
|
||
<button id="cut-cell">切八分之一晶胞</button>
|
||
<button id="reset-view">重置视图</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 观察视角 -->
|
||
<div class="control-section">
|
||
<h2 class="section-title">观察视角</h2>
|
||
<div class="axis-btn-group">
|
||
<button id="view-x">X轴</button>
|
||
<button id="view-y">Y轴</button>
|
||
<button id="view-z">Z轴</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="control-section">
|
||
<h2 class="section-title">化学知识</h2>
|
||
<p style="color: #ecf0f1; line-height: 1.6; font-size: 15px;">
|
||
氯化钠晶体属于面心立方结构,其中钠离子(Na⁺)和氯离子(Cl⁻)交替排列。
|
||
每个离子周围都有6个带相反电荷的离子,形成八面体配位结构。
|
||
晶胞是晶体中最小的重复单元,边长约为0.564 nm。
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 右侧主展示区 -->
|
||
<div class="main-display">
|
||
<div class="display-header">
|
||
<h1 class="main-title">氯化钠晶胞结构学演示</h1>
|
||
<p class="main-description">高中化学交互式教学演示 - 探索岩盐的晶体结构及离子排列方式</p>
|
||
</div>
|
||
|
||
<!-- 3D展示容器 -->
|
||
<div id="crystal-container"></div>
|
||
|
||
<!-- 交互提示 -->
|
||
<div class="interaction-hint">
|
||
提示:您可以使用鼠标拖拽旋转视角,滚轮缩放视图,按住Shift键平移视图
|
||
</div>
|
||
|
||
<!-- 图例 -->
|
||
<div class="legend">
|
||
<div class="legend-item">
|
||
<div class="legend-color na-color"></div>
|
||
<span>钠离子 (Na⁺)</span>
|
||
</div>
|
||
<div class="legend-item">
|
||
<div class="legend-color cl-color"></div>
|
||
<span>氯离子 (Cl⁻)</span>
|
||
</div>
|
||
<div class="legend-item">
|
||
<div class="legend-color lattice-color"></div>
|
||
<span>晶胞边界</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 装饰图标 -->
|
||
<div class="science-icon icon-1">⚗️</div>
|
||
<div class="science-icon icon-2">🧪</div>
|
||
<div class="science-icon icon-3">🔬</div>
|
||
</div>
|
||
|
||
<script>
|
||
// 主要变量
|
||
let scene, camera, renderer, controls;
|
||
let naIons = [], clIons = [], latticeLines = [], octahedrons = [];
|
||
let naRadius = 0.3, clRadius = 0.45;
|
||
let isOctaVisible = false;
|
||
|
||
// 初始化场景
|
||
function init() {
|
||
// 创建场景
|
||
scene = new THREE.Scene();
|
||
scene.background = new THREE.Color(0x0c1428);
|
||
|
||
// 创建相机
|
||
camera = new THREE.PerspectiveCamera(75, window.innerWidth / (window.innerHeight - 80), 0.1, 1000);
|
||
camera.position.set(2, 2, 2);
|
||
|
||
// 创建渲染器
|
||
const container = document.getElementById('crystal-container');
|
||
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
|
||
renderer.setSize(container.clientWidth, container.clientHeight);
|
||
container.appendChild(renderer.domElement);
|
||
|
||
// 添加轨道控制
|
||
controls = new THREE.OrbitControls(camera, renderer.domElement);
|
||
controls.enableDamping = true;
|
||
controls.dampingFactor = 0.05;
|
||
|
||
// 添加光源
|
||
const ambientLight = new THREE.AmbientLight(0x404040, 1.5);
|
||
scene.add(ambientLight);
|
||
|
||
const directionalLight1 = new THREE.DirectionalLight(0xffffff, 0.8);
|
||
directionalLight1.position.set(1, 1, 1);
|
||
scene.add(directionalLight1);
|
||
|
||
const directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.5);
|
||
directionalLight2.position.set(-1, -1, -1);
|
||
scene.add(directionalLight2);
|
||
|
||
// 创建坐标轴辅助
|
||
const axesHelper = new THREE.AxesHelper(2);
|
||
scene.add(axesHelper);
|
||
|
||
// 创建晶胞结构
|
||
createCrystalStructure();
|
||
|
||
// 添加事件监听器
|
||
setupEventListeners();
|
||
|
||
// 开始动画循环
|
||
animate();
|
||
|
||
// 窗口大小调整监听
|
||
window.addEventListener('resize', onWindowResize);
|
||
}
|
||
|
||
// 创建氯化钠晶胞结构
|
||
function createCrystalStructure() {
|
||
// 清除现有对象
|
||
naIons.forEach(ion => scene.remove(ion));
|
||
clIons.forEach(ion => scene.remove(ion));
|
||
latticeLines.forEach(line => scene.remove(line));
|
||
octahedrons.forEach(octa => scene.remove(octa));
|
||
|
||
naIons = [];
|
||
clIons = [];
|
||
latticeLines = [];
|
||
octahedrons = [];
|
||
|
||
// 钠离子位置(面心立方)
|
||
const naPositions = [
|
||
[0, 0, 0], [0.5, 0.5, 0], [0.5, 0, 0.5], [0, 0.5, 0.5],
|
||
[1, 0, 0], [1, 0.5, 0.5], [0.5, 1, 0], [0, 1, 0.5],
|
||
[0, 0, 1], [0.5, 0.5, 1], [0.5, 0, 1], [0, 0.5, 1],
|
||
[1, 0, 1], [1, 0.5, 1], [0.5, 1, 1], [0, 1, 1]
|
||
];
|
||
|
||
// 氯离子位置(面心立方,偏移)
|
||
const clPositions = [
|
||
[0.5, 0, 0], [0, 0.5, 0], [0, 0, 0.5], [0.5, 0.5, 0.5],
|
||
[0.5, 1, 0], [0, 1, 0.5], [1, 0.5, 0], [1, 0, 0.5],
|
||
[0.5, 0, 1], [0, 0.5, 1], [0, 0, 1.5], [0.5, 0.5, 1.5],
|
||
[0.5, 1, 1], [0, 1, 1.5], [1, 0.5, 1], [1, 0, 1.5]
|
||
];
|
||
|
||
// 创建钠离子(蓝色)
|
||
const naGeometry = new THREE.SphereGeometry(naRadius, 32, 32);
|
||
const naMaterial = new THREE.MeshPhongMaterial({
|
||
color: 0x3498db,
|
||
shininess: 100,
|
||
specular: 0xffffff
|
||
});
|
||
|
||
naPositions.forEach(pos => {
|
||
const naIon = new THREE.Mesh(naGeometry, naMaterial);
|
||
naIon.position.set(pos[0], pos[1], pos[2]);
|
||
scene.add(naIon);
|
||
naIons.push(naIon);
|
||
});
|
||
|
||
// 创建氯离子(绿色)
|
||
const clGeometry = new THREE.SphereGeometry(clRadius, 32, 32);
|
||
const clMaterial = new THREE.MeshPhongMaterial({
|
||
color: 0x2ecc71,
|
||
shininess: 100,
|
||
specular: 0xffffff
|
||
});
|
||
|
||
clPositions.forEach(pos => {
|
||
const clIon = new THREE.Mesh(clGeometry, clMaterial);
|
||
clIon.position.set(pos[0], pos[1], pos[2]);
|
||
scene.add(clIon);
|
||
clIons.push(clIon);
|
||
});
|
||
|
||
// 创建晶胞边界(红色线框)
|
||
const latticeMaterial = new THREE.LineBasicMaterial({ color: 0xe74c3c });
|
||
|
||
// 底部
|
||
createLatticeLine([0,0,0], [1,0,0], latticeMaterial);
|
||
createLatticeLine([1,0,0], [1,0,1], latticeMaterial);
|
||
createLatticeLine([1,0,1], [0,0,1], latticeMaterial);
|
||
createLatticeLine([0,0,1], [0,0,0], latticeMaterial);
|
||
|
||
// 顶部
|
||
createLatticeLine([0,1,0], [1,1,0], latticeMaterial);
|
||
createLatticeLine([1,1,0], [1,1,1], latticeMaterial);
|
||
createLatticeLine([1,1,1], [0,1,1], latticeMaterial);
|
||
createLatticeLine([0,1,1], [0,1,0], latticeMaterial);
|
||
|
||
// 侧面
|
||
createLatticeLine([0,0,0], [0,1,0], latticeMaterial);
|
||
createLatticeLine([1,0,0], [1,1,0], latticeMaterial);
|
||
createLatticeLine([1,0,1], [1,1,1], latticeMaterial);
|
||
createLatticeLine([0,0,1], [0,1,1], latticeMaterial);
|
||
|
||
// 创建八面体结构(中心位置)
|
||
createOctahedron(0.5, 0.5, 0.5);
|
||
}
|
||
|
||
// 创建晶格线
|
||
function createLatticeLine(start, end, material) {
|
||
const points = [];
|
||
points.push(new THREE.Vector3(start[0], start[1], start[2]));
|
||
points.push(new THREE.Vector3(end[0], end[1], end[2]));
|
||
|
||
const geometry = new THREE.BufferGeometry().setFromPoints(points);
|
||
const line = new THREE.Line(geometry, material);
|
||
scene.add(line);
|
||
latticeLines.push(line);
|
||
}
|
||
|
||
// 创建八面体结构
|
||
function createOctahedron(x, y, z) {
|
||
const octaGroup = new THREE.Group();
|
||
|
||
// 中心钠离子
|
||
const centerGeometry = new THREE.SphereGeometry(naRadius * 1.2, 32, 32);
|
||
const centerMaterial = new THREE.MeshPhongMaterial({
|
||
color: 0x3498db,
|
||
emissive: 0x0044aa,
|
||
shininess: 100
|
||
});
|
||
const centerIon = new THREE.Mesh(centerGeometry, centerMaterial);
|
||
centerIon.position.set(x, y, z);
|
||
octaGroup.add(centerIon);
|
||
|
||
// 六个氯离子(八面体顶点)
|
||
const vertices = [
|
||
[x, y, z - 0.7], // 下方
|
||
[x, y, z + 0.7], // 上方
|
||
[x, y - 0.7, z], // 前方
|
||
[x, y + 0.7, z], // 后方
|
||
[x - 0.7, y, z], // 左侧
|
||
[x + 0.7, y, z] // 右侧
|
||
];
|
||
|
||
const vertexGeometry = new THREE.SphereGeometry(clRadius * 1.2, 32, 32);
|
||
const vertexMaterial = new THREE.MeshPhongMaterial({
|
||
color: 0x2ecc71,
|
||
emissive: 0x008844,
|
||
shininess: 100
|
||
});
|
||
|
||
vertices.forEach(v => {
|
||
const vertex = new THREE.Mesh(vertexGeometry, vertexMaterial);
|
||
vertex.position.set(v[0], v[1], v[2]);
|
||
octaGroup.add(vertex);
|
||
});
|
||
|
||
// 八面体边(连接中心到顶点)
|
||
const edgeMaterial = new THREE.LineBasicMaterial({
|
||
color: 0xf39c12,
|
||
linewidth: 2,
|
||
transparent: true,
|
||
opacity: 0.7
|
||
});
|
||
|
||
vertices.forEach(v => {
|
||
const points = [];
|
||
points.push(new THREE.Vector3(x, y, z));
|
||
points.push(new THREE.Vector3(v[0], v[1], v[2]));
|
||
|
||
const geometry = new THREE.BufferGeometry().setFromPoints(points);
|
||
const line = new THREE.Line(geometry, edgeMaterial);
|
||
octaGroup.add(line);
|
||
});
|
||
|
||
// 八面体面
|
||
const faces = [
|
||
[vertices[0], vertices[2], vertices[4]],
|
||
[vertices[0], vertices[2], vertices[5]],
|
||
[vertices[0], vertices[3], vertices[4]],
|
||
[vertices[0], vertices[3], vertices[5]],
|
||
[vertices[1], vertices[2], vertices[4]],
|
||
[vertices[1], vertices[2], vertices[5]],
|
||
[vertices[1], vertices[3], vertices[4]],
|
||
[vertices[1], vertices[3], vertices[5]]
|
||
];
|
||
|
||
const faceMaterial = new THREE.MeshBasicMaterial({
|
||
color: 0xf39c12,
|
||
transparent: true,
|
||
opacity: 0.15,
|
||
side: THREE.DoubleSide
|
||
});
|
||
|
||
faces.forEach(face => {
|
||
const geometry = new THREE.BufferGeometry();
|
||
const vertices = [
|
||
new THREE.Vector3(face[0][0], face[0][1], face[0][2]),
|
||
new THREE.Vector3(face[1][0], face[1][1], face[1][2]),
|
||
new THREE.Vector3(face[2][0], face[2][1], face[2][2])
|
||
];
|
||
|
||
geometry.setFromPoints(vertices);
|
||
geometry.computeVertexNormals();
|
||
|
||
const triangle = new THREE.Mesh(geometry, faceMaterial);
|
||
octaGroup.add(triangle);
|
||
});
|
||
|
||
octaGroup.visible = isOctaVisible;
|
||
scene.add(octaGroup);
|
||
octahedrons.push(octaGroup);
|
||
}
|
||
|
||
// 设置事件监听器
|
||
function setupEventListeners() {
|
||
// 离子半径控制
|
||
document.getElementById('na-radius').addEventListener('input', function() {
|
||
naRadius = parseFloat(this.value);
|
||
document.getElementById('na-value').textContent = naRadius.toFixed(2);
|
||
createCrystalStructure();
|
||
});
|
||
|
||
document.getElementById('cl-radius').addEventListener('input', function() {
|
||
clRadius = parseFloat(this.value);
|
||
document.getElementById('cl-value').textContent = clRadius.toFixed(2);
|
||
createCrystalStructure();
|
||
});
|
||
|
||
// 显示/隐藏离子
|
||
document.getElementById('show-ions').addEventListener('change', function() {
|
||
const isVisible = this.checked;
|
||
naIons.forEach(ion => ion.visible = isVisible);
|
||
clIons.forEach(ion => ion.visible = isVisible);
|
||
});
|
||
|
||
// 显示/隐藏晶胞
|
||
document.getElementById('show-lattice').addEventListener('change', function() {
|
||
latticeLines.forEach(line => line.visible = this.checked);
|
||
});
|
||
|
||
// 显示八面体
|
||
document.getElementById('show-octa').addEventListener('click', function() {
|
||
isOctaVisible = true;
|
||
octahedrons.forEach(octa => octa.visible = true);
|
||
});
|
||
|
||
// 仅显示八面体
|
||
document.getElementById('only-octa').addEventListener('click', function() {
|
||
isOctaVisible = true;
|
||
octahedrons.forEach(octa => octa.visible = true);
|
||
|
||
naIons.forEach(ion => ion.visible = false);
|
||
clIons.forEach(ion => ion.visible = false);
|
||
latticeLines.forEach(line => line.visible = false);
|
||
|
||
document.getElementById('show-ions').checked = false;
|
||
document.getElementById('show-lattice').checked = false;
|
||
});
|
||
|
||
// 切八分之一晶胞
|
||
document.getElementById('cut-cell').addEventListener('click', function() {
|
||
naIons.forEach(ion => {
|
||
const pos = ion.position;
|
||
ion.visible = (pos.x <= 0.5 && pos.y <= 0.5 && pos.z <= 0.5);
|
||
});
|
||
|
||
clIons.forEach(ion => {
|
||
const pos = ion.position;
|
||
ion.visible = (pos.x <= 0.5 && pos.y <= 0.5 && pos.z <= 0.5);
|
||
});
|
||
|
||
latticeLines.forEach(line => line.visible = false);
|
||
document.getElementById('show-lattice').checked = false;
|
||
});
|
||
|
||
// 重置视图
|
||
document.getElementById('reset-view').addEventListener('click', function() {
|
||
// 重置相机位置
|
||
camera.position.set(2, 2, 2);
|
||
camera.lookAt(0, 0, 0);
|
||
controls.reset();
|
||
|
||
// 重置参数
|
||
naRadius = 0.3;
|
||
clRadius = 0.45;
|
||
|
||
document.getElementById('na-radius').value = naRadius;
|
||
document.getElementById('cl-radius').value = clRadius;
|
||
document.getElementById('na-value').textContent = naRadius.toFixed(2);
|
||
document.getElementById('cl-value').textContent = clRadius.toFixed(2);
|
||
|
||
document.getElementById('show-ions').checked = true;
|
||
document.getElementById('show-lattice').checked = true;
|
||
|
||
isOctaVisible = false;
|
||
createCrystalStructure();
|
||
});
|
||
|
||
// 视角控制
|
||
document.getElementById('view-x').addEventListener('click', function() {
|
||
camera.position.set(3, 0, 0);
|
||
camera.lookAt(0, 0, 0);
|
||
controls.update();
|
||
});
|
||
|
||
document.getElementById('view-y').addEventListener('click', function() {
|
||
camera.position.set(0, 3, 0);
|
||
camera.lookAt(0, 0, 0);
|
||
controls.update();
|
||
});
|
||
|
||
document.getElementById('view-z').addEventListener('click', function() {
|
||
camera.position.set(0, 0, 3);
|
||
camera.lookAt(0, 0, 0);
|
||
controls.update();
|
||
});
|
||
}
|
||
|
||
// 窗口大小调整处理
|
||
function onWindowResize() {
|
||
const container = document.getElementById('crystal-container');
|
||
camera.aspect = container.clientWidth / container.clientHeight;
|
||
camera.updateProjectionMatrix();
|
||
renderer.setSize(container.clientWidth, container.clientHeight);
|
||
}
|
||
|
||
// 动画循环
|
||
function animate() {
|
||
requestAnimationFrame(animate);
|
||
controls.update();
|
||
renderer.render(scene, camera);
|
||
}
|
||
|
||
// 页面加载完成后初始化
|
||
window.addEventListener('load', init);
|
||
</script>
|
||
</body>
|
||
</html> |