首页
/ Claude Code dataviz 技能交互设计指南:Tooltip 悬停层与过滤器/时间范围的实现规范(system_prompts_leaks)

Claude Code dataviz 技能交互设计指南:Tooltip 悬停层与过滤器/时间范围的实现规范(system_prompts_leaks)

2026-09-04 10:59:18作者:昌雅子Ethen

本文基于 interaction.md,系统讲解 Claude Code dataviz 技能中「交互层」的完整设计规范:为什么 HTML 图表的悬停层(crosshair、tooltip)是默认交付物而非可选升级,八条 tooltip/hover 规则(命中区域、系列标识、XSS 安全的 DOM 写入等),以及监控面板过滤器/时间范围控件的四条组合规则与日期选择器规格。读完后你可以直接照此规范实现一套「数值永不被遮挡、键盘与鼠标等价、过滤器统一作用域」的图表交互层,并理解它与仓库中配色校验脚本、标记规格等文档的衔接关系。

1. 交互层的定位:默认交付,不是升级项

interaction.md 开篇即给出总纲:HTML 图表默认是可交互的——悬停层是交付物(deliverable)的一部分,而不是锦上添花。省略它才是例外(仅限裸 stat tile 这类无绘图区的形态),绝非常态。技能主文件 SKILL.md 的七步流程中,第 5 步明确要求「默认加悬停层」:

线/面积图配 crosshair + tooltip,柱/点/热格配逐标记(per-mark)悬停 tooltip;唯一可以跳过的形态是没有绘图的裸 stat tile。命中区域要比标记本身大;过滤器放在图表上方的一行里。

这条规则与仓库中 anti-patterns.md 的反模式清单互为印证:「tooltip 成为读取数值的唯一途径」被明确列为错误做法,「命中区域小到必须正中 8px 散点」同样在列。换句话说,交互层的设计目标是可访问性与可用性,而不是炫技。

2. Tooltips 与悬停:八条规则逐条解析

核心原则一句话:Tooltips enhance, they never gate(增强,永不设障)。tooltip 显示的每一个值,都必须能通过直接标签或表格视图在不用 tooltip 的情况下取到;键盘 focus 下显示的信息必须与 hover 完全一致。这是整节规则的地基。

2.1 十字线负责「找 X」

  • 一条垂直发丝线跟随指针,并吸附到最近的数据位置
  • 设计意图:读者瞄准的是「日期」,而不是一根 2px 的线。十字线把「对齐某个 X」的精度问题从用户手中拿走。
  • 适用范围:折线图、面积图、柱状图这类「X 轴有连续/离散位置语义」的图表。

2.2 柱与热格:标记本身就是命中目标

  • 没有十字线。每根柱子、每个堆叠分段、每个散点、每个热格(heat-cell)各自携带 pointermove / focus 事件触发的 tooltip,内容包含类别名 + 数值
  • 被悬停的标记要有可见反馈(轻微提亮或描边),让读者确认「它响应了」。
  • 这条规则与 marks-and-anatomy.md 的「surface gap / surface ring」体系直接相关:标记之间 2px 的表面色间隙、重叠标记上的 2px 表面色描边,本身就是命中目标的一部分,不只是间距手段。

2.3 一个 tooltip,覆盖该 X 的全部系列

  • tooltip 的读数列出该 X 位置的所有系列,指针不必精确落在某条线或某个填充上才能取数。
  • 这消除了「多系列折线图上指针必须贴线」的经典可用性问题,同时与「values 永不设障」原则一致。

2.4 标签是不可信数据:一律用 textContent

这是一条安全规则,值得单独强调:

  • 系列名和类别名常来自 CSV 表头、工具输出或 API 响应——属于外部不可信输入。
  • 插入 tooltip / 图例 / 表格 DOM 时,必须使用 textContentcreateTextNode严禁 innerHTML 字符串拼接,否则等于把数据源变成本地 XSS 注入点。
  • 这条规则把「数据可视化」与「前端安全实践」在同一个文档里闭环了。

2.5 数值在前,标签在后(层级反转)

  • tooltip 内部的层级与图例相反:数值是 Strong、高对比度的主角元素,系列名退居次要。
  • 原因是阅读任务不同:在图例里,读者已有数值、需要找「这是哪条线」;在 tooltip 里,读者已有系列、需要的是数字。同一套视觉组件在不同语境下做层级反转,而不是照抄。

2.6 用「线」做系列键,不用「方块」

  • tooltip 行内标识系列,用一小段系列色短线(stroke),而不是实心色块。
  • 理由:在 tooltip 这种高密度排布下,实心方块是「数据分量的墨水」在做标签的活,视觉重量失衡。
  • 注意边界:图例仍然镜像标记形态(柱/面积用矩形 rect,折线用 line)——图例要能回答「这个颜色对应图上什么形状的标记」,而 tooltip 不需要。

2.7 命中区域必须大于标记本身

这是原文档中量化最明确的一条:

  • 标记的 hover/focus 热区至少包含其 2px 表面间隙并继续外扩,绝不能只有绘制出来的像素。
  • 一个 8px 的散点是「没人能可靠命中的针尖」:每个点必须给不小于 24px 的透明命中区
  • 对密集散点图,进一步上最近点 / Voronoi 层:指针只要「最接近」即可,不必正中。
  • 原文补充:折线/柱状图的 X 方向已经由十字线代劳了这件事,散点和气泡图需要逐点版本的等价方案。

2.8 挤不进标记的值,住进 tooltip

  • 当直接标签放不下(对应 marks-and-anatomy.md 中「先测量、放不下就外移或降级」的规则),该柱的热区在 hover/focus 时承载数值。
  • tooltip 是这个值的「溢出之家」,而表格视图保证不悬停也能取到——这再次回到「enhance, never gate」的地基。

3. 过滤器与时间范围:标准 UI + 组合规则

原文档的定位声明很关键:过滤器是标准 UI,不是图表标记——用普通 HTML 表单控件实现,样式对齐图表 chrome 即可。dataviz 技能只在此之上追加组合规则(composition rules)。

四条组合规则:

  1. 一行,位于所有图表上方。 过滤器放在一个左对齐的单行里,位于其所作用的内容上方——永远不放进图表卡片内部,也不允许逐图各设一套。如果某个图表需要独立时间范围,那它是另一块仪表盘。
  2. 日期范围优先。 它是读者伸手最频繁的过滤器:先给预设(今天、最近 7 / 30 / 90 天),再给自定义范围。
  3. 过滤器作用其下的一切。 其下方的每个图表、stat tile、表格都基于同一片数据切片重渲染,保证所有数字互相一致。
  4. Refetch 时保持画面(keep the frame)。 数据重载期间,图表保持上一次渲染结果并降低不透明度——无骨架屏、无布局跳动、无闪烁

日期选择器的实现规格(原文末尾段落 + palette.md 的 Filter controls 章节给出的参考规格):

  • 预设以行列表呈现(没有人会跟日历网格搏斗只为选「最近 30 天」);
  • 选中态用 16px 粗体对勾标记;
  • hover 用 ghost wash(幽灵底色),永远不与选中态竞争注意力;
  • 自定义范围收起在页脚的一条发丝线之后(tucked behind a hairline in the footer);
  • 维度过滤器用标准 combobox。

SKILL.md 的「接入设计系统」参数表也印证了这一分工:设计系统只需提供 Filter controls(日期范围与维度控件),而行为规格(behavioral spec)就定义在 interaction.md 中——即本文依据的文档。

4. 与仓库其余部分的衔接:可校验性与反模式对照

4.1 交互层与配色校验脚本是正交的两层

仓库的可执行校验器 validate_palette.js 计算的是颜色可测的五项检查(OKLCH 明度带、色度下限、CVD 分离度、正常视觉下限、表面对比度,基于 Machado–Oliveira–Fernandes 2009 色盲模拟矩阵),它不校验交互行为。从源码结构看,CLI 用法为:

node scripts/validate_palette.js "#2a78d6,#eb6834,#1baf7a,..." --mode light
# 深色表面复跑:
node scripts/validate_palette.js "..." --mode dark --surface "#1a1a19"
# 全对模式(散点/气泡/分级填充图):
node scripts/validate_palette.js "..." --pairs all
# 有序单色 ramp:
node scripts/validate_palette.js "#86b6ef,#5598e7,#256abf,#104281" --ordinal

因此完整的质检分工是:脚本管颜色的 pass/fail,interaction.md 管交互行为,anti-patterns.md 管最终人工目检(SKILL.md 第 7 步要求渲染出来实际看一眼)。

4.2 反模式清单中的交互条目

anti-patterns.md 的「Interaction & accessibility」一节列出了五条与本文规则一一对应的失败模式,可作为交付前的核对表:

反模式 正确做法(对应本文规则)
tooltip 成为读数的唯一途径 enhance, never gate;表格视图兜底;键盘 focus 与 hover 等价
针尖级命中目标(8px 散点必须正中) 热区含 2px 间隙、约 24px 下限;密集散点用最近点/Voronoi 层
逐图过滤器 / 过滤器嵌在图表卡片内 上方一行,作用其下一切
refetch 时骨架屏闪烁 保持上一帧、降不透明度,无布局跳动
无表格视图 / 连续刻度仅靠颜色 每个图表都有 WCAG 友好的表格视图孪生体

4.3 组件清单中的位置

components.md 的组件分层里,Tooltip 属于 Tier 0 基础组件(与图例、坐标轴、数据标签并列,挂在承载响应式尺寸、标题/说明与表格视图切换的 <figure> 容器上);Chart filters / time range 属于 Tier 2 套件(与空状态、火花线、热力图同层)。这解释了为什么过滤器虽然用标准表单控件实现,却仍由本技能给出组合规则——它是仪表盘级(composition)而非单个图表级的决策。

5. 落地检查清单

综合上述规则,实现一个图表交互层前可逐项核对:

  1. 悬停层是否默认存在(仅裸 stat tile 可省)?
  2. 折线/面积图是否有吸附式十字线?柱/点/热格是否为逐标记 tooltip?
  3. 一个 X 的 tooltip 是否列出全部系列?数值是否为主、系列名为辅?
  4. 系列名/类别名是否全部经 textContent/createTextNode 写入?
  5. 8px 级散点是否有 ≥24px 透明命中区?密集散点是否上了 Voronoi/最近点层?
  6. 被挤出的标签值是否落在 tooltip 且保留在表格视图?
  7. 键盘 focus 下的信息与 hover 是否完全一致?
  8. 过滤器是否单行、置顶、统一作用域?日期预设(今天/7/30/90 天)是否先于自定义范围?
  9. refetch 是否「保持画面」:旧帧降透明度,无骨架、无跳动?
  10. 日期选择器:预设行 + 16px 粗体对勾 + ghost wash hover + 页脚发丝线下收的自定义范围?

这套规范的来源边界说明:文中所有交互规则、数值(24px、16px、2px 间隙、7/30/90 天预设)均出自 interaction.md 原文及其直接引用的 palette.mdmarks-and-anatomy.mdanti-patterns.mdcomponents.md;关于校验器行为与命令行参数的描述基于对 validate_palette.js 源码的阅读(其 CLI 与浏览器 data-palette 自动运行两个入口均在文件中实现)。这些文档属于 Claude Code 的 dataviz 技能(品牌中立的方法 + 参考配色实例),适用于任何按此方法产出 HTML/SVG 图表的场景。

登录后查看全文
热门项目推荐
相关项目推荐