Files
dsProject/dsLightRag/static/deepseek_fulishiyanshi.html

785 lines
27 KiB
HTML
Raw Normal View History

2025-08-14 15:45:08 +08:00
<!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>