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

785 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>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Microsoft YaHei', Arial, sans-serif;
}
body {
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #1a2a6c);
color: #fff;
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
header {
grid-column: 1 / -1;
text-align: center;
padding: 20px;
background: rgba(0, 0, 0, 0.3);
border-radius: 15px;
margin-bottom: 20px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}
h1 {
font-size: 2.5rem;
margin-bottom: 10px;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
}
.subtitle {
font-size: 1.2rem;
opacity: 0.9;
}
.panel {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 15px;
padding: 20px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.18);
}
.panel-title {
font-size: 1.5rem;
margin-bottom: 15px;
text-align: center;
color: #ffcc00;
text-shadow: 0 0 10px rgba(255, 204, 0, 0.5);
}
.simulation-area {
position: relative;
height: 400px;
background: linear-gradient(to bottom, #87CEEB, #1E90FF);
border-radius: 10px;
overflow: hidden;
margin-bottom: 20px;
}
.liquid {
position: absolute;
bottom: 0;
width: 100%;
height: 60%;
background: rgba(30, 144, 255, 0.7);
}
.liquid-surface {
position: absolute;
width: 100%;
height: 2px;
background: rgba(255, 255, 255, 0.5);
bottom: 40%; /* 液面高度为60% */
}
.object {
position: absolute;
width: 60px;
height: 60px;
background: #FF6B6B;
border: 2px solid #fff;
border-radius: 5px;
cursor: move;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
transition: all 0.3s ease;
}
.object.dragging {
box-shadow: 0 0 15px #FFD700;
z-index: 10;
}
.force-diagram {
height: 400px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
}
.force-arrow {
position: absolute;
width: 8px;
transform-origin: bottom center;
}
.gravity-arrow {
background: #FF6B6B;
left: 50%;
bottom: 50%;
transform: translateX(-50%);
}
.buoyancy-arrow {
background: #4ECDC4;
left: 50%;
bottom: 50%;
transform: translateX(-50%) rotate(180deg);
}
.arrow-head {
position: absolute;
top: -10px;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
}
.gravity-arrow .arrow-head {
border-top: 15px solid #FF6B6B;
}
.buoyancy-arrow .arrow-head {
border-bottom: 15px solid #4ECDC4;
top: auto;
bottom: -10px;
}
.force-label {
position: absolute;
font-size: 14px;
font-weight: bold;
white-space: nowrap;
}
.gravity-label {
color: #FF6B6B;
top: -30px;
left: 50%;
transform: translateX(-50%);
}
.buoyancy-label {
color: #4ECDC4;
bottom: -30px;
left: 50%;
transform: translateX(-50%);
}
.controls {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
margin-top: 20px;
}
.control-group {
background: rgba(0, 0, 0, 0.2);
padding: 15px;
border-radius: 10px;
}
.control-label {
display: block;
margin-bottom: 8px;
font-weight: bold;
}
.slider-container {
display: flex;
align-items: center;
}
input[type="range"] {
flex: 1;
height: 8px;
-webkit-appearance: none;
background: rgba(255, 255, 255, 0.2);
border-radius: 4px;
outline: none;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: #FFD700;
cursor: pointer;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
}
.value-display {
width: 60px;
text-align: right;
font-weight: bold;
color: #FFD700;
}
.scenarios {
display: flex;
justify-content: space-between;
margin-top: 20px;
}
.scenario-btn {
flex: 1;
margin: 0 5px;
padding: 12px;
background: rgba(255, 255, 255, 0.15);
border: none;
border-radius: 8px;
color: white;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
}
.scenario-btn:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
}
.scenario-btn.active {
background: #FFD700;
color: #1a2a6c;
box-shadow: 0 0 15px rgba(255, 215, 0, 0.5);
}
.formula-area {
margin-top: 20px;
padding: 15px;
background: rgba(0, 0, 0, 0.2);
border-radius: 10px;
}
.formula {
font-size: 1.2rem;
text-align: center;
margin: 15px 0;
font-family: 'Cambria Math', serif;
}
.condition {
text-align: center;
font-size: 1.1rem;
margin: 10px 0;
padding: 10px;
border-radius: 8px;
font-weight: bold;
}
.condition.floating {
background: rgba(78, 205, 196, 0.3);
color: #4ECDC4;
}
.condition.sinking {
background: rgba(255, 107, 107, 0.3);
color: #FF6B6B;
}
.condition.suspended {
background: rgba(255, 215, 0, 0.3);
color: #FFD700;
}
.condition.submerged {
background: rgba(106, 90, 205, 0.3);
color: #6A5ACD;
}
.explanation {
margin-top: 15px;
font-size: 0.95rem;
line-height: 1.5;
}
.status-indicator {
display: flex;
justify-content: space-around;
margin-top: 15px;
}
.status-item {
text-align: center;
padding: 8px;
border-radius: 8px;
font-size: 0.9rem;
flex: 1;
margin: 0 5px;
opacity: 0.7;
transition: all 0.3s;
}
.status-item.active {
opacity: 1;
transform: scale(1.05);
box-shadow: 0 0 10px rgba(255, 215, 0, 0.5);
}
.status-item.floating {
background: rgba(78, 205, 196, 0.3);
border: 1px solid #4ECDC4;
}
.status-item.suspended {
background: rgba(255, 215, 0, 0.3);
border: 1px solid #FFD700;
}
.status-item.sinking {
background: rgba(255, 107, 107, 0.3);
border: 1px solid #FF6B6B;
}
.status-item.submerged {
background: rgba(106, 90, 205, 0.3);
border: 1px solid #6A5ACD;
}
footer {
grid-column: 1 / -1;
text-align: center;
padding: 20px;
margin-top: 20px;
background: rgba(0, 0, 0, 0.3);
border-radius: 15px;
font-size: 0.9rem;
opacity: 0.8;
}
@media (max-width: 768px) {
.container {
grid-template-columns: 1fr;
}
.scenarios {
flex-direction: column;
}
.scenario-btn {
margin: 5px 0;
}
.status-indicator {
flex-wrap: wrap;
}
.status-item {
flex: 0 0 45%;
margin: 5px;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>浮力仿真实验室</h1>
<p class="subtitle">精确模拟物体在液体中的四种浮沉状态</p>
</header>
<div class="panel">
<h2 class="panel-title">实时仿真实验区</h2>
<div class="simulation-area">
<div class="liquid"></div>
<div class="liquid-surface"></div>
<div class="object" id="draggable-object">物体</div>
</div>
<div class="controls">
<div class="control-group">
<label class="control-label">物体密度 (kg/m³)</label>
<div class="slider-container">
<input type="range" id="object-density" min="100" max="2000" value="800" step="10">
<span class="value-display" id="object-density-value">800</span>
</div>
</div>
<div class="control-group">
<label class="control-label">液体密度 (kg/m³)</label>
<div class="slider-container">
<input type="range" id="liquid-density" min="500" max="2000" value="1000" step="10">
<span class="value-display" id="liquid-density-value">1000</span>
</div>
</div>
</div>
<div class="scenarios">
<button class="scenario-btn active" data-scenario="wood">木块漂浮</button>
<button class="scenario-btn" data-scenario="submarine">潜水艇悬浮</button>
<button class="scenario-btn" data-scenario="stone">石块沉底</button>
<button class="scenario-btn" data-scenario="iron">铁块沉没悬浮</button>
</div>
<div class="status-indicator">
<div class="status-item floating" id="floating-status">漂浮</div>
<div class="status-item suspended" id="suspended-status">悬浮</div>
<div class="status-item sinking" id="sinking-status">沉底</div>
<div class="status-item submerged" id="submerged-status">沉没悬浮</div>
</div>
</div>
<div class="panel">
<h2 class="panel-title">动态受力分析</h2>
<div class="force-diagram">
<div class="force-arrow gravity-arrow" id="gravity-arrow">
<div class="arrow-head"></div>
<div class="force-label gravity-label" id="gravity-label">重力: 0 N</div>
</div>
<div class="force-arrow buoyancy-arrow" id="buoyancy-arrow">
<div class="arrow-head"></div>
<div class="force-label buoyancy-label" id="buoyancy-label">浮力: 0 N</div>
</div>
</div>
<div class="formula-area">
<div class="formula">F<sub></sub> = ρ<sub></sub> × g × V<sub></sub></div>
<div class="formula">G = m × g = ρ<sub></sub> × V<sub></sub> × g</div>
<div class="condition" id="condition-display">
物体悬浮 (F<sub></sub> = G)
</div>
<div class="explanation" id="explanation">
当物体密度等于液体密度时,物体悬浮在液体中。
</div>
<div class="explanation">
<strong>四种浮沉状态:</strong>
<ul style="margin-top: 10px; padding-left: 20px;">
<li><span style="color: #4ECDC4">漂浮</span>: ρ<sub></sub> < ρ<sub></sub>,物体部分露出液面</li>
<li><span style="color: #FFD700">悬浮</span>: ρ<sub></sub> = ρ<sub></sub>,物体完全浸没但不沉底</li>
<li><span style="color: #FF6B6B">沉底</span>: ρ<sub></sub> > ρ<sub></sub>,物体沉到容器底部</li>
<li><span style="color: #6A5ACD">沉没悬浮</span>: 沉底但未完全浸没</li>
</ul>
</div>
</div>
</div>
<footer>
<p>浮力仿真实验室改进版 | 基于阿基米德原理 | 精确模拟四种浮沉状态</p>
</footer>
</div>
<script>
// 获取DOM元素
const draggableObject = document.getElementById('draggable-object');
const objectDensitySlider = document.getElementById('object-density');
const liquidDensitySlider = document.getElementById('liquid-density');
const objectDensityValue = document.getElementById('object-density-value');
const liquidDensityValue = document.getElementById('liquid-density-value');
const gravityArrow = document.getElementById('gravity-arrow');
const buoyancyArrow = document.getElementById('buoyancy-arrow');
const gravityLabel = document.getElementById('gravity-label');
const buoyancyLabel = document.getElementById('buoyancy-label');
const conditionDisplay = document.getElementById('condition-display');
const explanation = document.getElementById('explanation');
const scenarioButtons = document.querySelectorAll('.scenario-btn');
// 状态指示器
const floatingStatus = document.getElementById('floating-status');
const suspendedStatus = document.getElementById('suspended-status');
const sinkingStatus = document.getElementById('sinking-status');
const submergedStatus = document.getElementById('submerged-status');
// 物理常数
const GRAVITY = 9.8; // 重力加速度 m/s²
const OBJECT_VOLUME = 0.001; // 物体体积 m³ (1立方分米)
// 容器尺寸
const CONTAINER_HEIGHT = 400; // 容器高度px
const LIQUID_HEIGHT_PERCENT = 0.6; // 液体占容器高度的比例
const LIQUID_SURFACE_Y = CONTAINER_HEIGHT * (1 - LIQUID_HEIGHT_PERCENT); // 液面位置
const OBJECT_HEIGHT = 60; // 物体高度px
// 当前状态
let isDragging = false;
let objectPosition = { x: 50, y: 150 };
let objectDensity = 800;
let liquidDensity = 1000;
let currentStatus = 'suspended'; // 初始状态
// 初始化物体位置
updateObjectPosition();
// 拖拽功能
draggableObject.addEventListener('mousedown', startDrag);
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', endDrag);
// 触摸设备支持
draggableObject.addEventListener('touchstart', handleTouchStart);
document.addEventListener('touchmove', handleTouchMove);
document.addEventListener('touchend', endDrag);
function handleTouchStart(e) {
e.preventDefault();
startDrag(e.touches[0]);
}
function handleTouchMove(e) {
e.preventDefault();
if (isDragging) {
drag(e.touches[0]);
}
}
function startDrag(e) {
isDragging = true;
draggableObject.classList.add('dragging');
const rect = draggableObject.getBoundingClientRect();
objectPosition.offsetX = e.clientX - rect.left;
objectPosition.offsetY = e.clientY - rect.top;
}
function drag(e) {
if (!isDragging) return;
const simulationArea = document.querySelector('.simulation-area');
const areaRect = simulationArea.getBoundingClientRect();
let newX = e.clientX - areaRect.left - objectPosition.offsetX;
let newY = e.clientY - areaRect.top - objectPosition.offsetY;
// 限制在容器内
newX = Math.max(0, Math.min(newX, areaRect.width - draggableObject.offsetWidth));
newY = Math.max(0, Math.min(newY, areaRect.height - draggableObject.offsetHeight));
objectPosition.x = newX;
objectPosition.y = newY;
updateObjectPosition();
}
function endDrag() {
isDragging = false;
draggableObject.classList.remove('dragging');
// 拖拽结束后重新计算位置
updatePositionBasedOnDensity();
}
function updateObjectPosition() {
draggableObject.style.left = `${objectPosition.x}px`;
draggableObject.style.top = `${objectPosition.y}px`;
}
// 密度滑块事件
objectDensitySlider.addEventListener('input', function() {
objectDensity = parseInt(this.value);
objectDensityValue.textContent = objectDensity;
updatePositionBasedOnDensity();
});
liquidDensitySlider.addEventListener('input', function() {
liquidDensity = parseInt(this.value);
liquidDensityValue.textContent = liquidDensity;
updatePositionBasedOnDensity();
});
// 场景切换
scenarioButtons.forEach(button => {
button.addEventListener('click', function() {
// 移除所有按钮的active类
scenarioButtons.forEach(btn => btn.classList.remove('active'));
// 为当前按钮添加active类
this.classList.add('active');
const scenario = this.dataset.scenario;
applyScenario(scenario);
});
});
function applyScenario(scenario) {
switch(scenario) {
case 'wood': // 木块漂浮
objectDensity = 600;
liquidDensity = 1000;
break;
case 'submarine': // 潜水艇悬浮
objectDensity = 1000;
liquidDensity = 1000;
break;
case 'stone': // 石块沉底
objectDensity = 2500;
liquidDensity = 1000;
break;
case 'iron': // 铁块沉没悬浮
objectDensity = 1200;
liquidDensity = 1000;
break;
}
// 更新滑块和显示值
objectDensitySlider.value = objectDensity;
liquidDensitySlider.value = liquidDensity;
objectDensityValue.textContent = objectDensity;
liquidDensityValue.textContent = liquidDensity;
updatePositionBasedOnDensity();
}
// 根据密度关系更新物体位置
function updatePositionBasedOnDensity() {
const simulationArea = document.querySelector('.simulation-area');
const areaWidth = simulationArea.offsetWidth;
const areaHeight = simulationArea.offsetHeight;
// 默认位置为中央
objectPosition.x = (areaWidth - draggableObject.offsetWidth) / 2;
// 计算物体在液体中的位置
if (objectDensity < liquidDensity) {
// 漂浮状态 - 部分露出液面
const immersionRatio = objectDensity / liquidDensity; // 浸入深度比例
const immersedHeight = OBJECT_HEIGHT * immersionRatio; // 浸入部分高度
objectPosition.y = LIQUID_SURFACE_Y - OBJECT_HEIGHT + immersedHeight;
currentStatus = 'floating';
} else if (objectDensity === liquidDensity) {
// 悬浮状态 - 完全浸没但不沉底
objectPosition.y = (LIQUID_SURFACE_Y + areaHeight) / 2 - OBJECT_HEIGHT / 2;
currentStatus = 'suspended';
} else {
// 沉底或沉没悬浮状态
objectPosition.y = areaHeight - OBJECT_HEIGHT; // 沉到底部
// 检查是否完全浸没
const objectBottom = objectPosition.y + OBJECT_HEIGHT;
if (objectBottom > LIQUID_SURFACE_Y) {
// 物体部分在液体中(沉没但未完全浸没)
currentStatus = 'submerged';
} else {
// 完全沉底
currentStatus = 'sinking';
}
}
// 确保位置在容器范围内
objectPosition.y = Math.max(0, Math.min(objectPosition.y, areaHeight - OBJECT_HEIGHT));
updateObjectPosition();
updateSimulation();
}
// 更新仿真
function updateSimulation() {
// 计算重力和浮力
const gravity = objectDensity * OBJECT_VOLUME * GRAVITY;
// 计算浮力 - 取决于浸入体积
let buoyancy = 0;
const objectBottomY = objectPosition.y + OBJECT_HEIGHT;
if (objectBottomY <= LIQUID_SURFACE_Y) {
// 物体完全在液面上方浮力为0
buoyancy = 0;
} else if (objectPosition.y >= LIQUID_SURFACE_Y) {
// 物体完全在液体中
buoyancy = liquidDensity * OBJECT_VOLUME * GRAVITY;
} else {
// 物体部分在液体中
const immersedHeight = objectBottomY - LIQUID_SURFACE_Y;
const immersedRatio = immersedHeight / OBJECT_HEIGHT;
const immersedVolume = OBJECT_VOLUME * immersedRatio;
buoyancy = liquidDensity * immersedVolume * GRAVITY;
}
// 更新力的显示
updateForceArrows(gravity, buoyancy);
// 更新状态显示
updateStatusDisplay();
// 更新物体颜色
updateObjectColor();
}
function updateForceArrows(gravity, buoyancy) {
// 箭头长度与力的大小成正比
const maxLength = 200;
const maxForce = 20; // 最大力值(牛顿)
const gravityHeight = Math.min(maxLength, (gravity / maxForce) * maxLength);
const buoyancyHeight = Math.min(maxLength, (buoyancy / maxForce) * maxLength);
gravityArrow.style.height = `${gravityHeight}px`;
buoyancyArrow.style.height = `${buoyancyHeight}px`;
gravityLabel.textContent = `重力: ${gravity.toFixed(2)} N`;
buoyancyLabel.textContent = `浮力: ${buoyancy.toFixed(2)} N`;
}
function updateStatusDisplay() {
// 更新状态指示器
floatingStatus.classList.remove('active');
suspendedStatus.classList.remove('active');
sinkingStatus.classList.remove('active');
submergedStatus.classList.remove('active');
switch(currentStatus) {
case 'floating':
conditionDisplay.innerHTML = '物体漂浮 (F<sub>浮</sub> = G)';
conditionDisplay.className = 'condition floating';
explanation.textContent = '当物体密度小于液体密度时,物体漂浮在液面上。此时浮力等于重力。';
floatingStatus.classList.add('active');
break;
case 'suspended':
conditionDisplay.innerHTML = '物体悬浮 (F<sub>浮</sub> = G)';
conditionDisplay.className = 'condition suspended';
explanation.textContent = '当物体密度等于液体密度时,物体悬浮在液体中任何位置。此时浮力等于重力。';
suspendedStatus.classList.add('active');
break;
case 'sinking':
conditionDisplay.innerHTML = '物体沉底 (F<sub>浮</sub> < G)';
conditionDisplay.className = 'condition sinking';
explanation.textContent = '当物体密度大于液体密度时,物体沉到容器底部。此时浮力小于重力。';
sinkingStatus.classList.add('active');
break;
case 'submerged':
conditionDisplay.innerHTML = '沉没悬浮 (F<sub>浮</sub> < G)';
conditionDisplay.className = 'condition submerged';
explanation.textContent = '物体沉到底部但未完全浸没。此时浮力小于重力,容器底部提供支持力。';
submergedStatus.classList.add('active');
break;
}
}
function updateObjectColor() {
switch(currentStatus) {
case 'floating':
draggableObject.style.background = '#4ECDC4'; // 青色
break;
case 'suspended':
draggableObject.style.background = '#FFD700'; // 金色
break;
case 'sinking':
draggableObject.style.background = '#FF6B6B'; // 红色
break;
case 'submerged':
draggableObject.style.background = '#6A5ACD'; // 紫色
break;
}
}
// 初始化仿真
updatePositionBasedOnDensity();
</script>
</body>
</html>