独立渲染引擎就绪引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>超临界 CO₂ 热射流无触点破岩原理演示</title>
<style>
:root {
--bg-color: #050811;
--panel-bg: rgba(10, 16, 30, 0.75);
--panel-border: rgba(0, 240, 255, 0.25);
--accent-cyan: #00f0ff;
--accent-orange: #ff5500;
--accent-yellow: #ffb800;
--accent-red: #ff2a4b;
--text-muted: #64748b;
--text-main: #e2e8f0;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
user-select: none;
}
body {
background-color: var(--bg-color);
color: var(--text-main);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
width: 100vw;
height: 100vh;
overflow: hidden;
display: flex;
flex-direction: column;
position: relative;
}
/* 顶部精简微标头 - 绝不侵占中央空间 */
.header-bar {
position: absolute;
top: 16px;
left: 20px;
z-index: 20;
display: flex;
align-items: center;
gap: 12px;
pointer-events: none;
}
.status-badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 3px 8px;
background: rgba(0, 240, 255, 0.1);
border: 1px solid var(--accent-cyan);
border-radius: 4px;
font-size: 11px;
font-weight: 600;
letter-spacing: 0.5px;
color: var(--accent-cyan);
}
.status-dot {
width: 6px;
height: 6px;
background: var(--accent-cyan);
border-radius: 50%;
box-shadow: 0 0 8px var(--accent-cyan);
animation: pulse-dot 1.5s infinite alternate;
}
.title-group h1 {
font-size: 14px;
font-weight: 600;
letter-spacing: 0.8px;
color: #ffffff;
}
.title-group p {
font-size: 11px;
color: var(--text-muted);
}
/* 中央超大核心动画主视口 */
.viewport-container {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
}
#stage-svg {
width: 100%;
height: 100%;
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
/* 粒子/特效独立 Canvas 覆盖层 */
#fx-canvas {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 2;
}
/* 右上角精简参数指示面板 (HUD) */
.hud-metrics {
position: absolute;
top: 16px;
right: 20px;
z-index: 20;
background: var(--panel-bg);
backdrop-filter: blur(8px);
border: 1px solid var(--panel-border);
border-radius: 6px;
padding: 10px 14px;
display: grid;
grid-template-columns: repeat(2, auto);
gap: 8px 16px;
font-size: 11px;
box-shadow: 0 8px 24px rgba(0,0,0,0.5);
}
.metric-item {
display: flex;
flex-direction: column;
}
.metric-label {
color: var(--text-muted);
font-size: 10px;
margin-bottom: 1px;
}
.metric-value {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-weight: 700;
font-size: 13px;
color: #fff;
}
.val-temp { color: #ff6e26; }
.val-press { color: #00f0ff; }
.val-speed { color: #ffca28; }
.val-stress { color: #ff2a4b; }
/* 底部极简悬浮控制器 */
.controls-dock {
position: absolute;
bottom: 16px;
left: 50%;
transform: translateX(-50%);
z-index: 20;
background: var(--panel-bg);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 30px;
padding: 6px 16px;
display: flex;
align-items: center;
gap: 16px;
box-shadow: 0 10px 30px rgba(0,0,0,0.6);
}
.ctrl-group {
display: flex;
align-items: center;
gap: 8px;
font-size: 11px;
color: var(--text-muted);
}
.ctrl-label {
font-size: 11px;
white-space: nowrap;
color: var(--text-main);
}
input[type="range"] {
-webkit-appearance: none;
width: 90px;
height: 4px;
background: rgba(255,255,255,0.2);
border-radius: 2px;
outline: none;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 12px;
height: 12px;
border-radius: 50%;
background: var(--accent-orange);
cursor: pointer;
box-shadow: 0 0 6px var(--accent-orange);
}
.btn-action {
background: rgba(0, 240, 255, 0.15);
border: 1px solid var(--accent-cyan);
color: #fff;
font-size: 11px;
padding: 4px 10px;
border-radius: 12px;
cursor: pointer;
transition: all 0.2s ease;
}
.btn-action:hover {
background: rgba(0, 240, 255, 0.35);
box-shadow: 0 0 8px rgba(0, 240, 255, 0.4);
}
/* 左下角紧凑微型图例 */
.legend-dock {
position: absolute;
bottom: 16px;
left: 20px;
z-index: 20;
background: var(--panel-bg);
backdrop-filter: blur(6px);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 6px;
padding: 6px 10px;
font-size: 10px;
display: flex;
flex-direction: column;
gap: 4px;
color: var(--text-muted);
pointer-events: none;
}
.legend-row {
display: flex;
align-items: center;
gap: 6px;
}
.legend-color {
width: 8px;
height: 8px;
border-radius: 2px;
}
@keyframes pulse-dot {
from { opacity: 0.4; transform: scale(0.9); }
to { opacity: 1; transform: scale(1.15); }
}
@keyframes heat-glow {
0% { opacity: 0.7; }
50% { opacity: 1; filter: drop-shadow(0 0 12px #ff4500); }
100% { opacity: 0.7; }
}
.glow-anim {
animation: heat-glow 2s infinite ease-in-out;
}
</style>
</head>
<body>
<!-- 顶部精简状态与标题 -->
<div class="header-bar">
<div class="status-badge">
<span class="status-dot"></span>
<span>超临界状态</span>
</div>
<div class="title-group">
<h1>高温超临界 CO₂ 热射流无触点破岩系统</h1>
<p>超临界循环 · 剧烈热应力 · 片状剥落</p>
</div>
</div>
<!-- 右上角精简参数仪表盘 -->
<div class="hud-metrics">
<div class="metric-item">
<span class="metric-label">射流出口温度</span>
<span class="metric-value val-temp" id="disp-temp">680 °C</span>
</div>
<div class="metric-item">
<span class="metric-label">射流喷出速度</span>
<span class="metric-value val-speed" id="disp-speed">265 m/s</span>
</div>
<div class="metric-item">
<span class="metric-label">井底环境压力</span>
<span class="metric-value val-press">48.5 MPa</span>
</div>
<div class="metric-item">
<span class="metric-label">表层热应力 / 临界</span>
<span class="metric-value val-stress" id="disp-stress">142 / 8.5 MPa</span>
</div>
</div>
<!-- 左下角微型图例 -->
<div class="legend-dock">
<div class="legend-row">
<span class="legend-color" style="background: linear-gradient(90deg, #ffeedd, #ff3700);"></span>
<span>650°C 超临界 CO₂ 高速射流</span>
</div>
<div class="legend-row">
<span class="legend-color" style="background: #00f0ff;"></span>
<span>井筒环空携屑上返流 (高密度)</span>
</div>
<div class="legend-row">
<span class="legend-color" style="background: #ff2a4b;"></span>
<span>热张应力集中裂纹扩展区</span>
</div>
</div>
<!-- 底部精简控制器 -->
<div class="controls-dock">
<div class="ctrl-group">
<span class="ctrl-label">射流功率</span>
<input type="range" id="power-slider" min="500" max="750" value="680" step="5">
<span id="power-val" style="font-size:10px; color:var(--accent-orange); font-family:monospace;">680°C</span>
</div>
<div style="width: 1px; height: 16px; background: rgba(255,255,255,0.15);"></div>
<button class="btn-action" id="btn-toggle-stress">热应力云图: 开</button>
<button class="btn-action" id="btn-burst">强化脉冲热冲击</button>
</div>
<!-- 视口与核心 SVG 结构 -->
<div class="viewport-container">
<svg id="stage-svg" viewBox="0 0 1600 900" preserveAspectRatio="xMidYMid meet">
<defs>
<!-- 渐变定义 -->
<linearGradient id="casingGrad" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#1e293b"/>
<stop offset="40%" stop-color="#475569"/>
<stop offset="70%" stop-color="#334155"/>
<stop offset="100%" stop-color="#0f172a"/>
</linearGradient>
<linearGradient id="insulationGrad" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#b45309"/>
<stop offset="50%" stop-color="#f59e0b"/>
<stop offset="100%" stop-color="#78350f"/>
</linearGradient>
<linearGradient id="innerPipeGrad" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#dc2626"/>
<stop offset="30%" stop-color="#ff7849"/>
<stop offset="70%" stop-color="#ffedd5"/>
<stop offset="100%" stop-color="#c2410c"/>
</linearGradient>
<radialGradient id="hotSpotGrad" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="#ffffff" stop-opacity="1"/>
<stop offset="25%" stop-color="#ffea79" stop-opacity="0.95"/>
<stop offset="55%" stop-color="#ff4800" stop-opacity="0.8"/>
<stop offset="85%" stop-color="#d90429" stop-opacity="0.4"/>
<stop offset="100%" stop-color="#1a0005" stop-opacity="0"/>
</radialGradient>
<radialGradient id="stressHalo" cx="50%" cy="30%" r="70%">
<stop offset="0%" stop-color="#ff0055" stop-opacity="0.7"/>
<stop offset="30%" stop-color="#ff5500" stop-opacity="0.4"/>
<stop offset="70%" stop-color="#00f0ff" stop-opacity="0.15"/>
<stop offset="100%" stop-color="#000000" stop-opacity="0"/>
</radialGradient>
<pattern id="rockTexture" width="60" height="60" patternUnits="userSpaceOnUse">
<rect width="60" height="60" fill="#121624"/>
<path d="M0 20 L20 0 M30 60 L60 30 M10 50 L50 10 M-5 35 L35 -5" stroke="#1c2338" stroke-width="1.5"/>
<circle cx="15" cy="15" r="1" fill="#2d3748"/>
<circle cx="45" cy="35" r="1.5" fill="#334155"/>
<circle cx="28" cy="52" r="1" fill="#1e293b"/>
</pattern>
<filter id="superGlow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="6" result="blur1" />
<feGaussianBlur stdDeviation="16" result="blur2" />
<feMerge>
<feMergeNode in="blur2" />
<feMergeNode in="blur1" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<!-- 喷嘴剪切路径 -->
<clipPath id="nozzleClip">
<path d="M 680 50 L 920 50 L 920 380 L 870 470 L 830 500 L 770 500 L 730 470 L 680 380 Z"/>
</clipPath>
</defs>
<!-- 1. 背景地层 (花岗岩超深层 300°C 环境) -->
<rect x="0" y="0" width="1600" height="900" fill="url(#rockTexture)"/>
<!-- 井眼外壁轮廓与环空边界 -->
<!-- 井筒左壁 -->
<path d="M 0 0 L 520 0 L 520 620 Q 520 740 640 760 L 640 900 L 0 900 Z" fill="#0b0e1a" stroke="#222f49" stroke-width="2"/>
<!-- 井筒右壁 -->
<path d="M 1600 0 L 1080 0 L 1080 620 Q 1080 740 960 760 L 960 900 L 1600 900 Z" fill="#0b0e1a" stroke="#222f49" stroke-width="2"/>
<!-- 井底岩面基底 (被热射流冲击剥落形成的凹坑) -->
<g id="rock-bed">
<!-- 基础岩石截面 -->
<path id="rock-bottom-path" d="M 520 620 Q 640 730 800 740 Q 960 730 1080 620 L 1080 900 L 520 900 Z" fill="#181d2f" stroke="#ff4500" stroke-width="1.5"/>
<!-- 热应力波穿透与温度梯度伪彩场 (FEM 风格应力云图) -->
<path id="stress-field" d="M 540 630 Q 640 730 800 740 Q 960 730 1060 630 L 1060 880 Q 800 910 540 880 Z" fill="url(#stressHalo)" opacity="0.85"/>
<!-- 陡峭热边界层(0.5mm微观急热层,白热化) -->
<path id="thermal-skin" d="M 680 690 Q 800 745 920 690 Q 800 735 680 690 Z" fill="url(#hotSpotGrad)" filter="url(#superGlow)"/>
<!-- 动态裂纹网络 (热应力张拉导致微裂纹脆性扩展) -->
<g id="crack-network" stroke="#ff1133" stroke-width="1.8" stroke-linecap="round" fill="none" opacity="0.9">
<!-- 裂纹1 -->
<path d="M 760 730 L 745 745 L 725 740 L 710 755" />
<path d="M 745 745 L 750 760" />
<!-- 裂纹2 (中央主剥落区) -->
<path d="M 790 738 L 795 758 L 780 770 L 765 775" />
<path d="M 795 758 L 815 765 L 830 780" />
<!-- 裂纹3 -->
<path d="M 835 732 L 850 746 L 875 742 L 890 758" />
<path d="M 850 746 L 855 768" />
<!-- 微小分叉 -->
<path d="M 815 765 L 810 785" stroke-dasharray="2 3"/>
<path d="M 725 740 L 720 758" stroke-dasharray="2 3"/>
</g>
</g>
<!-- 2. 井下无触点热射流喷嘴总成 (耐高温合金,无旋转密封与电子元器件) -->
<g id="nozzle-assembly">
<!-- 隔热连续油管 (真空绝热夹层结构) -->
<!-- 外层承压壁 -->
<rect x="680" y="-20" width="240" height="400" fill="url(#casingGrad)" stroke="#64748b" stroke-width="1.5"/>
<!-- 真空绝热层 -->
<rect x="710" y="-20" width="25" height="400" fill="url(#insulationGrad)"/>
<rect x="865" y="-20" width="25" height="400" fill="url(#insulationGrad)"/>
<line x1="722.5" y1="-20" x2="722.5" y2="380" stroke="#fef08a" stroke-width="1" stroke-dasharray="6 4" opacity="0.8"/>
<line x1="877.5" y1="-20" x2="877.5" y2="380" stroke="#fef08a" stroke-width="1" stroke-dasharray="6 4" opacity="0.8"/>
<!-- 内部高温通道 (650°C 超临界 CO₂ 注入管) -->
<rect x="735" y="-20" width="130" height="400" fill="url(#innerPipeGrad)" opacity="0.95"/>
<!-- 下部拉瓦尔/收缩型机械热喷嘴锥体 -->
<path d="M 680 380 L 920 380 L 860 480 L 835 495 L 765 495 L 740 480 Z" fill="url(#casingGrad)" stroke="#64748b" stroke-width="2"/>
<!-- 喷嘴内收缩流道 -->
<path d="M 735 380 L 865 380 L 825 480 L 818 495 L 782 495 L 775 480 Z" fill="url(#innerPipeGrad)"/>
<!-- 喷嘴合金耐磨耐冲刷唇口 -->
<ellipse cx="800" cy="495" rx="18" ry="5" fill="#ffffff" filter="url(#superGlow)"/>
<!-- 喷嘴结构注解精简小标牌 (SVG内部固定位置,不遮挡核心) -->
<g opacity="0.75" transform="translate(930, 240)">
<line x1="0" y1="0" x2="40" y2="0" stroke="#94a3b8" stroke-width="1"/>
<circle cx="0" cy="0" r="2.5" fill="#00f0ff"/>
<text x="48" y="4" fill="#cbd5e1" font-size="11" font-family="sans-serif">真空隔热连续油管 (外壁<150°C)</text>
</g>
<g opacity="0.75" transform="translate(900, 440)">
<line x1="0" y1="0" x2="70" y2="0" stroke="#94a3b8" stroke-width="1"/>
<circle cx="0" cy="0" r="2.5" fill="#ff5500"/>
<text x="78" y="4" fill="#cbd5e1" font-size="11" font-family="sans-serif">耐高温合金超音速喷嘴 (无转动件/无电子)</text>
</g>
</g>
<!-- 3. 超临界射流核心束 (高亮光柱与马赫环) -->
<g id="jet-stream">
<!-- 主发光能量射流 -->
<polygon points="782,495 818,495 890,720 710,720" fill="url(#innerPipeGrad)" opacity="0.85" filter="url(#superGlow)" class="glow-anim"/>
<!-- 射流中心极高温超音速核 -->
<polygon points="792,495 808,495 840,710 760,710" fill="#ffffff" opacity="0.95" filter="url(#superGlow)"/>
<!-- 驻点冲击波与马赫盘结构 (Shock Diamonds) -->
<g opacity="0.85" stroke="#ffffff" stroke-width="2" fill="none">
<ellipse cx="800" cy="540" rx="16" ry="4" stroke="#ffea79"/>
<ellipse cx="800" cy="590" rx="28" ry="6" stroke="#ffaa40"/>
<ellipse cx="800" cy="650" rx="46" ry="9" stroke="#ff7020"/>
<!-- 冲击底面翻卷激波 -->
<ellipse cx="800" cy="722" rx="90" ry="16" fill="url(#hotSpotGrad)"/>
</g>
</g>
<!-- 4. 环空携屑流动导引线 (动画虚线示意) -->
<g id="annulus-flow-lines" stroke="#00f0ff" stroke-width="1.5" stroke-dasharray="8 12" fill="none" opacity="0.45">
<!-- 左侧上返路径 -->
<path d="M 720 710 Q 560 690 560 550 L 560 0">
<animate attributeName="stroke-dashoffset" from="100" to="0" dur="1.2s" repeatCount="indefinite"/>
</path>
<path d="M 690 718 Q 600 690 600 550 L 600 0">
<animate attributeName="stroke-dashoffset" from="100" to="0" dur="1.5s" repeatCount="indefinite"/>
</path>
<!-- 右侧上返路径 -->
<path d="M 880 710 Q 1040 690 1040 550 L 1040 0">
<animate attributeName="stroke-dashoffset" from="100" to="0" dur="1.2s" repeatCount="indefinite"/>
</path>
<path d="M 910 718 Q 1000 690 1000 550 L 1000 0">
<animate attributeName="stroke-dashoffset" from="100" to="0" dur="1.5s" repeatCount="indefinite"/>
</path>
</g>
<!-- 5. 核心破岩热应力机理原理解析标示 (居中右侧,极简箭头,不挡主体) -->
<g transform="translate(1090, 680)" opacity="0.9">
<rect x="0" y="0" width="230" height="95" rx="6" fill="rgba(15, 23, 42, 0.85)" stroke="rgba(0, 240, 255, 0.3)" stroke-width="1"/>
<text x="14" y="22" fill="#00f0ff" font-size="12" font-weight="bold">热应力片状剥落机理 (Spallation)</text>
<text x="14" y="42" fill="#94a3b8" font-size="10">① 岩石低导热率 → 极窄层急剧膨胀</text>
<text x="14" y="58" fill="#94a3b8" font-size="10">② 内部冷态约束 → 形成巨大热剪/拉应力</text>
<text x="14" y="74" fill="#ff7020" font-size="10">③ 超越岩石抗拉强度(8MPa) → 薄片崩裂</text>
<text x="14" y="88" fill="#38bdf8" font-size="10">④ 高密超临界流瞬间携屑上返</text>
<path d="M 0 45 L -25 45 L -45 55" stroke="#00f0ff" stroke-width="1" fill="none" stroke-dasharray="3 2"/>
<circle cx="-45" cy="55" r="3" fill="#ff2a4b"/>
</g>
</svg>
<!-- 用于高性能粒子、剥落薄片飞溅、高温流体微团渲染的 Canvas 覆盖层 -->
<canvas id="fx-canvas"></canvas>
</div>
<script>
/**
* 高温超临界 CO₂ 破岩物理粒子与剥落动力学引擎
* 涵盖:高速超临界射流微团、热冲击驻点飞溅、岩石热应力片状剥落(Spallation Chips)、环空携屑上返流
*/
(function() {
const canvas = document.getElementById('fx-canvas');
const ctx = canvas.getContext('2d');
let width = 0;
let height = 0;
// 物理与工况状态
const state = {
temp: 680, // °C
speed: 265, // m/s
stressShow: true,
burstMultiplier: 1.0,
running: true
};
// 粒子容器
const jetParticles = []; // 射流高速微团
const spallChips = []; // 剥落的岩石薄片
const returnParticles = []; // 环空上返流携屑微团
// 坐标映射辅助(将 SVG 1600x900 逻辑坐标转换到真实 Canvas 像素)
function toCanvasCoord(svgX, svgY) {
const svgRatio = 1600 / 900;
const screenRatio = width / height;
let renderW, renderH, offsetX, offsetY;
if (screenRatio > svgRatio) {
renderH = height;
renderW = height * svgRatio;
offsetX = (width - renderW) / 2;
offsetY = 0;
} else {
renderW = width;
renderH = width / svgRatio;
offsetX = 0;
offsetY = (height - renderH) / 2;
}
const scale = renderW / 1600;
return {
x: offsetX + svgX * scale,
y: offsetY + svgY * scale,
scale: scale
};
}
function resize() {
width = canvas.width = window.innerWidth;
height = canvas.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();
// 创建高温射流粒子
function emitJetParticle() {
const count = Math.round(4 * (state.temp / 600) * state.burstMultiplier);
for (let i = 0; i < count; i++) {
const spread = (Math.random() - 0.5) * 28;
jetParticles.push({
svgX: 800 + spread,
svgY: 495,
vx: (Math.random() - 0.5) * 1.5,
vy: 14 + Math.random() * 8 + (state.speed - 200) * 0.05,
size: 2 + Math.random() * 3.5,
life: 1.0,
decay: 0.03 + Math.random() * 0.02,
temp: state.temp
});
}
}
// 创建剥落岩石薄片 (Spallation Flakes - 片状破岩创新特征)
function triggerSpallation(svgX, svgY) {
const count = Math.round((2 + Math.random() * 3) * state.burstMultiplier);
for (let i = 0; i < count; i++) {
const angle = Math.PI + (Math.random() - 0.5) * 1.8; // 向上反弹溅开
const speed = 4 + Math.random() * 9;
spallChips.push({
svgX: svgX + (Math.random() - 0.5) * 40,
svgY: svgY + (Math.random() - 0.5) * 10,
vx: Math.cos(angle) * speed,
vy: Math.sin(angle) * speed,
rot: Math.random() * Math.PI * 2,
vRot: (Math.random() - 0.5) * 0.3,
w: 5 + Math.random() * 9, // 片状长宽比大
h: 1.8 + Math.random() * 2.5,
life: 1.0,
decay: 0.008 + Math.random() * 0.012,
carried: false // 是否被环空流捕获上返
});
}
}
// 动画主循环
function animate() {
ctx.clearRect(0, 0, width, height);
// 1. 发射高速射流
if (state.running) {
emitJetParticle();
}
// 2. 渲染并更新射流粒子
for (let i = jetParticles.length - 1; i >= 0; i--) {
const p = jetParticles[i];
p.svgX += p.vx;
p.svgY += p.vy;
// 随着下落射流稍微向外展宽
p.vx += (p.svgX - 800) * 0.012;
p.life -= p.decay;
const pos = toCanvasCoord(p.svgX, p.svgY);
const r = p.size * pos.scale;
// 撞击井底岩面 (Y ~ 720~740)
if (p.svgY >= 725) {
// 触发热应力岩石剥落薄片
if (Math.random() < 0.28) {
triggerSpallation(p.svgX, p.svgY);
}
// 转化为环空返出微团
returnParticles.push({
svgX: p.svgX,
svgY: 720,
side: p.svgX < 800 ? -1 : 1,
vx: (p.svgX < 800 ? -1 : 1) * (4 + Math.random() * 4),
vy: -2 - Math.random() * 3,
size: 2 + Math.random() * 2,
life: 1.0,
decay: 0.012 + Math.random() * 0.01
});
jetParticles.splice(i, 1);
continue;
}
if (p.life <= 0) {
jetParticles.splice(i, 1);
continue;
}
// 绘制超临界微团光晕
ctx.beginPath();
ctx.arc(pos.x, pos.y, r * 1.8, 0, Math.PI * 2);
ctx.fillStyle = `rgba(255, ${Math.floor(120 + p.life * 135)}, ${Math.floor(p.life * 80)}, ${p.life * 0.7})`;
ctx.fill();
ctx.beginPath();
ctx.arc(pos.x, pos.y, r * 0.8, 0, Math.PI * 2);
ctx.fillStyle = `#ffffff`;
ctx.fill();
}
// 3. 渲染剥落的片状岩屑 (Spallation Flakes)
for (let i = spallChips.length - 1; i >= 0; i--) {
const c = spallChips[i];
c.svgX += c.vx;
c.svgY += c.vy;
c.rot += c.vRot;
c.life -= c.decay;
// 受到高密度超临界 CO₂ 环空流的携屑升力与侧向推力
if (c.svgY < 700) {
c.carried = true;
}
if (c.carried) {
const targetX = c.svgX < 800 ? 580 : 1020;
c.vx += (targetX - c.svgX) * 0.03; // 向环空收拢
c.vy -= 0.45; // 强劲上返流加速上浮
} else {
c.vy += 0.2; // 微小重力
}
const pos = toCanvasCoord(c.svgX, c.svgY);
const w = c.w * pos.scale;
const h = c.h * pos.scale;
ctx.save();
ctx.translate(pos.x, pos.y);
ctx.rotate(c.rot);
// 刚剥落时带有高温红热余晖,随后冷却为岩石灰褐色
const hotR = Math.floor(255 * c.life);
const hotG = Math.floor(120 * c.life);
ctx.fillStyle = `rgb(${Math.max(100, hotR)}, ${Math.max(80, hotG)}, 60)`;
ctx.strokeStyle = `rgba(255, 200, 100, ${c.life * 0.8})`;
ctx.lineWidth = 1;
// 绘制片状微多边形
ctx.beginPath();
ctx.moveTo(-w/2, -h/2);
ctx.lineTo(w/2, -h/3);
ctx.lineTo(w/2.2, h/2);
ctx.lineTo(-w/2.5, h/2.5);
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.restore();
if (c.life <= 0 || c.svgY < -50) {
spallChips.splice(i, 1);
}
}
// 4. 渲染环空携屑超临界循环流微团
for (let i = returnParticles.length - 1; i >= 0; i--) {
const rp = returnParticles[i];
rp.svgX += rp.vx;
rp.svgY += rp.vy;
rp.life -= rp.decay;
// 环空约束流线
if (rp.side === -1) {
if (rp.svgX < 540) rp.vx += 0.6;
if (rp.svgX > 620) rp.vx -= 0.6;
} else {
if (rp.svgX < 980) rp.vx += 0.6;
if (rp.svgX > 1060) rp.vx -= 0.6;
}
// 向上返出加速
rp.vy -= 0.35;
const pos = toCanvasCoord(rp.svgX, rp.svgY);
const r = rp.size * pos.scale;
ctx.beginPath();
ctx.arc(pos.x, pos.y, r, 0, Math.PI * 2);
ctx.fillStyle = `rgba(0, 240, 255, ${rp.life * 0.45})`;
ctx.fill();
if (rp.life <= 0 || rp.svgY < -30) {
returnParticles.splice(i, 1);
}
}
// 恢复脉冲倍率平滑
if (state.burstMultiplier > 1.0) {
state.burstMultiplier -= 0.02;
}
requestAnimationFrame(animate);
}
// 启动自动播放
requestAnimationFrame(animate);
// UI 控件与数据动态响应
const powerSlider = document.getElementById('power-slider');
const powerVal = document.getElementById('power-val');
const dispTemp = document.getElementById('disp-temp');
const dispSpeed = document.getElementById('disp-speed');
const dispStress = document.getElementById('disp-stress');
const btnToggleStress = document.getElementById('btn-toggle-stress');
const btnBurst = document.getElementById('btn-burst');
const stressField = document.getElementById('stress-field');
const crackNetwork = document.getElementById('crack-network');
function updateParameters(temp) {
state.temp = parseInt(temp);
state.speed = Math.round(200 + (state.temp - 500) * 0.45);
const stress = (state.temp * 0.21).toFixed(1);
powerVal.innerText = `${state.temp} °C`;
dispTemp.innerText = `${state.temp} °C`;
dispSpeed.innerText = `${state.speed} m/s`;
dispStress.innerText = `${stress} / 8.5 MPa`;
// 动态调整 SVG 热应力场强度
if (stressField) {
stressField.style.opacity = (state.temp / 750) * 0.9;
}
}
powerSlider.addEventListener('input', (e) => {
updateParameters(e.target.value);
});
btnToggleStress.addEventListener('click', () => {
state.stressShow = !state.stressShow;
btnToggleStress.innerText = `热应力云图: ${state.stressShow ? '开' : '关'}`;
stressField.style.display = state.stressShow ? 'block' : 'none';
crackNetwork.style.display = state.stressShow ? 'block' : 'none';
});
btnBurst.addEventListener('click', () => {
state.burstMultiplier = 3.5;
// 激波闪烁动效
const skin = document.getElementById('thermal-skin');
if (skin) {
skin.style.transform = 'scale(1.15)';
skin.style.transformOrigin = '800px 720px';
setTimeout(() => {
skin.style.transform = 'scale(1.0)';
}, 300);
}
});
})();
</script>
</body>
</html>
积分规则:每轮对话扣10分
等待动画代码生成...
