独立渲染引擎就绪引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EPM无人机吊装系统 - IFR理想最终解原理演示</title>
<style>
:root {
--bg-color: #0b1120;
--grid-color: #1e293b;
--text-main: #f8fafc;
--text-dim: #94a3b8;
--accent-cyan: #06b6d4;
--accent-glow: #22d3ee;
--accent-green: #10b981;
--accent-red: #ef4444;
--metal-light: #cbd5e1;
--metal-dark: #475569;
--warning: #f59e0b;
}
body {
margin: 0;
padding: 0;
background-color: var(--bg-color);
color: var(--text-main);
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
overflow: hidden;
background-image:
linear-gradient(rgba(30, 41, 59, 0.3) 1px, transparent 1px),
linear-gradient(90deg, rgba(30, 41, 59, 0.3) 1px, transparent 1px);
background-size: 40px 40px;
}
#animation-container {
width: 100%;
height: 100%;
max-width: 1600px;
max-height: 900px;
position: relative;
box-shadow: 0 0 100px rgba(6, 182, 212, 0.05) inset;
}
svg {
width: 100%;
height: 100%;
}
.hud-text {
font-family: 'Courier New', Courier, monospace;
font-size: 14px;
fill: var(--text-dim);
letter-spacing: 1px;
}
.hud-value {
font-family: 'Courier New', Courier, monospace;
font-size: 16px;
fill: var(--text-main);
font-weight: bold;
transition: fill 0.3s;
}
.hud-title {
font-size: 24px;
font-weight: 800;
fill: var(--text-main);
letter-spacing: 2px;
}
.hud-subtitle {
font-size: 12px;
fill: var(--accent-cyan);
letter-spacing: 4px;
}
.triz-panel {
fill: rgba(15, 23, 42, 0.8);
stroke: var(--accent-cyan);
stroke-width: 1;
stroke-dasharray: 4 2;
}
/* Animations */
@keyframes windBlow {
0% { stroke-dashoffset: 100; opacity: 0; }
20% { opacity: 0.6; }
80% { opacity: 0.6; }
100% { stroke-dashoffset: -100; opacity: 0; }
}
.wind-line {
stroke: var(--text-dim);
stroke-width: 2;
stroke-dasharray: 20 80;
animation: windBlow 3s linear infinite;
}
@keyframes pulseRing {
0% { r: 20; opacity: 1; stroke-width: 10; }
100% { r: 150; opacity: 0; stroke-width: 1; }
}
.pulse-effect {
fill: none;
stroke: var(--accent-cyan);
opacity: 0;
}
.pulse-active {
animation: pulseRing 0.5s ease-out;
}
@keyframes magFlow {
0% { stroke-dashoffset: 40; }
100% { stroke-dashoffset: 0; }
}
.mag-line {
fill: none;
stroke: var(--accent-green);
stroke-width: 2;
stroke-dasharray: 5 5;
opacity: 0;
transition: opacity 0.3s;
}
.mag-line.active {
opacity: 0.8;
animation: magFlow 1s linear infinite;
}
/* SVG Element Transitions */
#hook-group {
transition: transform 1.5s cubic-bezier(0.4, 0, 0.2, 1);
}
#cargo-group {
transition: transform 1.5s cubic-bezier(0.4, 0, 0.2, 1);
}
.smooth-slide {
transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) !important;
}
.epm-core {
fill: var(--metal-dark);
transition: fill 0.1s, filter 0.1s;
}
.epm-core.magnetized {
fill: var(--accent-green);
filter: drop-shadow(0 0 15px rgba(16, 185, 129, 0.8));
}
.force-arrow {
opacity: 0;
transition: opacity 0.3s;
}
.force-arrow.active {
opacity: 1;
}
@keyframes flashText {
0%, 100% { fill: var(--text-main); }
50% { fill: var(--accent-red); }
}
.text-flash {
animation: flashText 0.2s 3;
}
</style>
</head>
<body>
<div id="animation-container">
<svg viewBox="0 0 1600 900" preserveAspectRatio="xMidYMid meet">
<defs>
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="5" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
<linearGradient id="metal-grad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#475569" />
<stop offset="50%" stop-color="#94a3b8" />
<stop offset="100%" stop-color="#475569" />
</linearGradient>
<linearGradient id="cargo-grad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#1e293b" />
<stop offset="100%" stop-color="#0f172a" />
</linearGradient>
<!-- Arrow Head -->
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="var(--warning)" />
</marker>
</defs>
<!-- Background Decor -->
<g opacity="0.1">
<circle cx="800" cy="450" r="300" fill="none" stroke="var(--accent-cyan)" stroke-width="1" stroke-dasharray="10 20"/>
<circle cx="800" cy="450" r="400" fill="none" stroke="var(--accent-cyan)" stroke-width="1" />
<line x1="800" y1="0" x2="800" y2="900" stroke="var(--accent-cyan)" stroke-width="1" />
<line x1="0" y1="450" x2="1600" y2="450" stroke="var(--accent-cyan)" stroke-width="1" />
</g>
<!-- TRIZ & IFR Panel (Left) -->
<g transform="translate(50, 50)">
<rect width="380" height="260" rx="8" class="triz-panel" />
<text x="20" y="40" class="hud-title" fill="var(--accent-cyan)">设计原理分析</text>
<text x="20" y="60" class="hud-subtitle">TRIZ: IDEAL FINAL RESULT (IFR)</text>
<line x1="20" y1="80" x2="360" y2="80" stroke="var(--grid-color)" stroke-width="2"/>
<text x="20" y="110" class="hud-value" fill="#f8fafc">创新点 1: 被动形态对中</text>
<text x="20" y="135" class="hud-text">利用喇叭形导向罩与圆台法兰的物理</text>
<text x="20" y="155" class="hud-text">几何约束,通过重力下滑产生被动位移。</text>
<text x="20" y="175" class="hud-text" fill="var(--warning)">→ 消除矛盾: 去除高精度对位驱动件</text>
<text x="20" y="215" class="hud-value" fill="#f8fafc">创新点 2: 零功耗磁保持</text>
<text x="20" y="240" class="hud-text">50ms脉冲电流切换电永磁(EPM)极性。</text>
<text x="20" y="260" class="hud-text" fill="var(--accent-green)">→ 消除矛盾: 解决强磁吸力与持续耗电</text>
</g>
<!-- Telemetry Panel (Right) -->
<g transform="translate(1170, 50)">
<rect width="380" height="420" rx="8" class="triz-panel" />
<text x="20" y="40" class="hud-title">遥测系统 (TELEMETRY)</text>
<text x="20" y="60" class="hud-subtitle">实时传感器数据与状态监控</text>
<line x1="20" y1="80" x2="360" y2="80" stroke="var(--grid-color)" stroke-width="2"/>
<!-- Status Items -->
<g transform="translate(20, 110)">
<text x="0" y="0" class="hud-text">当前作业阶段:</text>
<text x="140" y="0" class="hud-value" id="ui-stage" fill="var(--accent-cyan)">系统待机</text>
<text x="0" y="40" class="hud-text">风扰动 (X轴):</text>
<text x="140" y="40" class="hud-value" id="ui-wind" fill="var(--accent-red)">3级 侧风</text>
<text x="0" y="80" class="hud-text">X轴 偏移误差:</text>
<text x="140" y="80" class="hud-value" id="ui-offset" fill="var(--warning)">+80.0 mm</text>
<text x="0" y="120" class="hud-text">导向接触开关:</text>
<text x="140" y="120" class="hud-value" id="ui-contact">未触发</text>
<text x="0" y="160" class="hud-text">线圈控制电流:</text>
<text x="140" y="160" class="hud-value" id="ui-current">0.0 A</text>
<text x="0" y="200" class="hud-text">电磁极性状态:</text>
<text x="140" y="200" class="hud-value" id="ui-polarity">退磁 (释放)</text>
<text x="0" y="240" class="hud-text">当前保持吸力:</text>
<text x="140" y="240" class="hud-value" id="ui-suction">0 N</text>
<text x="0" y="280" class="hud-text">吸力安全冗余:</text>
<text x="140" y="280" class="hud-value" id="ui-redundancy">N/A</text>
</g>
<!-- Oscilloscope for Pulse -->
<g transform="translate(20, 420)">
<text x="0" y="0" class="hud-text">控制脉冲示波器 (50ms)</text>
<rect x="0" y="10" width="340" height="60" fill="#0f172a" stroke="var(--grid-color)"/>
<path id="pulse-graph" d="M 0 60 L 150 60 L 150 60 L 170 60 L 170 60 L 340 60" fill="none" stroke="var(--accent-cyan)" stroke-width="2"/>
<text x="145" y="85" class="hud-subtitle" id="pulse-label" opacity="0">50ms 充磁脉冲</text>
</g>
</g>
<!-- Wind Animation Elements -->
<g id="wind-group" opacity="1">
<path class="wind-line" d="M 300 300 L 700 300" />
<path class="wind-line" d="M 250 400 L 650 400" style="animation-delay: 1s;" />
<path class="wind-line" d="M 350 500 L 750 500" style="animation-delay: 0.5s;" />
<path class="wind-line" d="M 400 600 L 800 600" style="animation-delay: 1.5s;" />
</g>
<!-- Main Animation Scene -->
<!-- Cargo Base -->
<g id="cargo-group" transform="translate(880, 650)">
<!-- Cargo Box -->
<rect x="-100" y="0" width="200" height="150" rx="5" fill="url(#cargo-grad)" stroke="var(--metal-dark)" stroke-width="3"/>
<text x="0" y="80" text-anchor="middle" class="hud-title" fill="var(--text-dim)">PAYLOAD</text>
<text x="0" y="105" text-anchor="middle" class="hud-text">10.0 KG</text>
<!-- Standard Ferromagnetic Flange (Truncated Cone) -->
<!-- Base width 100, Top width 40, Height 60 -->
<path d="M -50 0 L 50 0 L 20 -60 L -20 -60 Z" fill="var(--metal-light)" stroke="#fff" stroke-width="1"/>
<rect x="-20" y="-60" width="40" height="5" fill="var(--accent-cyan)" opacity="0.3"/> <!-- Interface -->
<!-- Center Line -->
<line x1="0" y1="-80" x2="0" y2="150" stroke="var(--text-dim)" stroke-dasharray="4 4" opacity="0.5"/>
<text x="0" y="170" text-anchor="middle" class="hud-subtitle">货物几何中心</text>
</g>
<!-- Drone Hook Assembly -->
<g id="hook-group" transform="translate(800, 100)">
<!-- Drone Tether (Cable) -->
<line x1="0" y1="-400" x2="0" y2="0" stroke="var(--metal-dark)" stroke-width="6" />
<line x1="0" y1="-400" x2="0" y2="0" stroke="#fff" stroke-width="2" stroke-dasharray="10 10"/>
<!-- Center Line (Hook) -->
<line x1="0" y1="-50" x2="0" y2="150" stroke="var(--warning)" stroke-dasharray="4 4" opacity="0.8"/>
<text x="0" y="-60" text-anchor="middle" class="hud-subtitle" fill="var(--warning)">吊索垂直轴</text>
<!-- Force Vectors (Passive Centering) -->
<g id="force-vectors" class="force-arrow">
<path d="M 60 70 L 20 70" stroke="var(--warning)" stroke-width="4" marker-end="url(#arrow)"/>
<text x="80" y="75" class="hud-value" fill="var(--warning)">滑移分力</text>
<!-- Highlight collision area -->
<circle cx="20" cy="50" r="15" fill="var(--warning)" opacity="0.4" filter="url(#glow)"/>
</g>
<!-- Magnetic Field Lines (Left & Right) -->
<g id="magnetic-field">
<!-- Left -->
<path class="mag-line" d="M -15 30 C -80 30, -80 90, -15 90" />
<path class="mag-line" d="M -10 20 C -120 20, -120 100, -10 100" />
<!-- Right -->
<path class="mag-line" d="M 15 30 C 80 30, 80 90, 15 90" />
<path class="mag-line" d="M 10 20 C 120 20, 120 100, 10 100" />
</g>
<!-- Horn-shaped Guide Cover (Inverted shape, hollow inside) -->
<!-- Top width 40, Bottom opening 140, Height 80 -->
<path d="M -20 0 L 20 0 L 70 80 L 40 80 L 15 30 L -15 30 L -40 80 L -70 80 Z" fill="url(#metal-grad)" stroke="#fff" stroke-width="1.5"/>
<!-- EPM Module (Center Cylinder) -->
<rect x="-15" y="0" width="30" height="40" class="epm-core" id="epm-core" stroke="#fff" stroke-width="1"/>
<!-- Coils representation -->
<line x1="-15" y1="10" x2="15" y2="10" stroke="#f59e0b" stroke-width="2"/>
<line x1="-15" y1="20" x2="15" y2="20" stroke="#f59e0b" stroke-width="2"/>
<line x1="-15" y1="30" x2="15" y2="30" stroke="#f59e0b" stroke-width="2"/>
<!-- Pulse Visual Effect -->
<circle cx="0" cy="40" r="0" class="pulse-effect" id="pulse-ring"/>
</g>
<!-- Distance/Offset Dimension Line -->
<g id="dimension-group" opacity="1">
<line id="dim-line" x1="800" y1="200" x2="880" y2="200" stroke="var(--warning)" stroke-width="2"/>
<line id="dim-left" x1="800" y1="190" x2="800" y2="210" stroke="var(--warning)" stroke-width="2"/>
<line id="dim-right" x1="880" y1="190" x2="880" y2="210" stroke="var(--warning)" stroke-width="2"/>
<text id="dim-text" x="840" y="185" text-anchor="middle" class="hud-value" fill="var(--warning)">ΔX: 80mm</text>
</g>
</svg>
</div>
<script>
document.addEventListener("DOMContentLoaded", () => {
// DOM Elements
const hook = document.getElementById('hook-group');
const cargo = document.getElementById('cargo-group');
const epmCore = document.getElementById('epm-core');
const pulseRing = document.getElementById('pulse-ring');
const magLines = document.querySelectorAll('.mag-line');
const forceVectors = document.getElementById('force-vectors');
const windGroup = document.getElementById('wind-group');
const pulseGraph = document.getElementById('pulse-graph');
const pulseLabel = document.getElementById('pulse-label');
// Dimension Elements
const dimGroup = document.getElementById('dimension-group');
const dimLine = document.getElementById('dim-line');
const dimRight = document.getElementById('dim-right');
const dimText = document.getElementById('dim-text');
// UI Elements
const uiStage = document.getElementById('ui-stage');
const uiOffset = document.getElementById('ui-offset');
const uiContact = document.getElementById('ui-contact');
const uiCurrent = document.getElementById('ui-current');
const uiPolarity = document.getElementById('ui-polarity');
const uiSuction = document.getElementById('ui-suction');
const uiRedundancy = document.getElementById('ui-redundancy');
const uiWind = document.getElementById('ui-wind');
// Initial Layout Coordinates
const hookStartY = 150;
const cargoStartY = 650;
const hookDescendY = 560; // Y when touching flange
const cargoLiftY = 350;
const hookLiftY = cargoLiftY - 90; // Hook relative offset to cargo
const hookStartX = 800; // Center of drone
const cargoStartX = 880; // Misaligned by wind (+80)
// Utility: Sleep
const sleep = ms => new Promise(r => setTimeout(r, ms));
// Utility: Set Transform
const setTransform = (el, x, y, addClass = '') => {
if (addClass) {
el.classList.add(addClass);
} else {
el.classList.remove('smooth-slide');
}
el.style.transform = `translate(${x}px, ${y}px)`;
};
// Utility: Update Dimension Tracker visually
const updateDimension = (hookX) => {
const diff = cargoStartX - hookX;
if (diff > 0) {
dimGroup.style.opacity = 1;
dimLine.setAttribute('x1', hookX);
dimLine.setAttribute('x2', cargoStartX);
const dimLeft = document.getElementById('dim-left');
dimLeft.setAttribute('x1', hookX);
dimLeft.setAttribute('x2', hookX);
dimText.setAttribute('x', hookX + diff / 2);
dimText.textContent = `ΔX: ${diff}mm`;
uiOffset.textContent = `+${diff}.0 mm`;
if(diff === 0) uiOffset.style.fill = "var(--accent-green)";
else uiOffset.style.fill = "var(--warning)";
} else {
dimGroup.style.opacity = 0;
uiOffset.textContent = `0.0 mm`;
uiOffset.style.fill = "var(--accent-green)";
}
};
// UI Update Function
const updateUI = (el, text, color = null, flash = false) => {
el.textContent = text;
if (color) el.style.fill = color;
if (flash) {
el.classList.remove('text-flash');
void el.offsetWidth; // trigger reflow
el.classList.add('text-flash');
}
};
// Action: 50ms Pulse Visualizer
const triggerPulse = async (isMagnetizing) => {
// Screen flash
pulseRing.classList.remove('pulse-active');
void pulseRing.offsetWidth;
pulseRing.classList.add('pulse-active');
// Oscilloscope animation
pulseGraph.setAttribute('d', `M 0 60 L 150 60 L 150 10 L 170 10 L 170 60 L 340 60`);
pulseLabel.style.opacity = 1;
pulseLabel.textContent = isMagnetizing ? "50ms 充磁脉冲" : "50ms 退磁脉冲";
pulseLabel.style.fill = isMagnetizing ? "var(--accent-green)" : "var(--accent-red)";
updateUI(uiCurrent, "50.0 A (脉冲)", "var(--accent-cyan)", true);
await sleep(50); // The 50ms literal wait
pulseGraph.setAttribute('d', `M 0 60 L 340 60`);
pulseLabel.style.opacity = 0;
updateUI(uiCurrent, "0.0 A (零功耗)", "var(--accent-green)");
};
// Main Animation Loop
async function runSequence() {
while (true) {
// --- STATE 0: RESET ---
setTransform(hook, hookStartX, hookStartY);
setTransform(cargo, cargoStartX, cargoStartY);
epmCore.classList.remove('magnetized');
magLines.forEach(l => l.classList.remove('active'));
forceVectors.classList.remove('active');
windGroup.style.opacity = 1;
updateUI(uiStage, "系统待机 / 目标定位", "var(--accent-cyan)");
updateUI(uiWind, "3级 侧风", "var(--accent-red)");
updateUI(uiContact, "未接触", "var(--text-main)");
updateUI(uiPolarity, "退磁 (释放)", "var(--text-dim)");
updateUI(uiSuction, "0 N", "var(--text-dim)");
updateUI(uiRedundancy, "N/A", "var(--text-dim)");
// Track dimension manually since CSS transition handles the X later
let currentHookX = hookStartX;
updateDimension(currentHookX);
await sleep(2000);
// --- STATE 1: DESCEND ---
updateUI(uiStage, "视觉下放吊索", "var(--warning)");
setTransform(hook, hookStartX, hookDescendY - 60); // Lowering but not touching yet
await sleep(1500);
// --- STATE 2: PASSIVE CENTERING (IFR CORE) ---
updateUI(uiStage, "物理被动滑移对中", "var(--accent-green)");
updateUI(uiContact, "接触边缘", "var(--warning)");
// Show force vectors to explain the TRIZ principle
forceVectors.classList.add('active');
// Hook slides to cargo center due to gravity/geometry
setTransform(hook, cargoStartX, hookDescendY, 'smooth-slide');
// Simulate dimensional update during transition
let slideInterval = setInterval(() => {
currentHookX += (cargoStartX - currentHookX) * 0.1;
updateDimension(currentHookX);
}, 30);
await sleep(600);
clearInterval(slideInterval);
updateDimension(cargoStartX); // Lock to 0 offset
forceVectors.classList.remove('active');
updateUI(uiContact, "完美贴合", "var(--accent-green)");
await sleep(500);
// --- STATE 3: MAGNETIZATION (IFR CORE) ---
updateUI(uiStage, "接触触发 - 充磁", "var(--accent-cyan)");
await triggerPulse(true);
// Apply magnetic state
epmCore.classList.add('magnetized');
magLines.forEach(l => l.classList.add('active'));
updateUI(uiPolarity, "充磁 (保持中)", "var(--accent-green)");
updateUI(uiSuction, "300 N", "var(--accent-green)", true);
updateUI(uiRedundancy, "3.0 倍", "var(--accent-green)");
await sleep(1500);
// --- STATE 4: LIFTING ---
updateUI(uiStage, "起吊飞行 (强磁保持)", "var(--accent-cyan)");
windGroup.style.opacity = 0; // Less wind effect when flying high
updateUI(uiWind, "1级 微风", "var(--accent-green)");
// Lift both Hook and Cargo together
setTransform(hook, cargoStartX, hookLiftY);
setTransform(cargo, cargoStartX, cargoLiftY);
await sleep(2500);
// --- STATE 5: DROPPING (AT DESTINATION) ---
updateUI(uiStage, "抵达目标地 - 放下", "var(--warning)");
setTransform(hook, cargoStartX, hookDescendY);
setTransform(cargo, cargoStartX, cargoStartY);
await sleep(1500);
// --- STATE 6: DEMAGNETIZATION ---
updateUI(uiStage, "承重卸载 - 退磁", "var(--accent-red)");
await triggerPulse(false);
// Remove magnetic state
epmCore.classList.remove('magnetized');
magLines.forEach(l => l.classList.remove('active'));
updateUI(uiPolarity, "退磁 (已释放)", "var(--text-dim)");
updateUI(uiSuction, "0 N", "var(--text-dim)");
updateUI(uiRedundancy, "N/A", "var(--text-dim)");
await sleep(1000);
// --- STATE 7: RETRACT ---
updateUI(uiStage, "绞盘收起吊索", "var(--accent-cyan)");
setTransform(hook, cargoStartX, hookStartY);
await sleep(2000);
}
}
// Start animation loop immediately
runSequence();
});
</script>
</body>
</html>
积分规则:第一轮对话扣减8分,后续每轮扣6分
等待动画代码生成...
