跳到正文
misoto22 design

数据

BulletChart

一个度量、它的目标,以及说明这个数好不好的几条背景带。

什么时候用它

一页要盯十个数的状态页。Stephen Few 设计它就是为了替掉仪表盘上的表盘——那种东西花掉整张卡片,只把一个数说得很差。

示例

default

Quarterly targetsBar is the measure, rule is the target
Availability96 / 99
Support CSAT84 / 80
Onboarding completion61 / 75
Docs coverage43 / 70
Quarterly targets
nameValueTargetRange bounds
Availability969950, 80
Support CSAT848050, 80
Onboarding completion617550, 80
Docs coverage437050, 80

per measure scales

Platform health
Uptime30 days99.4 / 99.9
98100
p95 latencyms, lower is better310 / 250
0600
Error budget left%38 / 50
0100
Open incidents3 / 0
08
Platform health
nameValueTargetRange bounds
Uptime99.499.999, 99.5
p95 latency310250200, 400
Error budget left385025, 60
Open incidents301, 4

说明

一个度量、它的目标值,以及说明这个数到底好不好的区间带——每一个被追踪的东西占密密的一行。

Stephen Few 设计它,就是为了取代仪表盘上那个表盘,而这个理由至今站得住:一个速度表要花掉整整一张卡片,才把一个数字表达得很糟;子弹图则在一行文字的高度里,把同一个数字、它的目标值,以及围绕它的定性背景一并说清楚。十个叠起来,就是一页读者一眼扫得完的状态页。

它不做的事,是呈现随时间的变化。子弹图只是一个瞬间,target 是它唯一带着的对照;当问题是「我们是怎么走到这一步的」,它要的是 <LineChart>;当几个度量需要互相比较、而不是各自跟自己的目标比时,<BarList> 会替你排出名次,而这里不会。

真正要当心的是那些区间带。它们是一种判断——是某个人决定了 80 算「好」——却和测量值用同一种笔墨画出来,读者根本分不清哪个是达成共识的阈值、哪个是谁随手敲进去的数。它们还会压缩信息:一个接近刻度顶端的值,无论是压线过关一分还是甩开三十分,都落在同一条带里。区间带回答的是「这个能不能接受」,永远不是「差了多少」。

刻意不带渲染引擎——这是整套里唯一一张什么都不用算的图。每一行都只是一把线性刻度,没有坐标轴、没有刻度线、也没有共享的绘图区,所以它是用 HTML 排出来的:区间带和条形都是内联轴方向上的偏移量,这意味着整张图在从右往左的文档里能正确镜像,而一张画在用户坐标系里的 SVG 做不到。

属性

BulletChart props
属性类型默认值说明
data必填BulletMeasure[]一个度量一条。顺序就是阅读顺序;这里不会替你排序。
title必填string这张图在讲什么,用一句读者能据此行动的话。必填,而且即使不显示出来也会播报给读屏软件。
classNamestring最后合并到 figure 上,所以调用处可以决定它的尺寸和间距。
descriptionReactNode标题下面的一行——单位、时间窗口、需要提醒的地方。
domain[number, number]各个度量默认沿用的刻度,写成 `[min, max]`。
emptyChartEmptyProps图表没东西可画时显示什么。
formatValue(value: number) => stringdefaultTick格式化这张图印出来的每一个数字。
hideDataTablebooleanfalse去掉隐藏的表格视图。只有当页面自己已经把数据印出来时,这才是对的。
rangesnumber[]各个度量默认沿用的区间带,写成一串递增的上界。 只有当这些度量共用一把刻度时,共享区间带才有意义。刻度不同的时候——一个延迟和一个转化率并排——就把 `ranges` 和 `domain` 分别写到每个度量上。
showScalebooleanfalse把刻度的两端印在每条轨道下面。
showTitleboolean把标题印在各行上方,而不是藏起来。

无障碍

  • 纯 HTML + 逻辑属性写成,不需要渲染引擎,可服务端渲染,在从右到左的文档里也是对的。recharts 不在场时照样能用。
  • 几条带子是一个**判断**,却和被测量的那个数用同一种墨画出来,所以页面必须交代它们从哪来。只是把量程三等分的带子会让图看起来「已经被评估过」,其实并没有。
  • 它呈现的是一个瞬间,除了 target 之外不携带任何比较。「我们是怎么走到这儿的」要的是 LineChart。
  • 共用的带子只有在几个度量共用同一把尺时才有意义——延迟和转化率并排时,要给每个度量各自的 ranges 和 domain。