独立渲染引擎就绪引擎就绪
这里是为您设计的“国标直流快充 PCM 相变热管理系统”原理动画。
为了打破常规的技术演示风格,我采用了**“深空科技诊断界面 (Sci-Fi Diagnostics Panel)”**的美学方向。这种风格通过硬核的等宽字体、深邃的炭黑背景、发光的能量流迹以及高对比度的热成像色彩映射,生动地呈现了 IFR(最终理想解)—— 即系统巧妙利用 PCM 潜热“吞噬”快充热量的核心物理过程。
请将以下代码保存为 .html 文件并在现代浏览器中全屏打开,动画将在加载完毕后自动循环播放。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CTP相变热管理系统原理</title>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Share+Tech+Mono&display=swap" rel="stylesheet">
<style>
:root {
/* 主题调色板 */
--bg-color: #07090e;
--grid-color: rgba(0, 255, 255, 0.04);
--panel-bg: rgba(9, 14, 23, 0.7);
--panel-border: #1a2a40;
--text-main: #e2e8f0;
--text-accent: #00f0ff;
--text-warn: #ff3c00;
/* 动态变量 (由JS控制) */
--cell-color: #1e293b;
--cell-glow: rgba(30, 41, 59, 0);
--pcm-color: #0f3a40;
--pcm-glow: rgba(0, 255, 255, 0);
--current-dash-speed: 0s;
--current-opacity: 0;
--data-blur: 8px;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-color);
background-image:
linear-gradient(var(--grid-color) 1px, transparent 1px),
linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
background-size: 30px 30px;
color: var(--text-main);
font-family: 'Share Tech Mono', monospace;
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
position: relative;
}
/* 顶部标题栏 */
.header {
position: absolute;
top: 20px;
left: 30px;
right: 30px;
display: flex;
justify-content: space-between;
align-items: flex-end;
border-bottom: 1px solid var(--panel-border);
padding-bottom: 10px;
z-index: 10;
}
.title-box h1 {
font-family: 'Orbitron', sans-serif;
font-size: 24px;
font-weight: 700;
letter-spacing: 2px;
color: var(--text-accent);
text-transform: uppercase;
}
.title-box p {
font-size: 12px;
color: #64748b;
margin-top: 4px;
}
/* 数据诊断面板 */
.hud-panel {
position: absolute;
bottom: 30px;
right: 30px;
background: var(--panel-bg);
backdrop-filter: blur(var(--data-blur));
border: 1px solid var(--panel-border);
padding: 20px;
border-radius: 4px;
width: 320px;
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
z-index: 10;
}
.data-row {
display: flex;
justify-content: space-between;
margin-bottom: 12px;
border-bottom: 1px dashed rgba(255,255,255,0.1);
padding-bottom: 4px;
}
.data-label {
color: #94a3b8;
font-size: 14px;
}
.data-value {
font-size: 18px;
font-weight: bold;
color: var(--text-accent);
transition: color 0.3s;
font-family: 'Orbitron', sans-serif;
}
.value-warn { color: var(--text-warn); }
.value-safe { color: #39ff14; }
/* 状态指示器 */
.status-box {
margin-top: 20px;
padding: 10px;
background: rgba(0, 0, 0, 0.4);
border-left: 3px solid var(--text-accent);
font-size: 13px;
line-height: 1.5;
}
.status-type { color: var(--text-accent); font-weight: bold; }
/* 动画主容器 */
.anim-container {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
padding: 80px 40px;
}
svg {
width: 100%;
height: 100%;
max-width: 1200px;
max-height: 700px;
filter: drop-shadow(0 0 20px rgba(0,0,0,0.5));
}
/* SVG 内元素动效 */
.cell-body {
fill: var(--cell-color);
transition: fill 0.3s ease;
stroke: #334155;
stroke-width: 2;
}
.pcm-material {
fill: var(--pcm-color);
transition: fill 0.5s ease;
stroke: #0d9488;
stroke-width: 1;
}
/* 流动的高压电流 */
.power-line {
fill: none;
stroke: var(--text-accent);
stroke-width: 4;
stroke-dasharray: 10 20;
opacity: var(--current-opacity);
animation: flow var(--current-dash-speed) linear infinite;
}
@keyframes flow {
to { stroke-dashoffset: -30; }
}
/* 扫描线效果 */
.scanline {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 10px;
background: linear-gradient(to bottom, transparent, rgba(0, 240, 255, 0.1), transparent);
opacity: 0.5;
animation: scan 8s linear infinite;
pointer-events: none;
z-index: 99;
}
@keyframes scan {
0% { top: -10%; }
100% { top: 110%; }
}
/* 十字准星装饰 */
.crosshair {
position: absolute;
width: 20px;
height: 20px;
border-color: rgba(0, 240, 255, 0.3);
border-style: solid;
z-index: 1;
}
.ch-tl { top: 20%; left: 10%; border-width: 2px 0 0 2px; }
.ch-tr { top: 20%; right: 10%; border-width: 2px 2px 0 0; }
.ch-bl { bottom: 20%; left: 10%; border-width: 0 0 2px 2px; }
.ch-br { bottom: 20%; right: 10%; border-width: 0 2px 2px 0; }
</style>
</head>
<body>
<div class="scanline"></div>
<div class="crosshair ch-tl"></div>
<div class="crosshair ch-tr"></div>
<div class="crosshair ch-bl"></div>
<div class="crosshair ch-br"></div>
<header class="header">
<div class="title-box">
<h1>CTP Thermal Management IFR</h1>
<p>PHASE-CHANGE MATERIAL HEAT ABSORPTION OVERRIDE (24S1P LFP)</p>
</div>
<div class="title-box" style="text-align: right;">
<p style="color: var(--text-accent);">SYS_ACTIVE // AUTOLOOP_ENGAGED</p>
</div>
</header>
<div class="anim-container">
<!-- SVG 渲染核心模块 -->
<svg viewBox="0 0 1000 500" preserveAspectRatio="xMidYMid meet">
<defs>
<!-- 发光滤镜 -->
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="8" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
<!-- PCM 液化噪点纹理 -->
<pattern id="pcm-pattern" width="20" height="20" patternUnits="userSpaceOnUse">
<rect width="20" height="20" fill="var(--pcm-color)" />
<circle cx="10" cy="10" r="1.5" fill="rgba(255,255,255,0.15)" />
<path d="M0,10 Q5,5 10,10 T20,10" fill="none" stroke="rgba(0,255,255,0.1)" stroke-width="1"/>
</pattern>
<!-- 发热粒子扩散效果(预留给相变吸热) -->
<filter id="thermal-blur">
<feGaussianBlur stdDeviation="4" />
</filter>
</defs>
<!-- 外层壳体 -->
<rect x="50" y="50" width="900" height="400" rx="10" fill="none" stroke="#1e293b" stroke-width="4" />
<text x="60" y="80" fill="#475569" font-size="14">BATTERY ENCLOSURE (CTP)</text>
<path d="M 50 100 L 950 100" stroke="#1e293b" stroke-width="2" stroke-dasharray="5 5" />
<!-- 生成电芯组和PCM材料 (局部展示 6块电芯 代表 24S1P) -->
<!-- 整体组居中 -->
<g transform="translate(100, 150)">
<!-- 底部导电排连接线 -->
<path class="power-line" d="M -50 200 L 800 200" />
<path class="power-line" d="M -50 0 L 800 0" />
<!-- 循环构建 6 个 Cell 和中间的 PCM -->
<!-- Cell 1 -->
<rect class="cell-body" x="0" y="20" width="100" height="160" rx="4" filter="drop-shadow(0 0 15px var(--cell-glow))"/>
<text x="50" y="105" fill="#94a3b8" font-size="16" text-anchor="middle" font-family="Orbitron">CELL</text>
<!-- PCM 1 -->
<rect class="pcm-material" x="105" y="30" width="25" height="140" fill="url(#pcm-pattern)" filter="drop-shadow(0 0 20px var(--pcm-glow))" />
<!-- Cell 2 -->
<rect class="cell-body" x="135" y="20" width="100" height="160" rx="4" filter="drop-shadow(0 0 15px var(--cell-glow))"/>
<text x="185" y="105" fill="#94a3b8" font-size="16" text-anchor="middle" font-family="Orbitron">CELL</text>
<!-- PCM 2 -->
<rect class="pcm-material" x="240" y="30" width="25" height="140" fill="url(#pcm-pattern)" filter="drop-shadow(0 0 20px var(--pcm-glow))" />
<!-- Cell 3 -->
<rect class="cell-body" x="270" y="20" width="100" height="160" rx="4" filter="drop-shadow(0 0 15px var(--cell-glow))"/>
<text x="320" y="105" fill="#94a3b8" font-size="16" text-anchor="middle" font-family="Orbitron">CELL</text>
<!-- PCM 3 -->
<rect class="pcm-material" x="375" y="30" width="25" height="140" fill="url(#pcm-pattern)" filter="drop-shadow(0 0 20px var(--pcm-glow))" />
<!-- Cell 4 -->
<rect class="cell-body" x="405" y="20" width="100" height="160" rx="4" filter="drop-shadow(0 0 15px var(--cell-glow))"/>
<text x="455" y="105" fill="#94a3b8" font-size="16" text-anchor="middle" font-family="Orbitron">CELL</text>
<!-- PCM 4 -->
<rect class="pcm-material" x="510" y="30" width="25" height="140" fill="url(#pcm-pattern)" filter="drop-shadow(0 0 20px var(--pcm-glow))" />
<!-- Cell 5 -->
<rect class="cell-body" x="540" y="20" width="100" height="160" rx="4" filter="drop-shadow(0 0 15px var(--cell-glow))"/>
<text x="590" y="105" fill="#94a3b8" font-size="16" text-anchor="middle" font-family="Orbitron">CELL</text>
<!-- PCM 5 -->
<rect class="pcm-material" x="645" y="30" width="25" height="140" fill="url(#pcm-pattern)" filter="drop-shadow(0 0 20px var(--pcm-glow))" />
<!-- Cell 6 -->
<rect class="cell-body" x="675" y="20" width="100" height="160" rx="4" filter="drop-shadow(0 0 15px var(--cell-glow))"/>
<text x="725" y="105" fill="#94a3b8" font-size="16" text-anchor="middle" font-family="Orbitron">CELL</text>
<!-- 注释线条 -->
<path d="M 117 10 L 117 -30 L 250 -30" stroke="#00f0ff" stroke-width="1" fill="none" opacity="0.6"/>
<circle cx="117" cy="10" r="3" fill="#00f0ff" />
<text x="260" y="-25" fill="#00f0ff" font-size="14" font-family="Share Tech Mono">GRAPHENE COMPOSITE PCM</text>
<text x="260" y="-10" fill="#64748b" font-size="12">LATENT HEAT CAPACITY > 220 kJ/kg</text>
</g>
</svg>
</div>
<!-- 数据浮层 -->
<div class="hud-panel">
<div class="data-row">
<span class="data-label">MODE</span>
<span class="data-value" id="ui-mode">IDLE</span>
</div>
<div class="data-row">
<span class="data-label">INPUT CURRENT</span>
<span class="data-value" id="ui-current">0.0 A</span>
</div>
<div class="data-row">
<span class="data-label">CELL TEMPERATURE</span>
<span class="data-value" id="ui-temp">25.0 °C</span>
</div>
<div class="data-row">
<span class="data-label">PCM STATE</span>
<span class="data-value" id="ui-pcm">SOLID</span>
</div>
<div class="status-box">
<div id="ui-desc" class="status-type">SYSTEM ONLINE</div>
<div id="ui-detail" style="color: #64748b; font-size: 11px; margin-top: 5px;">Waiting for charge cycle...</div>
</div>
</div>
<script>
/**
* 状态机与动画核心引擎
* 完全实现前端隔离与自治的自动循环动画
*/
document.addEventListener('DOMContentLoaded', () => {
const root = document.documentElement;
// UI 元素绑定
const uiMode = document.getElementById('ui-mode');
const uiCurrent = document.getElementById('ui-current');
const uiTemp = document.getElementById('ui-temp');
const uiPcm = document.getElementById('ui-pcm');
const uiDesc = document.getElementById('ui-desc');
const uiDetail = document.getElementById('ui-detail');
// 物理常量模拟
let currentTemp = 25.0;
let currentAmp = 0.0;
// 颜色插值函数 (Lerp color)
function interpolateColor(color1, color2, factor) {
const hex2rgb = hex => [
parseInt(hex.slice(1, 3), 16),
parseInt(hex.slice(3, 5), 16),
parseInt(hex.slice(5, 7), 16)
];
const c1 = hex2rgb(color1);
const c2 = hex2rgb(color2);
const r = Math.round(c1[0] + factor * (c2[0] - c1[0]));
const g = Math.round(c1[1] + factor * (c2[1] - c1[1]));
const b = Math.round(c1[2] + factor * (c2[2] - c1[2]));
return `rgb(${r}, ${g}, ${b})`;
}
// 更新 UI 和 CSS 变量
function updateVisuals(temp, amp, stateStr, pcmStateStr, descStr, detailStr, pcmColorHex, pcmGlowColor) {
// 更新数值文本
uiTemp.textContent = temp.toFixed(1) + ' °C';
uiCurrent.textContent = amp.toFixed(1) + ' A';
uiMode.textContent = stateStr;
uiPcm.textContent = pcmStateStr;
uiDesc.textContent = descStr;
uiDetail.textContent = detailStr;
// 颜色和特效计算
// 温度 25 到 45,冷色(#1e293b) 到 警告色(#ff3c00)
let tempFactor = Math.max(0, Math.min(1, (temp - 25) / 20));
let cellColor = interpolateColor('#1e293b', '#6b1000', tempFactor);
let cellGlow = `rgba(255, 60, 0, ${tempFactor * 0.8})`;
root.style.setProperty('--cell-color', cellColor);
root.style.setProperty('--cell-glow', cellGlow);
// PCM状态更新
root.style.setProperty('--pcm-color', pcmColorHex);
root.style.setProperty('--pcm-glow', pcmGlowColor);
// 电流特效更新
if (amp > 10) {
root.style.setProperty('--current-opacity', '1');
root.style.setProperty('--current-dash-speed', '0.5s'); // 极速流动
} else {
root.style.setProperty('--current-opacity', '0.2');
root.style.setProperty('--current-dash-speed', '4s'); // 缓慢流动
}
// 阈值UI颜色警告
if (temp >= 44.5) {
uiTemp.classList.add('value-warn');
uiPcm.classList.add('value-safe'); // PCM 救场高亮
} else {
uiTemp.classList.remove('value-warn');
uiPcm.classList.remove('value-safe');
}
}
// 关键帧Timeline引擎
const timeline = [
{
time: 0,
duration: 2,
update: (t) => {
currentTemp = 25;
currentAmp = 0;
updateVisuals(currentTemp, currentAmp, "STANDBY", "SOLID", "NATURAL COOLING", "System idle. Normal heat dissipation.", "#0f3a40", "rgba(0,0,0,0)");
}
},
{
time: 2,
duration: 3,
update: (t) => {
// 接入快充,电流瞬间飙升,温度快速线性上升
currentAmp = 230;
currentTemp = 25 + (20 * t); // 25 -> 45
updateVisuals(currentTemp, currentAmp, "DC FAST CHARGE", "SOLID", "JOULE HEATING RAPID", "1C/230A injected. Cell temp surging.", "#0f3a40", "rgba(0,0,0,0)");
}
},
{
time: 5,
duration: 6,
update: (t) => {
// PCM 触发,吸收潜热。温度锁定在 45-45.5 微小波动
currentAmp = 230;
currentTemp = 45 + Math.sin(t * 10) * 0.3; // 波动效果
// PCM 从固态暗色变为高亮凝胶态,发荧光青色
let pcmGlowAlpha = 0.5 + Math.sin(t * 8) * 0.3; // 脉冲呼吸
updateVisuals(
currentTemp, currentAmp,
"THERMAL OVERRIDE", "MICRO-GEL (ABSORBING)",
"PCM PHASE CHANGE TRIGGERED",
"Absorbing latent heat (>220 kJ/kg). Temp locked at 45°C limit.",
"#00f0ff", `rgba(0, 240, 255, ${pcmGlowAlpha})`
);
}
},
{
time: 11,
duration: 4,
update: (t) => {
// 快充结束,缓慢散热,PCM凝固放热
currentAmp = 0;
currentTemp = 45 - (15 * t); // 45 -> 30
// PCM 回归暗色
let backFactor = 1 - t;
updateVisuals(
currentTemp, currentAmp,
"COOLDOWN", "SOLIDIFYING",
"HEAT DISSIPATION",
"Charge complete. PCM slowly releasing stored thermal energy.",
interpolateColor('#0f3a40', '#00f0ff', backFactor),
`rgba(0, 240, 255, ${backFactor * 0.5})`
);
}
}
];
const totalDuration = timeline.reduce((acc, curr) => acc + curr.duration, 0);
let startTime = null;
function animate(timestamp) {
if (!startTime) startTime = timestamp;
let elapsedSec = (timestamp - startTime) / 1000;
// 循环播放
if (elapsedSec > totalDuration) {
startTime = timestamp;
elapsedSec = 0;
}
// 找到当前执行的关键阶段
let accumulatedTime = 0;
for (let i = 0; i < timeline.length; i++) {
let stage = timeline[i];
if (elapsedSec >= accumulatedTime && elapsedSec <= accumulatedTime + stage.duration) {
// 计算当前阶段的归一化时间 t (0.0 -> 1.0)
let localTime = elapsedSec - accumulatedTime;
let t = localTime / stage.duration;
stage.update(t);
break;
}
accumulatedTime += stage.duration;
}
requestAnimationFrame(animate);
}
// 启动引擎
requestAnimationFrame(animate);
});
</script>
</body>
</html>
积分规则:第一轮对话扣减8分,后续每轮扣6分
等待动画代码生成...
