- 数据可视化
- 前端
【免费下载链接】F2
📱📈An elegant, interactive and flexible charting library for mobile.
导读
PointGuide 是 F2 移动端图表库内置的标注(Guide)组件之一,用于在图表画布上以圆形标记的形式标注数据点,例如标注折线图上的最大值、最小值、中位值或特定百分比位置。本文将以 point-guide.zh.md 为核心,结合仓库源码与测试用例,系统讲解 PointGuide 的用法、全部 Props、records 特殊值语义、style 对象/函数两种形态、动画配置,以及面向分组柱状图的 precise 精确定位能力,帮助你在实际项目中快速、准确地为图表添加数据标注。
PointGuide 在 F2 中的定位与组件结构
在 F2 的组件体系中,PointGuide 属于 guide 组件族,与 TextGuide、LineGuide、ArcGuide、RectGuide、ImageGuide、TagGuide、LottieGuide、PolylineGuide 并列,统一由withGuide高阶组件包装对应视图而成。相关注册与导出位于 packages/f2/src/components/guide/index.tsx,其中:
const PointGuide = withGuide(PointGuideView);withGuide(packages/f2/src/components/guide/withGuide.tsx)负责所有 Guide 组件的通用逻辑:解析records为画布坐标、处理precise精确定位、执行style/animation函数形态的求值,以及统一处理visible与onClick。而PointGuideView(packages/f2/src/components/guide/views/Point.tsx)则专司把解析后的坐标渲染为一个圆点(circle图形),并把主题默认样式与传入style深合并。
这种"通用逻辑 + 视图渲染"的分层结构意味着:所有 Guide 在records解析规则、特殊值语义、precise 定位上的行为是一致的,本文讲解的 PointGuide 知识同样适用于其他 Guide 组件。
快速上手:最小可用示例
PointGuide 的典型用法是把图表数据逐条映射为标注:在<Chart>内、与图形组件(如<Line>)并列声明<PointGuide>,通过records指定标注位置,通过style指定圆点外观。
import { Canvas, Chart, Line, PointGuide } from '@antv/f2'; const data = [ { genre: 'Sports', sold: 275 }, { genre: 'Strategy', sold: 115 }, { genre: 'Action', sold: 120 }, { genre: 'Shooter', sold: 350 }, { genre: 'Other', sold: 150 }, ]; <Canvas context={context}> <Chart data={data}> <Line x="genre" y="sold" /> {data.map((item) => ( <PointGuide records={[item]} offsetX={0} offsetY={0} style={{ fill: '#f00' }} /> ))} </Chart> </Canvas>要点说明:
records接收一个数组,数组中的每个元素是一条数据记录(RecordItem = Record<string, string | number>),组件会把它翻译为画布坐标后取第一个点渲染圆点。所以"想标几个点就放几条记录"。Line x="genre" y="sold"声明了 x、y 字段映射,PointGuide 会复用图表的 x/y 度量(Scale)来做坐标换算。- 圆点的默认外观由主题控制,详见下文"默认样式值"。
TypeScript 类型定义与全部 Props
PointGuide 的完整类型定义(摘自 point-guide.zh.md):
interface PointGuideProps { /** 标注位置的数据项或比例值 */ records: RecordItem[]; /** x 轴偏移量,支持数字或带单位的字符串(如 '10px')*/ offsetX?: number | string; /** y 轴偏移量,支持数字或带单位的字符串(如 '10px')*/ offsetY?: number | string; /** 圆形样式,支持对象或函数形式 */ style?: Partial<CircleStyleProps> | ((points: Point[], chart: Chart) => Partial<CircleStyleProps>); /** 动画配置,详见 [动画文档](https://link.gitcode.com/i/6b1d3ce1a38bbcb0b4b9ec286e2e3e7a) */ animation?: AnimationProps | ((points: Point[], chart: Chart) => AnimationProps); /** 点击事件回调 */ onClick?: (ev: Event) => void; /** 是否显示,默认 true */ visible?: boolean; /** 是否精确定位(用于分组柱状图中精确定位到每个子柱子) */ precise?: boolean; } /** 画布坐标点 */ interface Point { x: number; y: number; } /** 数据记录 */ type RecordItem = Record<string, string | number>;全部 Props 一览:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
records | Array<RecordItem> | - | 标注位置的数据项或比例值,支持特殊值(见下文) |
offsetX | number \| string | 0 | x 轴偏移量 |
offsetY | number \| string | 0 | y 轴偏移量 |
style | CircleStyleProps \| Function | 见下方 | 圆形样式,支持对象或函数形式 |
animation | AnimationProps \| Function | - | 动画配置,详见 动画文档 |
onClick | (ev: Event) => void | - | 点击事件回调 |
visible | boolean | true | 是否显示标注 |
precise | boolean | - | 是否精确定位(用于分组柱状图中精确定位到每个子柱子) |
默认样式值
PointGuide 圆点的默认样式定义在 F2 主题的guide.point节点中(见 packages/f2/src/theme.ts):
{ fill: '#fff', r: 3, lineWidth: 2, stroke: '#1890ff', }即:白色填充、半径为 3、描边宽度 2、主题蓝(#1890ff)描边。由于视图在渲染时使用deepMix({ ...theme.point }, props)深合并,因此你传入的style会覆盖这些默认值中的对应字段,未声明的字段继续沿用主题默认。
此外主题中guide.point还带有offsetX: 0、offsetY: 0,这与文档表格中 offset 的默认值一致。
records 特殊值:无需手算坐标的定位语法
records中的字段值不仅可以是真实数据,还可以使用特殊字符串来表达"比例位置",组件会将其归一化为 0~1 的比例值再经度量换算,无需你手动计算具体数值。完整取值表如下:
| 值 | 含义 | 对应位置 |
|---|---|---|
'min' | 最小值 | 0 |
'max' | 最大值 | 1 |
'median' | 中位值 | 0.5 |
'0%' | 0% 位置 | 0.0 |
'50%' | 50% 位置 | 0.5 |
'100%' | 100% 位置 | 1.0 |
注意:这里的
min/max/median是"比例意义上的最小值/最大值"(即坐标轴的起点 0 与终点 1),对应到连续型 y 轴上等价于数据的最小值/最大值刻度;'0%'、'50%'、'100%'则是坐标轴的 0%、50%、100% 位置。两者指向同一组位置。
特殊值的底层解析逻辑
从源码看,这一语义由withGuide中的parseReplaceStr实现(packages/f2/src/components/guide/withGuide.tsx):
- 先查内置映射表:
min → 0、max → 1、median → 0.5,命中则直接返回比例值; - 若值是形如
'xx%'的字符串(以%结尾且前缀是数字),则rateValue / 100得到比例值(例如'50%'→ 0.5); - 否则走正常路径:
scale.scale(value),用对应度量把真实数据值换算成归一化比例。
换算出的比例值会与另一维度的值一同交给coord.convertPoint({ x, y })转为最终画布坐标。因此特殊值既可以用于 y 轴(如sold: 'min'),也可以用于 x 轴(如genre: 'min'标注坐标轴最左端)。
示例:标注每个 x 位置的 y 最小值
{data.map((item) => ( <PointGuide records={[{ genre: item.genre, sold: 'min' }]} style={{ stroke: '#262626' }} /> ))}style 属性的两种形态
style支持对象形式与函数形式两种写法,对应静态样式与动态样式两种诉求。
对象形式:静态样式
style={{ fill: '#f00', stroke: '#000', lineWidth: 2 }}适用于样式与数据、位置无关的场景。可配置的样式字段是CircleStyleProps,即圆形图形属性(cx、cy由组件自动计算,其余如fill、stroke、lineWidth、r、opacity、shadow等均可),完整属性见 Shape 属性文档。
函数形式:动态样式
style={(points, chart) => ({ fill: points[0].y > 0.5 ? '#f00' : '#00f' })}函数接收两个参数:
points:Point[]- 转换后的画布坐标点数组(每个元素形如{ x: number; y: number },取自records解析结果);chart:Chart- 图表实例,可获取图表布局信息(如chart.layout)、坐标、度量等。
从源码看(packages/f2/src/components/guide/withGuide.tsx),withGuide在渲染阶段会检测style是否为函数:若是,则先以style(points, chart)求值得到最终的样式对象,再传入视图;函数形态的animation同理。这意味着你可以在函数内基于任意一个标注点的画布坐标、甚至整个图表的状态来动态决定圆点的大小、颜色等外观。
实战:按相对高度动态着色
<Canvas context={context}> <Chart data={data}> <Line x="genre" y="sold" /> {data.map((item) => ( <PointGuide records={[item]} style={(points, chart) => { const y = points[0].y; const { top, bottom } = chart.layout; const normalizedY = (y - bottom) / (top - bottom); return { fill: normalizedY > 0.7 ? 'red' : 'gray', r: normalizedY > 0.7 ? 6 : 4, }; }} /> ))} </Chart> </Canvas>这里利用chart.layout的top/bottom把点的画布 y 坐标归一化到 0~1,再据此区分"高点"(红色、半径 6)与"普通点"(灰色、半径 4),非常适合做阈值告警式标注。
用法示例集
以下示例覆盖 PointGuide 最常见的几种实战形态,可直接复制到项目中按需组合。
使用特殊值标注:min 与 max 同屏展示
<Canvas context={context}> <Chart data={data}> <Line x="genre" y="sold" /> {data.map((item) => ( <PointGuide records={[{ genre: item.genre, sold: 'min' }]} style={{ stroke: '#262626' }} /> ))} {data.map((item) => ( <PointGuide records={[{ genre: item.genre, sold: 'max' }]} style={{ stroke: '#82DC95' }} /> ))} </Chart> </Canvas>标注百分比位置
<Canvas context={context}> <Chart data={data}> <Line x="genre" y="sold" /> {data.map((item) => ( <PointGuide records={[{ genre: item.genre, sold: '100%' }]} style={{ stroke: 'blue' }} /> ))} {data.map((item) => ( <PointGuide records={[{ genre: item.genre, sold: '50%' }]} style={{ stroke: 'red' }} /> ))} </Chart> </Canvas>多标注组合:min / median / max 三线同绘
使用多个map分别生成多组标注,可用于在一条折线上同时标出每个 x 位置的最低、居中与最高参考点:
<Canvas context={context}> <Chart data={data}> <Line x="genre" y="sold" /> {data.map((item) => ( <PointGuide records={[{ genre: item.genre, sold: 'min' }]} style={{ stroke: '#262626' }} /> ))} {data.map((item) => ( <PointGuide records={[{ genre: item.genre, sold: 'median' }]} style={{ stroke: '#FF6797' }} /> ))} {data.map((item) => ( <PointGuide records={[{ genre: item.genre, sold: 'max' }]} style={{ stroke: '#82DC95' }} /> ))} </Chart> </Canvas>使用动画
animation同样支持对象与函数两种形态(函数接收(points, chart)并返回动画配置)。下面的示例让标注点以 450ms 的 appear 动画淡入:
<Canvas context={context}> <Chart data={data}> <Line x="genre" y="sold" /> {data.map((item) => ( <PointGuide records={[item]} style={{ fill: 'red', r: 6 }} animation={{ appear: { duration: 450, } }} /> ))} </Chart> </Canvas>更多动画阶段的配置(appear/update/leave等)详见 动画文档。
深入原理:records 如何变成画布坐标
要真正用好 PointGuide,理解坐标换算链路很有价值。从源码看,整个流程集中在withGuide的parsePoint(packages/f2/src/components/guide/withGuide.tsx)中:
- 取度量:从
chart.getXScales()[0]与chart.getYScales()[0]分别取 x、y 轴的主度量; - 逐字段换算:对
records中的每条记录,x 字段与 y 字段各自经过parseReplaceStr(普通值走scale.scale,特殊值走映射/百分比换算)得到 0~1 归一化比例; - 坐标转换:把
{ x, y }比例值交给coord.convertPoint,得到画布像素坐标; - 渲染:
PointGuideView取points[0]作为圆心,叠加offsetX/offsetY偏移后绘制circle。
关于偏移与单位:PointGuideView在渲染前用context.px2hd(offsetX)、context.px2hd(offsetY)处理偏移量(packages/f2/src/components/guide/views/Point.tsx),因此offsetX/offsetY既支持纯数字,也支持带单位的字符串(如'10px'),最终按当前环境的像素比换算。另外,视图对isNaN(x) || isNaN(y)的坐标直接返回空节点,避免在坐标无效时绘制脏图形。
precise 精确定位:分组柱状图场景
默认情况下,Guide 的 x 定位落在"该 x 字段对应刻度"上。但在**分组柱状图(dodge 调整)**中,同一 x 刻度下存在多个按颜色分组的子柱子,普通定位无法落到具体的某一根柱子上。此时需要precise属性。
parsePoint中precise的分支逻辑(packages/f2/src/components/guide/withGuide.tsx):
- 当
precise && adjust?.type === 'dodge'时,额外取出颜色度量(chart.getColorScales()[0]),调用adjust.adjust.getPositionInfo结合分类字段与颜色字段算出该数据项在 dodge 调整后的精确位置,再经coord.convertPoint定位; - 该逻辑对 TextGuide 等所有 Guide 生效(示例中以 TextGuide 演示,PointGuide 的
precise语义相同)。
仓库测试 packages/f2/test/components/guide/preciseGuide.test.tsx 提供了完整的分组柱状图验证用例:数据含name(分组字段)、月份(x 字段)、月均降雨量(y 字段),配合adjust={{ type: 'dodge', marginRatio: 0.05 }}的分组柱状图,逐条records={[item]}加precise即可让每条标注精确钉在对应的子柱子上。
<Canvas context={context}> <Chart data={data}> <Axis field="月份" /> <Axis field="月均降雨量" /> <Interval x="月份" y="月均降雨量" color={{ field: 'name' }} adjust={{ type: 'dodge', marginRatio: 0.05 }} /> {data.map((item) => ( <PointGuide records={[item]} precise style={{ r: 6 }} /> ))} </Chart> </Canvas>使用precise的注意事项:
- 它仅在分组(dodge)调整下有意义,非 dodge 场景下该分支不会生效,走常规定位;
records中需要包含颜色字段(分组字段)的值,否则无法定位到具体子柱子;- 若对定位精度有疑问,可参考测试中 TextGuide 的逐数据项标注写法,通过比对快照验证效果。
交互与其他能力
- 点击事件:
onClick={(ev) => ...}接收事件对象。从withGuide的渲染结构看,点击事件挂在包裹标注的<group>节点上(packages/f2/src/components/guide/withGuide.tsx),可在图表事件体系内实现标注的点击反馈。 - 显隐控制:
visible默认为true,设为false时整个标注组不渲染(if (!visible) return;),可用于按条件展示标注。 - 主题覆盖:除传入
style外,也可通过全局主题覆盖guide.point来统一调整所有 PointGuide 的默认外观,主题文件见 packages/f2/src/theme.ts。
相关阅读
- Guide 组件总览与注册: packages/f2/src/components/guide/index.tsx
- Guide 通用逻辑(records 解析 / precise / 函数式 style 与 animation): packages/f2/src/components/guide/withGuide.tsx
- PointGuide 视图渲染: packages/f2/src/components/guide/views/Point.tsx
- 主题默认样式: packages/f2/src/theme.ts
- 测试用例: type.test.tsx、preciseGuide.test.tsx
- 其他标注类型文档: TextGuide、LineGuide、RectGuide、ImageGuide
- 数据可视化
- 前端
【免费下载链接】F2
📱📈An elegant, interactive and flexible charting library for mobile.
相关推荐
F2 ImageGuide 图片标注组件完全指南:定位、样式、事件与动画实战
F2 ImageGuide 图片标注组件完全指南:定位、样式、事件与动画实战 在移动端图表中,除了图形本身,常常需要在关键数据点(如最高值、最低值或特定记录)上
数据可视化前端TypeScript SDK 故障排查完全指南:从 stdio 污染到协议时代协商失败的逐条解法
TypeScript SDK 故障排查完全指南:从 stdio 污染到协议时代协商失败的逐条解法 本篇指南面向使用 Model Context Protocol
数据可视化前端昇腾CANN PTO浮点取模指令
TFMOD Tile Operation Diagram ! TFMOD tile operation https://raw.gitcode.com/ca
数据可视化前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考