222 lines
10 KiB
HTML

<!--
Component: chart-svg
SVG 内嵌图表参考 — 适合简单图表(数据点 ≤ 8)
Agent 参考此文件的写法,根据实际数据生成 SVG 图表代码
直接嵌入到 slide--chart 布局的 .chart-container 中
⚡ CSS 入场动画:
SVG 图表默认支持 CSS 动画。当 Slide 变为 .active 时,
通过 .slide.active 选择器触发动画,无需 JS 介入。
-->
<!-- ============================================================
示例 1:水平柱状图(带入场动画)
============================================================ -->
<svg class="chart-svg chart-svg--bar" viewBox="0 0 600 300" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-height:100%">
<!-- 背景网格线 -->
<line x1="100" y1="40" x2="100" y2="260" stroke="var(--color-border)" stroke-width="1"/>
<line x1="100" y1="260" x2="580" y2="260" stroke="var(--color-border)" stroke-width="1"/>
<!-- 数据条 — Agent 根据实际数据调整 width 和文字 -->
<!-- 每个 rect 使用 chart-bar 类触发宽度生长动画 -->
<g>
<text x="90" y="75" text-anchor="end" font-size="14" fill="var(--color-text-secondary)">产品A</text>
<rect class="chart-bar" x="100" y="58" width="380" height="28" rx="4" fill="var(--color-primary)" opacity="0.85" style="--bar-target: 380"/>
<text class="chart-label" x="490" y="77" font-size="13" fill="var(--color-text-secondary)">78%</text>
</g>
<g>
<text x="90" y="125" text-anchor="end" font-size="14" fill="var(--color-text-secondary)">产品B</text>
<rect class="chart-bar" x="100" y="108" width="300" height="28" rx="4" fill="var(--color-primary)" opacity="0.7" style="--bar-target: 300"/>
<text class="chart-label" x="410" y="127" font-size="13" fill="var(--color-text-secondary)">62%</text>
</g>
<g>
<text x="90" y="175" text-anchor="end" font-size="14" fill="var(--color-text-secondary)">产品C</text>
<rect class="chart-bar" x="100" y="158" width="220" height="28" rx="4" fill="var(--color-primary)" opacity="0.55" style="--bar-target: 220"/>
<text class="chart-label" x="330" y="177" font-size="13" fill="var(--color-text-secondary)">45%</text>
</g>
<g>
<text x="90" y="225" text-anchor="end" font-size="14" fill="var(--color-text-secondary)">产品D</text>
<rect class="chart-bar" x="100" y="208" width="160" height="28" rx="4" fill="var(--color-primary)" opacity="0.4" style="--bar-target: 160"/>
<text class="chart-label" x="270" y="227" font-size="13" fill="var(--color-text-secondary)">33%</text>
</g>
</svg>
<!-- ============================================================
示例 2:饼图 / 环形图(带描边展开动画)
============================================================ -->
<!--
环形图使用 stroke-dasharray + stroke-dashoffset 技巧
圆周长 = 2 * π * r ≈ 314.16(r=50)
每段弧长 = 百分比 × 314.16
动画:从 stroke-dashoffset = 圆周长 → 最终位置
-->
<svg class="chart-svg chart-svg--donut" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" style="width:280px;height:280px">
<!-- 底色圆环 -->
<circle cx="100" cy="100" r="50" fill="none"
stroke="var(--color-border)" stroke-width="20"/>
<!-- 数据段 1: 45% → 长度 141.37 -->
<circle class="chart-donut-seg" cx="100" cy="100" r="50" fill="none"
stroke="var(--color-primary)" stroke-width="20"
stroke-dasharray="141.37 172.79"
stroke-dashoffset="0"
style="--donut-delay: 0s"
transform="rotate(-90 100 100)"/>
<!-- 数据段 2: 30% → 长度 94.25,偏移 = 141.37 -->
<circle class="chart-donut-seg" cx="100" cy="100" r="50" fill="none"
stroke="var(--color-accent)" stroke-width="20"
stroke-dasharray="94.25 219.91"
stroke-dashoffset="-141.37"
style="--donut-delay: 0.3s"
transform="rotate(-90 100 100)"/>
<!-- 数据段 3: 25% → 长度 78.54,偏移 = 235.62 -->
<circle class="chart-donut-seg" cx="100" cy="100" r="50" fill="none"
stroke="var(--color-secondary)" stroke-width="20" opacity="0.5"
stroke-dasharray="78.54 235.62"
stroke-dashoffset="-235.62"
style="--donut-delay: 0.6s"
transform="rotate(-90 100 100)"/>
<!-- 中心文字 -->
<text class="chart-label" x="100" y="96" text-anchor="middle" font-size="18" font-weight="700" fill="var(--color-text)">100%</text>
<text class="chart-label" x="100" y="114" text-anchor="middle" font-size="10" fill="var(--color-text-secondary)">总计</text>
</svg>
<!-- ============================================================
示例 3:简单折线(用 polyline,带绘制动画)
============================================================ -->
<svg class="chart-svg chart-svg--line" viewBox="0 0 600 300" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-height:100%">
<!-- 网格 -->
<line x1="60" y1="20" x2="60" y2="260" stroke="var(--color-border)" stroke-width="1"/>
<line x1="60" y1="260" x2="580" y2="260" stroke="var(--color-border)" stroke-width="1"/>
<!-- 横向参考线 -->
<line x1="60" y1="80" x2="580" y2="80" stroke="var(--color-border)" stroke-width="0.5" stroke-dasharray="4"/>
<line x1="60" y1="140" x2="580" y2="140" stroke="var(--color-border)" stroke-width="0.5" stroke-dasharray="4"/>
<line x1="60" y1="200" x2="580" y2="200" stroke="var(--color-border)" stroke-width="0.5" stroke-dasharray="4"/>
<!-- 折线 — 使用 stroke-dasharray 实现绘制动画 -->
<!-- Agent 需要计算 polyline 总路径长度(近似值即可),设为 stroke-dasharray -->
<polyline class="chart-line-path" points="80,220 160,180 240,140 320,160 400,100 480,60 560,80"
fill="none" stroke="var(--color-primary)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"
style="--line-length: 700"/>
<!-- 数据点 — 延迟淡入 -->
<circle class="chart-dot" cx="80" cy="220" r="4" fill="var(--color-primary)" style="--dot-delay: 0.8s"/>
<circle class="chart-dot" cx="160" cy="180" r="4" fill="var(--color-primary)" style="--dot-delay: 0.9s"/>
<circle class="chart-dot" cx="240" cy="140" r="4" fill="var(--color-primary)" style="--dot-delay: 1.0s"/>
<circle class="chart-dot" cx="320" cy="160" r="4" fill="var(--color-primary)" style="--dot-delay: 1.1s"/>
<circle class="chart-dot" cx="400" cy="100" r="4" fill="var(--color-primary)" style="--dot-delay: 1.2s"/>
<circle class="chart-dot" cx="480" cy="60" r="4" fill="var(--color-primary)" style="--dot-delay: 1.3s"/>
<circle class="chart-dot" cx="560" cy="80" r="4" fill="var(--color-primary)" style="--dot-delay: 1.4s"/>
<!-- X 轴标签 -->
<text x="80" y="280" text-anchor="middle" font-size="12" fill="var(--color-text-secondary)">1月</text>
<text x="160" y="280" text-anchor="middle" font-size="12" fill="var(--color-text-secondary)">2月</text>
<text x="240" y="280" text-anchor="middle" font-size="12" fill="var(--color-text-secondary)">3月</text>
<text x="320" y="280" text-anchor="middle" font-size="12" fill="var(--color-text-secondary)">4月</text>
<text x="400" y="280" text-anchor="middle" font-size="12" fill="var(--color-text-secondary)">5月</text>
<text x="480" y="280" text-anchor="middle" font-size="12" fill="var(--color-text-secondary)">6月</text>
<text x="560" y="280" text-anchor="middle" font-size="12" fill="var(--color-text-secondary)">7月</text>
</svg>
<!-- ============================================================
SVG 图表动画样式
Agent 将此 <style> 块注入到 base.html 的布局样式占位区域
关键:所有动画由 .slide.active 选择器触发,
Slide 不可见时元素保持初始状态,翻到时自动播放
============================================================ -->
<style>
/* --- 柱状图:宽度从 0 生长 --- */
.chart-bar {
transform-origin: left center;
transform: scaleX(0);
transition: none;
}
.slide.active .chart-bar {
animation: chartBarGrow 0.8s ease-out forwards;
}
@keyframes chartBarGrow {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
/* 逐条错开:第 2/3/4 条延迟 */
.slide.active g:nth-child(3) .chart-bar { animation-delay: 0.1s; }
.slide.active g:nth-child(4) .chart-bar { animation-delay: 0.2s; }
.slide.active g:nth-child(5) .chart-bar { animation-delay: 0.3s; }
.slide.active g:nth-child(6) .chart-bar { animation-delay: 0.4s; }
/* --- 标签淡入 --- */
.chart-label {
opacity: 0;
}
.slide.active .chart-label {
animation: chartFadeIn 0.4s ease-out forwards;
animation-delay: 0.6s;
}
/* --- 环形图:描边展开 --- */
.chart-donut-seg {
opacity: 0;
}
.slide.active .chart-donut-seg {
animation: chartDonutReveal 0.8s ease-out forwards;
animation-delay: var(--donut-delay, 0s);
}
@keyframes chartDonutReveal {
from { opacity: 0; stroke-width: 0; }
to { opacity: 1; stroke-width: 20; }
}
/* --- 折线图:路径绘制 --- */
.chart-line-path {
stroke-dasharray: var(--line-length, 1000);
stroke-dashoffset: var(--line-length, 1000);
}
.slide.active .chart-line-path {
animation: chartLineDraw 1.2s ease-out forwards;
}
@keyframes chartLineDraw {
to { stroke-dashoffset: 0; }
}
/* --- 数据点:延迟弹入 --- */
.chart-dot {
opacity: 0;
transform-origin: center;
r: 0;
}
.slide.active .chart-dot {
animation: chartDotPop 0.3s ease-out forwards;
animation-delay: var(--dot-delay, 0.8s);
}
@keyframes chartDotPop {
from { opacity: 0; r: 0; }
to { opacity: 1; r: 4; }
}
/* --- 通用淡入 --- */
@keyframes chartFadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
</style>
<!--
使用说明:
1. SVG 图表的动画完全由 CSS 驱动,通过 .slide.active 选择器自动触发
— 不需要 JS,不需要 slideAnimations 注册
2. Agent 根据实际数据调整坐标、颜色和文字
3. 所有颜色使用 CSS 变量,自动适配当前主题(浅色/深色均可)
4. SVG 内嵌到 HTML 中,无外部依赖,自包含
5. 适合数据点 ≤ 8 的简单图表,复杂图表请使用 Chart.js(见 chart-js.html)
6. Agent 需要将 <style> 块注入到 base.html 的布局样式占位区域
7. 折线图的 --line-length 需要 Agent 估算 polyline 的路径总长度
(近似方法:各点间距离之和,不需要精确)
-->