☰
F2 PointGuide 点标注指南:records 特殊值、样式函数与精确标注实战
2026/9/27 23:52:04 网站建设 项目流程
  • 数据可视化
  • 前端

【免费下载链接】F2

📱📈An elegant, interactive and flexible charting library for mobile.

项目地址:https://gitcode.com/gh_mirrors/f2/F2
点击查看免费下载

导读

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 一览:

属性类型默认值说明
recordsArray<RecordItem>-标注位置的数据项或比例值,支持特殊值(见下文)
offsetXnumber \| string0x 轴偏移量
offsetYnumber \| string0y 轴偏移量
styleCircleStyleProps \| Function见下方圆形样式,支持对象或函数形式
animationAnimationProps \| Function-动画配置,详见 动画文档
onClick(ev: Event) => void-点击事件回调
visiblebooleantrue是否显示标注
preciseboolean-是否精确定位(用于分组柱状图中精确定位到每个子柱子)

默认样式值

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)中:

  1. 取度量:从chart.getXScales()[0]与chart.getYScales()[0]分别取 x、y 轴的主度量;
  2. 逐字段换算:对records中的每条记录,x 字段与 y 字段各自经过parseReplaceStr(普通值走scale.scale,特殊值走映射/百分比换算)得到 0~1 归一化比例;
  3. 坐标转换:把{ x, y }比例值交给coord.convertPoint,得到画布像素坐标;
  4. 渲染: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.

项目地址:https://gitcode.com/gh_mirrors/f2/F2
点击查看免费下载
上一篇:CAMEL 多智能体框架快速上手:三步让两个 AI 角色自动协作完成任务
下一篇:如何高效使用开源网盘直链解析工具:智能下载解决方案完全指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询