@topmindspace/tms-skills 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/LICENSE +21 -0
  3. package/README.md +102 -0
  4. package/bin/tms-skills.js +160 -0
  5. package/package.json +48 -0
  6. package/top-ppt-html/README.md +254 -0
  7. package/top-ppt-html/SKILL.md +111 -0
  8. package/top-ppt-html/assets/examples/2026-09-09-architecture-graphite-dark.html +3926 -0
  9. package/top-ppt-html/assets/examples/2026-09-09-architecture-graphite-dark.model.json +168 -0
  10. package/top-ppt-html/assets/examples/2026-09-09-architecture-spectrum.html +3926 -0
  11. package/top-ppt-html/assets/examples/2026-09-09-architecture-spectrum.model.json +168 -0
  12. package/top-ppt-html/assets/examples/2026-09-09-presentation-apple-mono.html +4325 -0
  13. package/top-ppt-html/assets/examples/2026-09-09-presentation-apple-mono.model.json +321 -0
  14. package/top-ppt-html/assets/examples/2026-09-09-presentation-brand-red.html +4325 -0
  15. package/top-ppt-html/assets/examples/2026-09-09-presentation-brand-red.model.json +321 -0
  16. package/top-ppt-html/assets/examples/2026-09-09-presentation-business-blue.html +4325 -0
  17. package/top-ppt-html/assets/examples/2026-09-09-presentation-business-blue.model.json +321 -0
  18. package/top-ppt-html/assets/examples/2026-09-09-research-deep-teal.html +5527 -0
  19. package/top-ppt-html/assets/examples/2026-09-09-research-deep-teal.model.json +914 -0
  20. package/top-ppt-html/assets/examples/2026-09-09-research-indigo-violet.html +5527 -0
  21. package/top-ppt-html/assets/examples/2026-09-09-research-indigo-violet.model.json +914 -0
  22. package/top-ppt-html/assets/examples/2026-09-09-research-mckinsey.html +5527 -0
  23. package/top-ppt-html/assets/examples/2026-09-09-research-mckinsey.model.json +914 -0
  24. package/top-ppt-html/assets/examples/2026-09-09-research-warm-sand.html +5527 -0
  25. package/top-ppt-html/assets/examples/2026-09-09-research-warm-sand.model.json +914 -0
  26. package/top-ppt-html/assets/pptx-export.js +1944 -0
  27. package/top-ppt-html/assets/style-gallery.html +589 -0
  28. package/top-ppt-html/assets/templates/architecture.html +3728 -0
  29. package/top-ppt-html/assets/templates/engine.css +840 -0
  30. package/top-ppt-html/assets/templates/presentation.html +3738 -0
  31. package/top-ppt-html/assets/templates/research.html +4017 -0
  32. package/top-ppt-html/assets/templates/ui.js +520 -0
  33. package/top-ppt-html/assets/theme-overview-architecture.png +0 -0
  34. package/top-ppt-html/assets/theme-overview-presentation.png +0 -0
  35. package/top-ppt-html/assets/theme-overview-research.png +0 -0
  36. package/top-ppt-html/assets/theme-overview.png +0 -0
  37. package/top-ppt-html/evals/prompts.csv +15 -0
  38. package/top-ppt-html/evals/rubric.schema.json +25 -0
  39. package/top-ppt-html/evals/run_evals.py +220 -0
  40. package/top-ppt-html/evals/trace.example.json +16 -0
  41. package/top-ppt-html/package.json +35 -0
  42. package/top-ppt-html/references/charts-basic.md +624 -0
  43. package/top-ppt-html/references/charts-discipline.md +108 -0
  44. package/top-ppt-html/references/charts-extended.md +482 -0
  45. package/top-ppt-html/references/charts.md +28 -0
  46. package/top-ppt-html/references/components-atoms.md +624 -0
  47. package/top-ppt-html/references/components.md +30 -0
  48. package/top-ppt-html/references/content-rules.md +490 -0
  49. package/top-ppt-html/references/design-system-engine.md +235 -0
  50. package/top-ppt-html/references/design-system.md +478 -0
  51. package/top-ppt-html/references/failure-modes.md +214 -0
  52. package/top-ppt-html/references/high-fidelity.md +127 -0
  53. package/top-ppt-html/references/icons.md +397 -0
  54. package/top-ppt-html/references/industry-benchmark.md +105 -0
  55. package/top-ppt-html/references/infographics-stats.md +308 -0
  56. package/top-ppt-html/references/infographics-structure.md +226 -0
  57. package/top-ppt-html/references/infographics.md +43 -0
  58. package/top-ppt-html/references/layout-grammar.md +315 -0
  59. package/top-ppt-html/references/layouts-architecture.md +108 -0
  60. package/top-ppt-html/references/layouts-combo.md +600 -0
  61. package/top-ppt-html/references/layouts-research.md +160 -0
  62. package/top-ppt-html/references/modes.md +254 -0
  63. package/top-ppt-html/references/outline-design.md +275 -0
  64. package/top-ppt-html/references/playbook.md +266 -0
  65. package/top-ppt-html/references/pptx-export.md +209 -0
  66. package/top-ppt-html/references/reform-plan.md +252 -0
  67. package/top-ppt-html/references/styles.md +370 -0
  68. package/top-ppt-html/references/tech-design.md +138 -0
  69. package/top-ppt-html/scripts/audit_css.py +109 -0
  70. package/top-ppt-html/scripts/audit_docs.py +176 -0
  71. package/top-ppt-html/scripts/audit_skill.py +220 -0
  72. package/top-ppt-html/scripts/audit_styles.py +351 -0
  73. package/top-ppt-html/scripts/build_examples.py +2276 -0
  74. package/top-ppt-html/scripts/build_pptx.js +2380 -0
  75. package/top-ppt-html/scripts/capture_theme_overview.js +78 -0
  76. package/top-ppt-html/scripts/checks_html.py +127 -0
  77. package/top-ppt-html/scripts/cross_verify.py +294 -0
  78. package/top-ppt-html/scripts/env_probe.py +158 -0
  79. package/top-ppt-html/scripts/extract_model.py +210 -0
  80. package/top-ppt-html/scripts/extract_snippet.py +374 -0
  81. package/top-ppt-html/scripts/gen_channel_a.js +214 -0
  82. package/top-ppt-html/scripts/layout-constants.json +3377 -0
  83. package/top-ppt-html/scripts/layout_slots.json +830 -0
  84. package/top-ppt-html/scripts/lib_layout_regions.js +412 -0
  85. package/top-ppt-html/scripts/measure_height.py +178 -0
  86. package/top-ppt-html/scripts/model-schema.json +547 -0
  87. package/top-ppt-html/scripts/negative_tests.py +307 -0
  88. package/top-ppt-html/scripts/package_skill.py +291 -0
  89. package/top-ppt-html/scripts/prepare_images.py +341 -0
  90. package/top-ppt-html/scripts/probe_image_export.py +188 -0
  91. package/top-ppt-html/scripts/quality_gate.py +301 -0
  92. package/top-ppt-html/scripts/regression.py +308 -0
  93. package/top-ppt-html/scripts/render_compare.py +275 -0
  94. package/top-ppt-html/scripts/render_from_model.py +698 -0
  95. package/top-ppt-html/scripts/scaffold_report.py +1054 -0
  96. package/top-ppt-html/scripts/section-file-map.json +105 -0
  97. package/top-ppt-html/scripts/sync_runtime.py +662 -0
  98. package/top-ppt-html/scripts/validate_pptx.py +1510 -0
  99. package/top-ppt-html/scripts/validate_report.py +1456 -0
@@ -0,0 +1,624 @@
1
+ # 图表全库 · charts-basic.md
2
+
3
+ > 由 `charts.md` 拆出(§编号保持不变,跨文件稳定引用)。
4
+ > 取码:`python scripts/extract_snippet.py --file charts.md --section <编号>`
5
+ > 或直接 `--file charts-basic.md --section <编号>`。整读大文件视为违规。
6
+
7
+ ## 16. 环形图(占比)`data-chart="donut"`
8
+
9
+ ```html
10
+ <div class="fig" style="text-align:center">
11
+ <div class="fig__cap">图表标题</div>
12
+ <svg class="chart" data-chart="donut" viewBox="0 0 140 140" style="width:150px;margin-inline:auto">
13
+ <circle cx="70" cy="70" r="54" class="f-none s-bds" stroke-width="15"/>
14
+ <circle data-sweep data-circ="339.3" data-p="0.31" cx="70" cy="70" r="54" class="f-none s-acc"
15
+ stroke-width="15" stroke-dasharray="105.3 234" stroke-linecap="round"
16
+ transform="rotate(-90 70 70)"><title>使用率 31%</title></circle>
17
+ <text x="70" y="68" text-anchor="middle" class="f-txt" font-size="24" font-weight="600"
18
+ data-count="31" data-suffix="%">31%</text>
19
+ <text x="70" y="88" text-anchor="middle" class="f-txt3" font-size="11">使用率</text>
20
+ </svg>
21
+ <div class="row" style="justify-content:center;gap:var(--sp-4);margin-top:var(--sp-4)">
22
+ <span class="chip chip--accent">已使用 31%</span>
23
+ <span class="chip">未使用 69%</span>
24
+ </div>
25
+ </div>
26
+ ```
27
+
28
+ 周长 `= 2π × 54 ≈ 339.3`;`31% → 105.3`,`69% → 234`。
29
+ 公式:`dasharray="{周长×p} {周长×(1-p)}"`。
30
+
31
+ **饼图变体**(`data-chart="pie"`):去掉背景挖孔圆(`.f-none.s-bds` 那一圈),弧段半径铺满即可;中心不再放合计数字,改由右侧图例承担——其余同构,配色仍走语义类。
32
+
33
+ ---
34
+
35
+ ---
36
+
37
+ ## 17. 横向条形图(排名 / 对比)`data-chart="hbar"`
38
+
39
+ ```html
40
+ <div class="fig">
41
+ <div class="fig__cap">各域覆盖率</div>
42
+ <svg class="chart" data-chart="hbar" viewBox="0 0 520 150">
43
+ <!-- 每行:标签 + 底槽 + 实条 + 数值;行高 30 -->
44
+ <text x="0" y="18" class="f-txt2" font-size="12">供应链</text>
45
+ <rect x="80" y="7" width="360" height="15" rx="7.5" class="f-s2"/>
46
+ <rect x="80" y="7" width="274" height="15" rx="7.5" class="f-acc"><title>供应链 76%</title></rect>
47
+ <text x="450" y="19" text-anchor="end" class="f-txt" font-size="12" font-weight="600">76%</text>
48
+
49
+ <text x="0" y="48" class="f-txt2" font-size="12">财务</text>
50
+ <rect x="80" y="37" width="360" height="15" rx="7.5" class="f-s2"/>
51
+ <rect x="80" y="37" width="205" height="15" rx="7.5" class="f-acc"/>
52
+ <text x="450" y="49" text-anchor="end" class="f-txt" font-size="12" font-weight="600">57%</text>
53
+
54
+ <text x="0" y="78" class="f-txt2" font-size="12">研发</text>
55
+ <rect x="80" y="67" width="360" height="15" rx="7.5" class="f-s2"/>
56
+ <rect x="80" y="67" width="126" height="15" rx="7.5" class="f-acc"/>
57
+ <text x="450" y="79" text-anchor="end" class="f-txt" font-size="12" font-weight="600">35%</text>
58
+ </svg>
59
+ </div>
60
+ ```
61
+
62
+ 条宽 `= 槽宽 × p`。
63
+
64
+ ---
65
+
66
+ ---
67
+
68
+ ## 18. 分组柱状图(阶段目标)`data-chart="bar"`
69
+
70
+ ```html
71
+ <div class="fig">
72
+ <div class="fig__cap">分阶段目标</div>
73
+ <svg class="chart" data-chart="bar" viewBox="0 0 560 220">
74
+ <line x1="46" y1="170" x2="540" y2="170" class="s-bds" stroke-width="1"/>
75
+ <!-- 柱高 = 值/100 × 130;y = 170 - 柱高 -->
76
+ <rect data-anim="grow" x="60" y="131" width="58" height="39" rx="6" class="f-s3"/>
77
+ <rect data-anim="grow" x="188" y="92" width="58" height="78" rx="6" class="f-s3"/>
78
+ <rect data-anim="grow" x="316" y="60" width="58" height="110" rx="6" class="f-acc"/>
79
+ <rect data-anim="grow" x="444" y="53" width="58" height="117" rx="6" class="f-acc"/>
80
+ <text data-anim="fade" x="89" y="152" text-anchor="middle" class="t-on-inv" font-size="13" font-weight="600">30%</text>
81
+ <text data-anim="fade" x="89" y="192" text-anchor="middle" class="f-txt3" font-size="11">2026Q3</text>
82
+ </svg>
83
+ </div>
84
+ ```
85
+
86
+ ---
87
+
88
+ ---
89
+
90
+ ## 19. 堆叠柱状图(构成随阶段变化)`data-chart="stack"`
91
+
92
+ ```html
93
+ <div class="fig">
94
+ <div class="fig__cap">数据消费构成(按季度)</div>
95
+ <svg class="chart" data-chart="stack" viewBox="0 0 560 220">
96
+ <line x1="40" y1="180" x2="540" y2="180" class="s-bds" stroke-width="1"/>
97
+ <!-- 每柱两段堆叠:下段 f-s3,上段 f-acc;总高 = 值/100*140 -->
98
+ <g>
99
+ <rect data-anim="grow" x="90" y="120" width="60" height="60" rx="4" class="f-s3"/>
100
+ <rect data-anim="grow" x="90" y="96" width="60" height="24" rx="4" class="f-acc"/>
101
+ <text x="120" y="196" text-anchor="middle" class="f-txt3" font-size="11">Q3</text>
102
+ </g>
103
+ <g>
104
+ <rect data-anim="grow" x="250" y="100" width="60" height="80" rx="4" class="f-s3"/>
105
+ <rect data-anim="grow" x="250" y="66" width="60" height="34" rx="4" class="f-acc"/>
106
+ <text x="280" y="196" text-anchor="middle" class="f-txt3" font-size="11">Q4</text>
107
+ </g>
108
+ <!-- 图例 -->
109
+ <rect x="90" y="10" width="10" height="10" rx="2" class="f-acc"/><text x="104" y="19" class="f-txt3" font-size="11">服务层消费</text>
110
+ <rect x="190" y="10" width="10" height="10" rx="2" class="f-s3"/><text x="204" y="19" class="f-txt3" font-size="11">直连/其他</text>
111
+ </svg>
112
+ </div>
113
+ ```
114
+
115
+ ---
116
+
117
+ ---
118
+
119
+ ## 20. 100% 堆叠条(构成占比)`data-chart="stackline"`
120
+
121
+ ```html
122
+ <div class="fig">
123
+ <div class="fig__cap">数据消费构成</div>
124
+ <svg class="chart" data-chart="stackline" viewBox="0 0 560 60">
125
+ <!-- 三段拼满 520 宽,占比 45/35/20 -->
126
+ <rect x="20" y="18" width="234" height="24" rx="6" class="f-acc"/>
127
+ <rect x="254" y="18" width="182" height="24" class="f-s3"/>
128
+ <rect x="436" y="18" width="104" height="24" rx="6" class="f-s2"/>
129
+ <text x="137" y="34" text-anchor="middle" class="t-on-inv" font-size="12" font-weight="600">服务层 45%</text>
130
+ <text x="345" y="34" text-anchor="middle" class="f-txt" font-size="12">直连 35%</text>
131
+ <text x="488" y="34" text-anchor="middle" class="f-txt2" font-size="12">其他 20%</text>
132
+ </svg>
133
+ </div>
134
+ ```
135
+
136
+ ---
137
+
138
+ ---
139
+
140
+ ## 21. 折线 / 面积图(时间趋势)`data-chart="line"`
141
+
142
+ ```html
143
+ <div class="fig">
144
+ <div class="fig__cap">可信数据消费率趋势</div>
145
+ <svg class="chart" data-chart="line" viewBox="0 0 560 220">
146
+ <!-- 网格线 -->
147
+ <line x1="46" y1="180" x2="540" y2="180" class="s-bds" stroke-width="1"/>
148
+ <line x1="46" y1="130" x2="540" y2="130" class="s-bds" stroke-width="1" stroke-dasharray="3 5"/>
149
+ <line x1="46" y1="80" x2="540" y2="80" class="s-bds" stroke-width="1" stroke-dasharray="3 5"/>
150
+ <!-- 面积(accent 12% 透明) -->
151
+ <path d="M60,150 L180,120 L300,95 L420,70 L520,50 L520,180 L60,180 Z"
152
+ class="f-acc" fill-opacity=".12"/>
153
+ <!-- 折线(data-draw 描边动效) -->
154
+ <path data-draw d="M60,150 L180,120 L300,95 L420,70 L520,50" class="f-none s-acc"
155
+ stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
156
+ <!-- 数据点 -->
157
+ <circle cx="60" cy="150" r="4" class="f-acc"><title>Q3 · 32%</title></circle>
158
+ <circle cx="180" cy="120" r="4" class="f-acc"/><circle cx="300" cy="95" r="4" class="f-acc"/>
159
+ <circle cx="420" cy="70" r="4" class="f-acc"/><circle cx="520" cy="50" r="4" class="f-acc"/>
160
+ <!-- 轴标签 -->
161
+ <text x="60" y="200" text-anchor="middle" class="f-txt3" font-size="11">Q3</text>
162
+ <text x="180" y="200" text-anchor="middle" class="f-txt3" font-size="11">Q4</text>
163
+ <text x="300" y="200" text-anchor="middle" class="f-txt3" font-size="11">2027H1</text>
164
+ <text x="420" y="200" text-anchor="middle" class="f-txt3" font-size="11">H2</text>
165
+ <text x="520" y="200" text-anchor="middle" class="f-txt3" font-size="11">2028</text>
166
+ </svg>
167
+ </div>
168
+ ```
169
+
170
+ ---
171
+
172
+ ---
173
+
174
+ ## 22. 雷达图(多维能力,≤6 维)`data-chart="radar"`
175
+
176
+ ```html
177
+ <div class="fig" style="text-align:center">
178
+ <div class="fig__cap">治理能力雷达</div>
179
+ <svg class="chart" data-chart="radar" viewBox="0 0 260 240" style="width:230px;margin-inline:auto">
180
+ <!-- 同心网格(3 圈)+ 轴线 -->
181
+ <polygon points="130,30 216,80 216,165 130,215 44,165 44,80" class="f-none s-bds" stroke-width="1"/>
182
+ <polygon points="130,70 182,100 182,145 130,175 78,145 78,100" class="f-none s-bds" stroke-width="1"/>
183
+ <line x1="130" y1="120" x2="130" y2="30" class="s-bds" stroke-width="1"/>
184
+ <line x1="130" y1="120" x2="216" y2="80" class="s-bds" stroke-width="1"/>
185
+ <line x1="130" y1="120" x2="216" y2="165" class="s-bds" stroke-width="1"/>
186
+ <line x1="130" y1="120" x2="130" y2="215" class="s-bds" stroke-width="1"/>
187
+ <line x1="130" y1="120" x2="44" y2="165" class="s-bds" stroke-width="1"/>
188
+ <line x1="130" y1="120" x2="44" y2="80" class="s-bds" stroke-width="1"/>
189
+ <!-- 数据多边形 -->
190
+ <polygon points="130,48 198,90 196,150 130,180 60,150 62,95"
191
+ class="f-acc" fill-opacity=".18" stroke="var(--accent)" stroke-width="2"/>
192
+ <!-- 顶点标签 -->
193
+ <text x="130" y="22" text-anchor="middle" class="f-txt2" font-size="11">语义</text>
194
+ <text x="228" y="80" text-anchor="start" class="f-txt2" font-size="11">服务</text>
195
+ <text x="228" y="172" text-anchor="start" class="f-txt2" font-size="11">消费</text>
196
+ <text x="130" y="232" text-anchor="middle" class="f-txt2" font-size="11">底座</text>
197
+ <text x="32" y="172" text-anchor="end" class="f-txt2" font-size="11">安全</text>
198
+ <text x="32" y="80" text-anchor="end" class="f-txt2" font-size="11">契约</text>
199
+ </svg>
200
+ </div>
201
+ ```
202
+
203
+ ---
204
+
205
+ ---
206
+
207
+ ## 23. 仪表盘 / 进度环(达成度)`data-chart="gauge"`
208
+
209
+ ```html
210
+ <div class="fig" style="text-align:center">
211
+ <div class="fig__cap">年度目标达成度</div>
212
+ <svg class="chart" data-chart="gauge" viewBox="0 0 200 120" style="width:210px;margin-inline:auto">
213
+ <!-- 半环底槽 -->
214
+ <path d="M20 110 A 80 80 0 0 1 180 110" class="f-none s-bds" stroke-width="16" stroke-linecap="round"/>
215
+ <!-- 进度(弧长 = π×80 ≈ 251;72% → 181) -->
216
+ <path data-draw d="M20 110 A 80 80 0 0 1 180 110" class="f-none s-acc" stroke-width="16"
217
+ stroke-linecap="round" stroke-dasharray="181 251"/>
218
+ <text x="100" y="98" text-anchor="middle" class="f-txt" font-size="30" font-weight="700"
219
+ data-count="72" data-suffix="%">72%</text>
220
+ <text x="100" y="116" text-anchor="middle" class="f-txt3" font-size="11">指标纳管</text>
221
+ </svg>
222
+ </div>
223
+ ```
224
+
225
+ 半环周长 `= π × r`;`dasharray="{周长×p} {周长}"`。
226
+
227
+ ---
228
+
229
+ ---
230
+
231
+ ## 24. 瀑布图(增减归因 / 从 A 到 B)`data-chart="waterfall"`
232
+
233
+ ```html
234
+ <div class="fig">
235
+ <div class="fig__cap">使用率提升路径(31% → 60%)</div>
236
+ <svg class="chart" data-chart="waterfall" viewBox="0 0 560 230">
237
+ <line x1="40" y1="190" x2="540" y2="190" class="s-bds" stroke-width="1"/>
238
+ <!-- 每段:起点值→终点值;柱从 min 到 max;y = 190 - 值/100*160 -->
239
+ <rect data-anim="grow" x="60" y="140" width="70" height="50" rx="5" class="f-s3"/>
240
+ <text x="95" y="132" text-anchor="middle" class="f-txt2" font-size="12" font-weight="600">31%</text>
241
+ <text x="95" y="206" text-anchor="middle" class="f-txt3" font-size="11">基线</text>
242
+ <rect data-anim="grow" x="160" y="121" width="70" height="19" rx="5" class="f-acc"/>
243
+ <text x="195" y="113" text-anchor="middle" class="f-acc" font-size="12" font-weight="600">+12</text>
244
+ <text x="195" y="206" text-anchor="middle" class="f-txt3" font-size="11">清僵尸</text>
245
+ <rect data-anim="grow" x="260" y="106" width="70" height="15" rx="5" class="f-acc"/>
246
+ <text x="295" y="98" text-anchor="middle" class="f-acc" font-size="12" font-weight="600">+9</text>
247
+ <text x="295" y="206" text-anchor="middle" class="f-txt3" font-size="11">语义层</text>
248
+ <rect data-anim="grow" x="360" y="93" width="70" height="13" rx="5" class="f-acc"/>
249
+ <text x="395" y="85" text-anchor="middle" class="f-acc" font-size="12" font-weight="600">+8</text>
250
+ <text x="395" y="206" text-anchor="middle" class="f-txt3" font-size="11">服务化</text>
251
+ <rect data-anim="grow" x="460" y="94" width="70" height="96" rx="5" class="f-s3"/>
252
+ <text x="495" y="86" text-anchor="middle" class="f-txt" font-size="12" font-weight="700">60%</text>
253
+ <text x="495" y="206" text-anchor="middle" class="f-txt3" font-size="11">目标</text>
254
+ <!-- 连接虚线 -->
255
+ <line x1="130" y1="140" x2="160" y2="140" class="s-txt3" stroke-width="1" stroke-dasharray="3 3"/>
256
+ <line x1="230" y1="121" x2="260" y2="121" class="s-txt3" stroke-width="1" stroke-dasharray="3 3"/>
257
+ <line x1="330" y1="106" x2="360" y2="106" class="s-txt3" stroke-width="1" stroke-dasharray="3 3"/>
258
+ <line x1="430" y1="94" x2="460" y2="94" class="s-txt3" stroke-width="1" stroke-dasharray="3 3"/>
259
+ </svg>
260
+ </div>
261
+ ```
262
+
263
+ ---
264
+
265
+ ---
266
+
267
+ ## 25. 散点 / 气泡图(双维分布 / 优先级矩阵)`data-chart="scatter"`
268
+
269
+ ```html
270
+ <div class="fig">
271
+ <div class="fig__cap">用例优先级:价值 × 实施难度(气泡=数据量)</div>
272
+ <svg class="chart" data-chart="scatter" viewBox="0 0 560 260">
273
+ <!-- 象限分割线 -->
274
+ <line x1="60" y1="210" x2="530" y2="210" class="s-bds" stroke-width="1"/>
275
+ <line x1="60" y1="20" x2="60" y2="210" class="s-bds" stroke-width="1"/>
276
+ <line x1="295" y1="20" x2="295" y2="210" class="s-txt3" stroke-width="1" stroke-dasharray="3 5"/>
277
+ <line x1="60" y1="115" x2="530" y2="115" class="s-txt3" stroke-width="1" stroke-dasharray="3 5"/>
278
+ <!-- 轴标签 -->
279
+ <text x="530" y="228" text-anchor="end" class="f-txt3" font-size="11">业务价值 →</text>
280
+ <text x="52" y="30" text-anchor="end" class="f-txt3" font-size="11" transform="rotate(-90 52 30)">难度 →</text>
281
+ <!-- 气泡:cx=价值, cy=难度, r=规模;右上=优先做 -->
282
+ <circle cx="420" cy="70" r="16" class="f-acc" fill-opacity=".85"><title>ChatBI 问数 · 高价值低难度</title></circle>
283
+ <circle cx="350" cy="110" r="12" class="f-acc" fill-opacity=".6"/>
284
+ <circle cx="180" cy="80" r="10" class="f-s3"/>
285
+ <circle cx="140" cy="160" r="8" class="f-s3"/>
286
+ <circle cx="440" cy="170" r="11" class="f-s3"/>
287
+ <!-- 点标签 -->
288
+ <text x="420" y="48" text-anchor="middle" class="f-txt2" font-size="11">ChatBI 问数</text>
289
+ <text x="350" y="136" text-anchor="middle" class="f-txt2" font-size="11">经营预警</text>
290
+ <text x="180" y="60" text-anchor="middle" class="f-txt2" font-size="11">主数据治理</text>
291
+ </svg>
292
+ </div>
293
+ ```
294
+
295
+ ---
296
+
297
+ ---
298
+
299
+ ## 26. 漏斗图(转化 / 筛选)`data-chart="funnel"`
300
+
301
+ ```html
302
+ <div class="fig" style="text-align:center">
303
+ <div class="fig__cap">数据资产激活漏斗</div>
304
+ <svg class="chart" data-chart="funnel" viewBox="0 0 560 240" style="max-width:560px;margin-inline:auto">
305
+ <!-- 每层:居中梯形/矩形,宽 ∝ 数值;层间距 8 -->
306
+ <rect data-anim="fade" x="80" y="10" width="400" height="44" rx="8" class="f-acc" fill-opacity=".95"/>
307
+ <text x="280" y="37" text-anchor="middle" class="t-on-inv" font-size="13" font-weight="600">入湖表 4,662</text>
308
+ <rect data-anim="fade" x="120" y="66" width="320" height="44" rx="8" class="f-acc" fill-opacity=".75"/>
309
+ <text x="280" y="93" text-anchor="middle" class="t-on-inv" font-size="13" font-weight="600">纳入指标中心 2,100</text>
310
+ <rect data-anim="fade" x="160" y="122" width="240" height="44" rx="8" class="f-acc" fill-opacity=".55"/>
311
+ <text x="280" y="149" text-anchor="middle" class="t-on-inv" font-size="13" font-weight="600">挂接数据契约 890</text>
312
+ <rect data-anim="fade" x="200" y="178" width="160" height="44" rx="8" class="f-acc" fill-opacity=".38"/>
313
+ <text x="280" y="205" text-anchor="middle" class="f-txt" font-size="13" font-weight="600">被 Agent 消费 320</text>
314
+ <!-- 侧边转化率 -->
315
+ <text x="500" y="93" class="f-txt3" font-size="11">45%</text>
316
+ <text x="440" y="149" class="f-txt3" font-size="11">42%</text>
317
+ <text x="392" y="205" class="f-txt3" font-size="11">36%</text>
318
+ </svg>
319
+ </div>
320
+ ```
321
+
322
+ > 层宽 = 值/最大值 × 最大层宽;层数 ≤ 5,多了改条形图。
323
+
324
+ ---
325
+
326
+ ---
327
+
328
+ ## 27. 甘特 / 路线图(计划排期)`data-chart="gantt"`
329
+
330
+ ```html
331
+ <div class="fig">
332
+ <div class="fig__cap">数字大脑 3.0 四个季度路线</div>
333
+ <svg class="chart" data-chart="gantt" viewBox="0 0 560 190">
334
+ <!-- 季度刻度:4 列,每列 110 宽,从 x=130 起 -->
335
+ <line x1="130" y1="28" x2="130" y2="160" class="s-bds" stroke-width="1"/>
336
+ <line x1="240" y1="28" x2="240" y2="160" class="s-bds" stroke-width="1" stroke-dasharray="3 4"/>
337
+ <line x1="350" y1="28" x2="350" y2="160" class="s-bds" stroke-width="1" stroke-dasharray="3 4"/>
338
+ <line x1="460" y1="28" x2="460" y2="160" class="s-bds" stroke-width="1" stroke-dasharray="3 4"/>
339
+ <text x="185" y="20" text-anchor="middle" class="f-txt3" font-size="11">Q3</text>
340
+ <text x="295" y="20" text-anchor="middle" class="f-txt3" font-size="11">Q4</text>
341
+ <text x="405" y="20" text-anchor="middle" class="f-txt3" font-size="11">2027Q1</text>
342
+ <text x="515" y="20" text-anchor="middle" class="f-txt3" font-size="11">Q2</text>
343
+ <!-- 每行:任务标签 + 横道(accent=主线,s3=支撑) -->
344
+ <text x="0" y="56" class="f-txt2" font-size="12">指标中心</text>
345
+ <rect data-anim="grow" x="130" y="42" width="220" height="20" rx="10" class="f-acc"/>
346
+ <text x="0" y="94" class="f-txt2" font-size="12">数据契约</text>
347
+ <rect data-anim="grow" x="185" y="80" width="220" height="20" rx="10" class="f-acc" fill-opacity=".75"/>
348
+ <text x="0" y="132" class="f-txt2" font-size="12">治理 Agent</text>
349
+ <rect data-anim="grow" x="295" y="118" width="220" height="20" rx="10" class="f-s3"/>
350
+ <!-- 里程碑菱形 -->
351
+ <polygon points="350,36 358,44 350,52 342,44" class="f-acc"><title>Q4 末:指标中心上线</title></polygon>
352
+ </svg>
353
+ </div>
354
+ ```
355
+
356
+ > 横道 `data-anim="grow"` 需把 CSS 的 `transform-origin` 换成 `left center`(横向生长,见第 35 节附注)。
357
+
358
+ ---
359
+
360
+ ---
361
+
362
+ ## 28. 双向对比条形(正/反、A/B 对比)`data-chart="vsbar"`
363
+
364
+ ```html
365
+ <div class="fig">
366
+ <div class="fig__cap">直连源库 vs 指标中心(业务满意度)</div>
367
+ <svg class="chart" data-chart="vsbar" viewBox="0 0 560 140">
368
+ <!-- 中线 -->
369
+ <line x1="280" y1="10" x2="280" y2="130" class="s-bds" stroke-width="1"/>
370
+ <!-- 每行:左条(s3,从中间向左)+ 右条(acc,从中间向右) -->
371
+ <text x="270" y="30" text-anchor="end" class="f-txt2" font-size="12">找数时长</text>
372
+ <rect x="120" y="18" width="150" height="15" rx="7.5" class="f-s3"/>
373
+ <rect x="280" y="18" width="60" height="15" rx="7.5" class="f-acc"/>
374
+ <text x="112" y="30" text-anchor="end" class="f-txt" font-size="11" font-weight="600">2 天</text>
375
+ <text x="348" y="30" class="f-acc" font-size="11" font-weight="600">2 分钟</text>
376
+
377
+ <text x="270" y="68" text-anchor="end" class="f-txt2" font-size="12">口径一致性</text>
378
+ <rect x="190" y="56" width="80" height="15" rx="7.5" class="f-s3"/>
379
+ <rect x="280" y="56" width="190" height="15" rx="7.5" class="f-acc"/>
380
+ <text x="182" y="68" text-anchor="end" class="f-txt" font-size="11" font-weight="600">各说各话</text>
381
+ <text x="478" y="68" class="f-acc" font-size="11" font-weight="600">统一定义</text>
382
+
383
+ <text x="270" y="106" text-anchor="end" class="f-txt2" font-size="12">Agent 可用性</text>
384
+ <rect x="240" y="94" width="30" height="15" rx="7.5" class="f-s3"/>
385
+ <rect x="280" y="94" width="170" height="15" rx="7.5" class="f-acc"/>
386
+ <text x="232" y="106" text-anchor="end" class="f-txt" font-size="11" font-weight="600">不可用</text>
387
+ <text x="458" y="106" class="f-acc" font-size="11" font-weight="600">原生可消费</text>
388
+ </svg>
389
+ </div>
390
+ ```
391
+
392
+ ---
393
+
394
+ ---
395
+
396
+ ## 29. 多段环形(多系列占比,≤4 段)`data-chart="multidonut"`
397
+
398
+ ```html
399
+ <div class="fig" style="text-align:center">
400
+ <div class="fig__cap">数据消费构成(四类)</div>
401
+ <svg class="chart" data-chart="multidonut" viewBox="0 0 160 160" style="width:170px;margin-inline:auto">
402
+ <!-- 周长 2π×60≈377;段:45%→169.6 / 25%→94.2 / 18%→67.9 / 12%→45.2
403
+ 每段 dashoffset 依次累减;缝隙用 2px 背景色描边 -->
404
+ <circle cx="80" cy="80" r="60" class="f-none s-bds" stroke-width="18"/>
405
+ <circle cx="80" cy="80" r="60" class="f-none s-acc" stroke-width="18"
406
+ stroke-dasharray="169.6 207.4" transform="rotate(-90 80 80)"/>
407
+ <circle cx="80" cy="80" r="60" class="f-none" stroke="var(--accent)" stroke-opacity=".55" stroke-width="18"
408
+ stroke-dasharray="94.2 282.8" stroke-dashoffset="-169.6" transform="rotate(-90 80 80)"/>
409
+ <circle cx="80" cy="80" r="60" class="f-none s-txt3" stroke-width="18"
410
+ stroke-dasharray="67.9 309.1" stroke-dashoffset="-263.8" transform="rotate(-90 80 80)"/>
411
+ <circle cx="80" cy="80" r="60" class="f-none s-bds" stroke-width="18"
412
+ stroke-dasharray="45.2 331.8" stroke-dashoffset="-331.7" transform="rotate(-90 80 80)"/>
413
+ <text x="80" y="78" text-anchor="middle" class="f-txt" font-size="22" font-weight="700">4 类</text>
414
+ <text x="80" y="98" text-anchor="middle" class="f-txt3" font-size="11">消费方式</text>
415
+ </svg>
416
+ <div class="row row-wrap" style="justify-content:center;gap:var(--sp-3);margin-top:var(--sp-4)">
417
+ <span class="chip chip--accent">服务层 45%</span>
418
+ <span class="chip">直连 25%</span>
419
+ <span class="chip">导出 18%</span>
420
+ <span class="chip">其他 12%</span>
421
+ </div>
422
+ </div>
423
+ ```
424
+
425
+ > 段色层级:主段 `--accent` 实色 → 次段 accent 55% 透明 → 再次 `--text-3` → 最次 `--border-soft`。**同族明度递减,不引入第二色相。**
426
+
427
+ ---
428
+
429
+ ---
430
+
431
+ ## 29b. 多系列图表 · 数据色板(9 套风格各有 c1–c5)
432
+
433
+ 多系列图表(多段环形、分组柱、多折线、散点分组)统一用 `f-c1~c5` / `s-c1~c5`:
434
+ **9 套风格各有自己的 5 色板**(单源 `styleDataColors` / `styleDataColorsDark`,随主题自动切换):同一份代码在任何风格下都能出可区分的彩色系列,而结构色仍恒为中性 + 单一强调色。
435
+
436
+ ```html
437
+ <div class="fig" style="text-align:center">
438
+ <div class="fig__cap">各域数据消费占比(四系列)</div>
439
+ <svg class="chart" data-chart="multidonut" viewBox="0 0 160 160" style="width:170px;margin-inline:auto">
440
+ <circle cx="80" cy="80" r="60" class="f-none s-bds" stroke-width="18"/>
441
+ <!-- 周长≈377;38%→143.2 / 27%→101.8 / 21%→79.2 / 14%→52.8 -->
442
+ <circle cx="80" cy="80" r="60" class="f-none s-c1" stroke-width="18"
443
+ stroke-dasharray="143.2 233.8" transform="rotate(-90 80 80)"/>
444
+ <circle cx="80" cy="80" r="60" class="f-none s-c2" stroke-width="18"
445
+ stroke-dasharray="101.8 275.2" stroke-dashoffset="-143.2" transform="rotate(-90 80 80)"/>
446
+ <circle cx="80" cy="80" r="60" class="f-none s-c3" stroke-width="18"
447
+ stroke-dasharray="79.2 297.8" stroke-dashoffset="-245" transform="rotate(-90 80 80)"/>
448
+ <circle cx="80" cy="80" r="60" class="f-none s-c4" stroke-width="18"
449
+ stroke-dasharray="52.8 324.2" stroke-dashoffset="-324.2" transform="rotate(-90 80 80)"/>
450
+ <text x="80" y="78" text-anchor="middle" class="f-txt" font-size="22" font-weight="700">4 域</text>
451
+ <text x="80" y="98" text-anchor="middle" class="f-txt3" font-size="11">消费占比</text>
452
+ </svg>
453
+ <!-- 图例:小色点 + 文字(色点用 f-c*,文字保持中性) -->
454
+ <div class="row row-wrap" style="justify-content:center;gap:var(--sp-4);margin-top:var(--sp-4)">
455
+ <span class="row" style="gap:6px"><svg width="10" height="10" viewBox="0 0 10 10"><rect width="10" height="10" rx="3" class="f-c1"/></svg><span class="t-sm">供应链 38%</span></span>
456
+ <span class="row" style="gap:6px"><svg width="10" height="10" viewBox="0 0 10 10"><rect width="10" height="10" rx="3" class="f-c2"/></svg><span class="t-sm">财务 27%</span></span>
457
+ <span class="row" style="gap:6px"><svg width="10" height="10" viewBox="0 0 10 10"><rect width="10" height="10" rx="3" class="f-c3"/></svg><span class="t-sm">研发 21%</span></span>
458
+ <span class="row" style="gap:6px"><svg width="10" height="10" viewBox="0 0 10 10"><rect width="10" height="10" rx="3" class="f-c4"/></svg><span class="t-sm">营销 14%</span></span>
459
+ </div>
460
+ </div>
461
+ ```
462
+
463
+ **彩色使用边界(9 套风格同一条纪律)**:
464
+ - 彩色**只**在数据系列、图例色点、小段标签;标题/正文/边框/按钮/大底色保持中性 + 单一 `--accent`。
465
+ - 同屏彩色系列 ≤ 5,超出合并为「其他」(用 `f-c5`)。
466
+ - 多折线同理:每条线 `s-c1` / `s-c2` / `s-c3`,数据点同色。
467
+
468
+ ---
469
+
470
+ ---
471
+
472
+ ## 30. 大数字 + 迷你趋势线(KPI 卡)
473
+
474
+ ```html
475
+ <div class="metric">
476
+ <div class="metric__k">可信数据消费率</div>
477
+ <div class="metric__v t-metric">45<small>%</small></div>
478
+ <svg viewBox="0 0 120 28" style="width:100%;height:26px;margin-top:6px">
479
+ <path data-draw d="M2,22 L22,18 L42,20 L62,12 L82,14 L102,7 L118,4" class="f-none s-acc"
480
+ stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
481
+ <circle cx="118" cy="4" r="2.6" class="f-acc"/>
482
+ </svg>
483
+ <div class="metric__n">近四季度持续上行</div>
484
+ </div>
485
+ ```
486
+
487
+ ---
488
+
489
+ ---
490
+
491
+ ## 31. 进度条列表(多项目完成度)
492
+
493
+ ```html
494
+ <div class="card">
495
+ <h3 class="t-h3" style="margin-bottom:var(--sp-4)">各域治理进度</h3>
496
+ <div class="stack gap-4">
497
+ <div>
498
+ <div class="row" style="justify-content:space-between;margin-bottom:5px">
499
+ <span class="t-sm" style="color:var(--text)">供应链</span>
500
+ <span class="t-sm" style="color:var(--text-3)">76%</span>
501
+ </div>
502
+ <div style="height:8px;border-radius:999px;background:var(--surface-2);overflow:hidden">
503
+ <div style="width:76%;height:100%;border-radius:999px;background:var(--accent)"></div>
504
+ </div>
505
+ </div>
506
+ </div>
507
+ </div>
508
+ ```
509
+
510
+ ---
511
+
512
+ # 第二部分 · 图表尺寸与轻量交互
513
+
514
+ > 尺寸下限(低于即不合格)与进入视口的克制动效;阈值唯一事实源 `layout-constants.json` `charts.minSize`。
515
+
516
+ ---
517
+
518
+ ## 35. 图表尺寸下限 + 轻量交互
519
+
520
+ ### 尺寸下限(不要再小;校验脚本按 data-chart 类型核对)
521
+
522
+ > **阈值唯一事实源 = `scripts/layout-constants.json` 的 `charts.minSize`**(下表为其可读版;改阈值只改 JSON)。
523
+ > `pxWidthMin` = 内联 `width:NNNpx` 硬下限(FAIL);`vbHeightMin` = 通宽图 `viewBox` 高度建议下限(WARN)。
524
+
525
+ | data-chart | 图表 | 最小尺寸 | 类型键 |
526
+ |-----------|------|---------|--------|
527
+ | donut / multidonut | 环形 | 显示直径 140px | `pxWidthMin:140` |
528
+ | gauge | 仪表盘 / 进度环 | 显示直径 180px | `pxWidthMin:180` |
529
+ | radar | 雷达图(≤6 维) | 显示直径 220px | `pxWidthMin:220` |
530
+ | rose | 玫瑰图(≤6 维) | 显示直径 180px | `pxWidthMin:180` |
531
+ | bar / stack | 柱状 / 堆叠柱 | viewBox 高 160 | `vbHeightMin:160` |
532
+ | line / dualline / area | 折线 / 双折线 / 面积 | viewBox 高 160 | `vbHeightMin:160` |
533
+ | waterfall | 瀑布 | viewBox 高 170 | `vbHeightMin:170` |
534
+ | scatter / bubble | 散点 / 气泡 | viewBox 高 180 | `vbHeightMin:180` |
535
+ | funnel | 漏斗(≤5 层) | viewBox 高 160 | `vbHeightMin:160` |
536
+ | treemap | 矩形树图 | viewBox 高 170 | `vbHeightMin:170` |
537
+ | marimekko | 马赛克图(变宽堆叠) | viewBox 高 160 | `vbHeightMin:160` |
538
+ | dumbbell | 哑铃图(前后对比) | viewBox 高 160 | `vbHeightMin:160` |
539
+ | lollipop | 棒棒糖图(排名) | viewBox 高 140 | `vbHeightMin:140` |
540
+ | bulletchart | 子弹图(目标 vs 实际) | viewBox 高 140 | `vbHeightMin:140` |
541
+ | gantt | 甘特 | viewBox 高 130 | `vbHeightMin:130` |
542
+ | dotplot | 点图(分布) | viewBox 高 120 | `vbHeightMin:120` |
543
+ | hbar / vsbar | 横向条形 | viewBox 高 100 | `vbHeightMin:100` |
544
+ | progress | 进度条组 | viewBox 高 100 | `vbHeightMin:100` |
545
+ | stackline | 100% 堆叠条 | viewBox 高 40 | `vbHeightMin:40` |
546
+ | sparkline | 迷你趋势线(KPI 内嵌) | viewBox 高 20 | `vbHeightMin:20` |
547
+ | sankey | 桑基 / 流向图 | viewBox 高 200 | `vbHeightMin:200` |
548
+ | slope | 斜率图(两期对比) | viewBox 高 180 | `vbHeightMin:180` |
549
+ | waffle | 华夫图(构成占比点阵) | viewBox 高 160 | `vbHeightMin:160` |
550
+ | boxplot | 箱线图(多组分布) | viewBox 高 180 | `vbHeightMin:180` |
551
+ | pareto | 帕累托(柱+累计线) | viewBox 高 180 | `vbHeightMin:180` |
552
+ | radialbar | 径向条形(多环进度) | 显示直径 200px | `pxWidthMin:200` |
553
+ | streamgraph | 流图 / 堆叠面积 | viewBox 高 160 | `vbHeightMin:160` |
554
+ | candlestick | K 线(区间波动) | viewBox 高 180 | `vbHeightMin:180` |
555
+ | (无 data-chart) | 主图(架构/流程 SVG) | 宽 ≥ 版心 55% | — |
556
+
557
+ **原则:宁可少放一张图,也不把图缩成一团。** 新图表类型必须在 `charts.types` 登记并配 `minSize`,否则校验器会提示「未登记」。
558
+
559
+ ### 轻量交互(进入视口触发,克制不炫技)
560
+
561
+ **① 柱状生长 / 元素淡入(CSS,配合 JS 给容器加 `.in`)**
562
+
563
+ ```css
564
+ [data-anim]{transform-box:fill-box}
565
+ .chart rect[data-anim="grow"]{transform:scaleY(0);transform-origin:center bottom;
566
+ transition:transform .7s cubic-bezier(.05,.7,.1,1)}
567
+ .chart.in rect[data-anim="grow"]{transform:scaleY(1)}
568
+ .chart [data-anim="fade"]{opacity:0;transition:opacity .6s ease .18s}
569
+ .chart.in [data-anim="fade"]{opacity:1}
570
+ ```
571
+
572
+ ```html
573
+ <svg class="chart" data-chart="bar" viewBox="0 0 400 210">
574
+ <rect data-anim="grow" x="52" y="131" width="58" height="39" rx="6" class="f-s3"/>
575
+ <rect data-anim="grow" x="146" y="92" width="58" height="78" rx="6" class="f-s3"/>
576
+ <text data-anim="fade" x="81" y="193" text-anchor="middle" class="f-txt3" font-size="11">Q3</text>
577
+ </svg>
578
+ ```
579
+
580
+ > **横向生长**(甘特横道、横条):svg 加 `chart--x` 即可,模板已内置 `.chart--x` 规则(`scaleX` + 左原点)。
581
+
582
+ **② 折线描边(`data-draw`)** —— 折线 path 上加 `data-draw`,JS 用 `getTotalLength()` 做 dashoffset 描边。
583
+
584
+ **③ 环形扫入(`data-sweep`)** —— 环形 accent 弧加 `data-sweep data-circ="339" data-p="0.31"`,JS 从 0 扫到 31%。
585
+
586
+ **④ 数字 count-up(`data-count`)** —— `<text data-count="31" data-suffix="%">0%</text>`,进入视口从 0 数到 31%。
587
+
588
+ **⑤ 悬浮提示(原生 `<title>`)** —— 图形内嵌 `<title>2026Q4 · 60%</title>`,鼠标悬停出提示,零成本。
589
+
590
+ ### 动效触发 JS(已内置公共 UI 脚本,全页通用)
591
+
592
+ ```js
593
+ (function(){
594
+ function countUp(el){var t=parseFloat(el.dataset.count),s=el.dataset.suffix||'',
595
+ d=(el.dataset.count.split('.')[1]||'').length,t0=null;
596
+ (function st(ts){if(!t0)t0=ts;var p=Math.min(1,(ts-t0)/900);
597
+ el.textContent=(t*p).toFixed(d)+s;if(p<1)requestAnimationFrame(st)})(performance.now());}
598
+ function draw(p){var L=p.getTotalLength();p.style.strokeDasharray=L;p.style.strokeDashoffset=L;
599
+ requestAnimationFrame(function(){p.style.transition='stroke-dashoffset 1s cubic-bezier(.05,.7,.1,1)';
600
+ p.style.strokeDashoffset=0;});}
601
+ function sweep(c){var L=+c.dataset.circ,p=+c.dataset.p;
602
+ c.style.strokeDasharray=L;c.style.strokeDashoffset=L;
603
+ requestAnimationFrame(function(){c.style.transition='stroke-dashoffset 1s cubic-bezier(.05,.7,.1,1)';
604
+ c.style.strokeDashoffset=L*(1-p);});}
605
+ if(!('IntersectionObserver' in window))return;
606
+ var io=new IntersectionObserver(function(es){es.forEach(function(e){
607
+ if(!e.isIntersecting)return;var g=e.target;io.unobserve(g);g.classList.add('in');
608
+ g.querySelectorAll('[data-count]').forEach(countUp);
609
+ g.querySelectorAll('[data-draw]').forEach(draw);
610
+ g.querySelectorAll('[data-sweep]').forEach(sweep);})},{threshold:.3});
611
+ document.querySelectorAll('.chart,[data-chart]').forEach(function(el){io.observe(el)});
612
+ })();
613
+ ```
614
+
615
+ > 尊重 `prefers-reduced-motion`:系统要求减动效时,直接显示终态(给 `[data-anim]` 兜底 `transition:none`)。
616
+
617
+ ---
618
+
619
+ # 第三部分 · 扩展图表
620
+
621
+ > 与第一部分同族:纯 SVG + `data-chart` 标记 + 语义类配色;新增类型须在 `charts.types` 登记并配 `minSize`。
622
+
623
+ ---
624
+