Files
dsProject/dsLightRag/static/deepseek_html_20250812_5fd0ec.html
2025-08-14 15:45:08 +08:00

769 lines
27 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>