
Antv G2 Chart
- 978 installs
- 454 repo stars
- Updated July 31, 2026
- antvis/chart-visualization-skills
antv-g2-chart is an AntV G2 v5 visualization skill that configures enter, update, and exit animations via the animate property for developers who need polished chart transitions in data dashboards.
About
antv-g2-chart is an antvis/chart-visualization-skills agent skill focused on the G2 v5 animation system through the animate configuration property. It documents three timing phases—enter, update, and exit—and built-in animation types including fadeIn/Out, scaleInX/Y, growInX/Y, waveIn, zoomIn/Out, morphing, and pathIn, each tunable with duration, delay, and easing. Frontend developers building AntV G2 dashboards reach for antv-g2-chart when first render, data refresh, or chart removal needs motion without hand-rolling keyframes. The skill is tagged beginner difficulty with full completeness and links related skills g2-animation-keyframe and g2-core-chart-init for deeper animation control.
- Supports 14 built-in animation types including fadeIn/Out, scaleInX/Y, growInX/Y, waveIn, zoomIn/Out, morphing and pathI
- Configure timing with duration, delay, and easing functions for enter, update, and exit moments
- One-line animate option on G2 chart elements
- Ready-to-run minimal JavaScript example included
- Visual reference table mapping each animation to its best-use chart type
Antv G2 Chart by the numbers
- 978 all-time installs (skills.sh)
- +46 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #388 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/antvis/chart-visualization-skills --skill antv-g2-chartAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 978 |
|---|---|
| repo stars | ★ 454 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 31, 2026 |
| Repository | antvis/chart-visualization-skills ↗ |
How do you add enter and exit animations in AntV G2?
Quickly add polished enter, update, and exit animations to data visualizations built with AntV G2.
Who is it for?
Frontend developers shipping AntV G2 v5 charts who want built-in transition animations on render and data updates.
Skip if: Non-G2 chart libraries, static SVG exports with no animation requirements, or backend-only data pipelines.
When should I use this skill?
The user asks for G2 chart animations, animate config, or enter/update/exit transitions on AntV visualizations.
What you get
G2 animate configurations for enter, update, and exit phases with duration, delay, and easing settings.
- animate configuration snippets
- Animation timing setup for chart lifecycle
By the numbers
- G2 v5 animation system with 3 timing phases: enter, update, exit
- Documents 10+ built-in animation types including fadeIn, waveIn, and morphing
Files
内置动画类型速查
| 动画名 | 效果 | 适合场景 |
|---|---|---|
fadeIn | 从透明到不透明 | 通用入场 |
fadeOut | 从不透明到透明 | 通用退场 |
scaleInX | 从 X 轴起点缩放展开 | 柱状图入场 |
scaleInY | 从 Y 轴底部缩放展开 | 柱状图入场(竖向) |
scaleOutX | 向 X 轴收缩消失 | 柱状图退场 |
scaleOutY | 向 Y 轴收缩消失 | 柱状图退场 |
growInX | 从左向右生长 | 条形图、折线图入场 |
growInY | 从下向上生长 | 柱状图入场 |
waveIn | 波浪扫描入场 | 极坐标图(玫瑰图、饼图) |
zoomIn | 从中心缩放放大 | 点图入场 |
zoomOut | 向中心缩小消失 | 点图退场 |
pathIn | 路径逐步绘制 | 折线图、路径图 |
morphing | 形状变形过渡 | 图表类型切换 |
最小可运行示例
import { Chart } from '@antv/g2';
const chart = new Chart({ container: 'container', width: 640, height: 480 });
chart.options({
type: 'interval',
data: [
{ genre: 'Sports', sold: 275 },
{ genre: 'Strategy', sold: 115 },
{ genre: 'Action', sold: 120 },
{ genre: 'RPG', sold: 98 },
],
encode: { x: 'genre', y: 'sold', color: 'genre' },
animate: {
enter: {
type: 'growInY', // 入场动画:从下向上生长
duration: 800, // 持续时间(毫秒)
delay: 0, // 延迟
easing: 'ease-out', // 缓动函数
},
},
});
chart.render();配置动画的三个时机
chart.options({
type: 'interval',
data,
encode: { x: 'x', y: 'y', color: 'type' },
animate: {
// 入场:图表首次渲染时
enter: {
type: 'scaleInY',
duration: 1000,
easing: 'ease-out-bounce',
},
// 更新:数据变化时
update: {
type: 'morphing',
duration: 500,
},
// 退场:图元被移除时
exit: {
type: 'fadeOut',
duration: 300,
},
},
});禁用动画
// 禁用所有动画
chart.options({
animate: false,
});
// 仅禁用入场动画
chart.options({
animate: {
enter: false,
},
});常见动画组合推荐
// 柱状图:growInY 入场
animate: { enter: { type: 'growInY', duration: 800 } }
// 折线图:pathIn 入场(路径绘制效果)
animate: { enter: { type: 'pathIn', duration: 1200 } }
// 饼图(极坐标):waveIn 入场
animate: { enter: { type: 'waveIn', duration: 1000 } }
// 散点图:zoomIn 入场
animate: { enter: { type: 'zoomIn', duration: 600 } }
// 通用淡入
animate: { enter: { type: 'fadeIn', duration: 500 } }常见错误与修正
错误 1:animate.enter 写成字符串
// ❌ 错误:enter 不是字符串,是对象
chart.options({
animate: { enter: 'fadeIn' }, // ❌
});
// ✅ 正确
chart.options({
animate: { enter: { type: 'fadeIn', duration: 600 } }, // ✅
});错误 2:在极坐标图用非极坐标动画
// ❌ scaleInX/Y 在极坐标中效果不对
chart.options({
coordinate: { type: 'theta' },
animate: { enter: { type: 'scaleInY' } }, // ❌ 饼图应该用 waveIn
});
// ✅ 极坐标图推荐 waveIn
chart.options({
coordinate: { type: 'theta' },
animate: { enter: { type: 'waveIn', duration: 1000 } }, // ✅
});--- id: "g2-animation-keyframe" title: "G2 关键帧动画(timingKeyframe)" description: | timingKeyframe 是 G2 v5 的组合类型,将多个图表视图按时序播放, 实现数据故事讲述(data storytelling)效果。 每个子视图是一个"关键帧",系统自动在帧间插值过渡,支持形变动画(morphing)。
library: "g2" version: "5.x" category: "animations" tags:
- "timingKeyframe"
- "关键帧"
- "数据故事"
- "keyframe"
- "morphing"
- "动画"
- "composition"
related:
- "g2-animation-intro"
- "g2-core-view-composition"
use_cases:
- "演示数据如何从一种图表类型变为另一种(柱状图 → 折线图)"
- "展示数据随时间的演变过程"
- "数据新闻和可视化故事讲述"
difficulty: "advanced" completeness: "full" created: "2025-03-24" updated: "2025-03-24" author: "antv-team" source_url: "https://g2.antv.ant
内置动画类型速查
| 动画名 | 效果 | 适合场景 |
|---|---|---|
fadeIn | 从透明到不透明 | 通用入场 |
fadeOut | 从不透明到透明 | 通用退场 |
scaleInX | 从 X 轴起点缩放展开 | 柱状图入场 |
scaleInY | 从 Y 轴底部缩放展开 | 柱状图入场(竖向) |
scaleOutX | 向 X 轴收缩消失 | 柱状图退场 |
scaleOutY | 向 Y 轴收缩消失 | 柱状图退场 |
growInX | 从左向右生长 | 条形图、折线图入场 |
growInY | 从下向上生长 | 柱状图入场 |
waveIn | 波浪扫描入场 | 极坐标图(玫瑰图、饼图) |
zoomIn | 从中心缩放放大 | 点图入场 |
zoomOut | 向中心缩小消失 | 点图退场 |
pathIn | 路径逐步绘制 | 折线图、路径图 |
morphing | 形状变形过渡 | 图表类型切换 |
最小可运行示例
import { Chart } from '@antv/g2';
const chart = new Chart({ container: 'container', width: 640, height: 480 });
chart.options({
type: 'interval',
data: [
{ genre: 'Sports', sold: 275 },
{ genre: 'Strategy', sold: 115 },
{ genre: 'Action', sold: 120 },
{ genre: 'RPG', sold: 98 },
],
encode: { x: 'genre', y: 'sold', color: 'genre' },
animate: {
enter: {
type: 'growInY', // 入场动画:从下向上生长
duration: 800, // 持续时间(毫秒)
delay: 0, // 延迟
easing: 'ease-out', // 缓动函数
},
},
});
chart.render();配置动画的三个时机
chart.options({
type: 'interval',
data,
encode: { x: 'x', y: 'y', color: 'type' },
animate: {
// 入场:图表首次渲染时
enter: {
type: 'scaleInY',
duration: 1000,
easing: 'ease-out-bounce',
},
// 更新:数据变化时
update: {
type: 'morphing',
duration: 500,
},
// 退场:图元被移除时
exit: {
type: 'fadeOut',
duration: 300,
},
},
});禁用动画
// 禁用所有动画
chart.options({
animate: false,
});
// 仅禁用入场动画
chart.options({
animate: {
enter: false,
},
});常见动画组合推荐
// 柱状图:growInY 入场
animate: { enter: { type: 'growInY', duration: 800 } }
// 折线图:pathIn 入场(路径绘制效果)
animate: { enter: { type: 'pathIn', duration: 1200 } }
// 饼图(极坐标):waveIn 入场
animate: { enter: { type: 'waveIn', duration: 1000 } }
// 散点图:zoomIn 入场
animate: { enter: { type: 'zoomIn', duration: 600 } }
// 通用淡入
animate: { enter: { type: 'fadeIn', duration: 500 } }常见错误与修正
错误 1:animate.enter 写成字符串
// ❌ 错误:enter 不是字符串,是对象
chart.options({
animate: { enter: 'fadeIn' }, // ❌
});
// ✅ 正确
chart.options({
animate: { enter: { type: 'fadeIn', duration: 600 } }, // ✅
});错误 2:在极坐标图用非极坐标动画
// ❌ scaleInX/Y 在极坐标中效果不对
chart.options({
coordinate: { type: 'theta' },
animate: { enter: { type: 'scaleInY' } }, // ❌ 饼图应该用 waveIn
});
// ✅ 极坐标图推荐 waveIn
chart.options({
coordinate: { type: 'theta' },
animate: { enter: { type: 'waveIn', duration: 1000 } }, // ✅
});最小可运行示例(柱状图 → 折线图)
import { Chart } from '@antv/g2';
const data = [
{ month: 'Jan', value: 83 },
{ month: 'Feb', value: 60 },
{ month: 'Mar', value: 95 },
{ month: 'Apr', value: 72 },
{ month: 'May', value: 110 },
];
const chart = new Chart({ container: 'container', width: 640, height: 480 });
chart.options({
type: 'timingKeyframe', // 关键帧组合类型
duration: 1000, // 每帧过渡时长(毫秒)
iterationCount: 2, // 循环次数('infinite' 为无限循环)
direction: 'alternate', // 'normal' | 'reverse' | 'alternate' | 'reverse-alternate'
easing: 'ease-in-out-sine',
children: [
// 关键帧 1:柱状图
{
type: 'interval',
data,
encode: { x: 'month', y: 'value', color: 'month' },
axis: { y: { title: '月份销量' } },
},
// 关键帧 2:折线图(自动在两者之间插值动画)
{
type: 'line',
data,
encode: { x: 'month', y: 'value' },
style: { lineWidth: 3 },
},
],
});
chart.render();多关键帧(数据更新动画)
chart.options({
type: 'timingKeyframe',
duration: 800,
iterationCount: 'infinite',
direction: 'alternate',
children: [
// 关键帧 1:2022 年数据
{
type: 'interval',
data2022,
encode: { x: 'city', y: 'gdp', color: 'city' },
title: '2022 年 GDP',
},
// 关键帧 2:2023 年数据(相同字段,自动形变过渡)
{
type: 'interval',
data: data2023,
encode: { x: 'city', y: 'gdp', color: 'city' },
title: '2023 年 GDP',
},
],
});配置项
chart.options({
type: 'timingKeyframe',
duration: 1000, // 关键帧间过渡时长(毫秒),默认 1000
iterationCount: 1, // 循环次数,默认 1;'infinite' 无限循环
direction: 'normal', // 播放方向:
// 'normal' - 正向
// 'reverse' - 反向
// 'alternate' - 正反交替
// 'reverse-alternate' - 反正交替
easing: 'ease-in-out-sine', // 缓动函数,默认 'ease-in-out-sine'
children: [/* 各关键帧视图配置 */],
});常见错误与修正
错误 1:children 帧的 encode 字段名不一致——无法形变
// ❌ 字段名不一致,无法识别对应关系,形变效果丢失
children: [
{ type: 'interval', encode: { x: 'month', y: 'sales' } }, // sales
{ type: 'line', encode: { x: 'month', y: 'revenue' } }, // revenue ❌ 名字不同
]
// ✅ 相同字段名才能实现平滑形变
children: [
{ type: 'interval', encode: { x: 'month', y: 'value' } },
{ type: 'line', encode: { x: 'month', y: 'value' } }, // ✅ 同名字段
]错误 2:iterationCount 写成数字字符串
// ❌ 错误:应该是字符串 'infinite',不是数字
chart.options({ iterationCount: Infinity }); // ❌
// ✅ 正确
chart.options({ iterationCount: 'infinite' }); // ✅
chart.options({ iterationCount: 3 }); // ✅ 或具体数字动画类型与适用场景
| 动画名 | 方向 | 最适合 Mark | 特点 |
|---|---|---|---|
fadeIn | - | 所有 Mark | 渐显,通用,最安全 |
fadeOut | - | 所有 Mark | 渐隐,退场通用 |
scaleInX | X 轴 | interval(柱状图) | 从左上角向右扩展 |
scaleInY | Y 轴 | interval(柱状图) | 从底部向上缩放 |
scaleOutX | X 轴 | interval | scaleInX 的退场版本 |
scaleOutY | Y 轴 | interval | scaleInY 的退场版本 |
growInX | X 轴 | line, area, interval(直角坐标) | 裁剪从左向右生长 |
growInY | Y 轴 | interval, area(直角坐标) | 裁剪从底部向上生长;极坐标/helix 禁用 |
pathIn | 路径 | line, path, link | 路径线条逐步绘制 |
waveIn | 波浪 | interval(极坐标) | 极坐标专用扇形展开 |
zoomIn | 中心 | point, text | 从中心缩放放大 |
zoomOut | 中心 | point, text | 向中心缩小消失 |
morphing | 形变 | 所有 Mark | 形状平滑变形过渡 |
fadeIn / fadeOut(渐显渐隐)
// 最通用的动画,适合任何 mark
chart.options({
type: 'point',
data,
encode: { x: 'x', y: 'y' },
animate: {
enter: { type: 'fadeIn', duration: 600 },
exit: { type: 'fadeOut', duration: 300 },
},
});scaleInY / growInY(柱状图入场)
// scaleInY:缩放展开(有缩放感)
// growInY:裁剪生长(有"从地面长出来"的感觉,更自然)
chart.options({
type: 'interval',
data,
encode: { x: 'genre', y: 'sold' },
animate: {
// 方式一:缩放
enter: { type: 'scaleInY', duration: 800, easing: 'ease-out' },
// 方式二:生长(推荐)
// enter: { type: 'growInY', duration: 800 },
},
});pathIn(折线图路径绘制)
// pathIn:折线/路径从左向右逐步绘制
chart.options({
type: 'line',
data: timeSeriesData,
encode: { x: 'date', y: 'value', color: 'type' },
animate: {
enter: {
type: 'pathIn', // 路径逐步绘制
duration: 1500,
easing: 'linear', // 匀速绘制效果更佳
},
},
});waveIn(极坐标/饼图专用)
// waveIn:从外圈向内的波浪扫入,专为极坐标设计
chart.options({
type: 'interval',
data,
encode: { y: 'value', color: 'type' },
transform: [{ type: 'stackY' }],
coordinate: { type: 'theta', outerRadius: 0.8 },
animate: {
enter: {
type: 'waveIn', // 极坐标专用
duration: 1000,
},
},
});zoomIn / zoomOut(点图缩放)
// zoomIn:散点从中心缩放出现
chart.options({
type: 'point',
data: scatterData,
encode: { x: 'x', y: 'y', size: 'value' },
animate: {
enter: { type: 'zoomIn', duration: 500 },
exit: { type: 'zoomOut', duration: 300 },
},
});morphing(形变更新动画)
// morphing:数据更新时图形平滑变形
chart.options({
type: 'interval',
data,
encode: { x: 'genre', y: 'sold' },
animate: {
update: {
type: 'morphing', // 数据更新时形变过渡
duration: 600,
},
},
});
// 也可以在 timingKeyframe 中自动触发形变
chart.options({
type: 'timingKeyframe',
children: [
{ type: 'interval', data, encode: { x: 'x', y: 'y' } },
{ type: 'line', data, encode: { x: 'x', y: 'y' } },
],
});按图表类型推荐的动画
// 柱状图(推荐 growInY)
{ type: 'interval', animate: { enter: { type: 'growInY', duration: 800 } } }
// 条形图(推荐 growInX)
{ type: 'interval', coordinate: { transform: [{ type: 'transpose' }] },
animate: { enter: { type: 'growInX', duration: 800 } } }
// 折线图(推荐 pathIn)
{ type: 'line', animate: { enter: { type: 'pathIn', duration: 1200 } } }
// 散点图(推荐 zoomIn 或 fadeIn)
{ type: 'point', animate: { enter: { type: 'zoomIn', duration: 400 } } }
// 饼图/环形图(推荐 waveIn)
{ type: 'interval', coordinate: { type: 'theta' },
animate: { enter: { type: 'waveIn', duration: 1000 } } }
// 面积图(推荐 fadeIn 或 growInX)
{ type: 'area', animate: { enter: { type: 'fadeIn', duration: 800 } } }
// 螺旋图 helix 坐标系(必须用 fadeIn,禁止用 growInX/Y)
{ type: 'interval', coordinate: { type: 'helix', ... },
animate: { enter: { type: 'fadeIn', duration: 800 } } }常见错误与修正
错误 1:在条形图(转置)上用 scaleInY
// ❌ 条形图是水平方向,用 scaleInY(竖向缩放)效果不对
chart.options({
type: 'interval',
coordinate: { transform: [{ type: 'transpose' }] },
animate: { enter: { type: 'scaleInY' } }, // ❌ 应该用 growInX 或 scaleInX
});
// ✅ 条形图用 X 方向动画
chart.options({
animate: { enter: { type: 'growInX', duration: 800 } }, // ✅
});错误 2:在 helix(螺旋)坐标系上用 growInX/growInY
growInX / growInY 的实现是沿直角坐标轴方向做 clipPath 裁剪。在 helix 坐标系中,坐标轴被重映射为螺旋路径,屏幕上不存在"底部"或"左侧"基线,裁剪矩形会横穿螺旋形,导致部分螺旋区域被切掉或渲染残缺,动画结束后图表也可能显示不完整。
同样问题适用于所有非直角坐标系(polar、theta、helix)——这些坐标系均应使用 waveIn(极坐标专用)或 fadeIn(通用),不能使用 growInX/Y。
// ❌ 错误:helix 坐标系用 growInY → 裁剪矩形横穿螺旋,图表渲染残缺
chart.options({
type: 'interval',
coordinate: { type: 'helix', startAngle: 0, endAngle: Math.PI * 6 },
animate: {
enter: { type: 'growInY', duration: 2000 }, // ❌ 螺旋被裁剪,部分区域缺失
},
});
// ✅ 正确:helix 坐标系用 fadeIn
chart.options({
type: 'interval',
coordinate: { type: 'helix', startAngle: 0, endAngle: Math.PI * 6 },
animate: {
enter: { type: 'fadeIn', duration: 1000 }, // ✅ 渐显,无裁剪副作用
},
});
// ✅ 极坐标(theta/polar)用 waveIn
chart.options({
type: 'interval',
coordinate: { type: 'theta' },
animate: {
enter: { type: 'waveIn', duration: 1000 }, // ✅ 极坐标专用扇形展开
},
});根本原因:growInX/Y 假设存在固定的直角基线(X=0 或 Y=0)作为裁剪起点,这在笛卡尔坐标系中成立;但 helix / polar 将坐标重映射到极坐标或螺旋路径后,该基线不再对应可见边界,裁剪结果是任意截断螺旋形状。
水平参考线(lineY)
import { Chart } from '@antv/g2';
const chart = new Chart({ container: 'container', width: 640, height: 480 });
chart.options({
type: 'view',
data,
children: [
// 主图:折线图
{
type: 'line',
encode: { x: 'month', y: 'value' },
},
// 标注:y=60 的水平参考线
{
type: 'lineY',
data: [60],
style: {
stroke: '#f5222d',
strokeDasharray: '4 4',
lineWidth: 1.5,
},
labels: [
{
text: '目标值: 60',
position: 'right',
style: { fill: '#f5222d', fontSize: 11 },
},
],
},
],
});
chart.render();垂直参考线(lineX)
// 标记某个特殊时间点
{
type: 'lineX',
data: [new Date('2024-03-01')],
style: { stroke: '#722ed1', strokeDasharray: '4 4', lineWidth: 1.5 },
labels: [
{ text: '版本发布', position: 'top', style: { fill: '#722ed1' } },
],
}标注最大值点
chart.options({
type: 'view',
data,
children: [
{ type: 'line', encode: { x: 'month', y: 'value' } },
{
// 用 point + text 标注最大值
type: 'point',
data,
encode: { x: 'month', y: 'value' },
transform: [{ type: 'select', channel: 'y', selector: 'max' }], // 只选最大值点
style: { fill: '#f5222d', r: 5 },
labels: [
{
text: (d) => `最大值\n${d.value}`,
position: 'top',
style: { fill: '#f5222d', fontSize: 11 },
},
],
},
],
});参考区间(rangeX)
// 高亮某个 x 值范围(如正常区间)
{
type: 'rangeX',
data: [{ x: '6月', x1: '7月' }],
encode: { x: 'x', x1: 'x1' },
style: {
fill: '#52c41a',
fillOpacity: 0.08,
},
labels: [
{
text: '正常范围',
position: 'top-right',
style: { fill: '#52c41a', fontSize: 11 },
},
],
}参考区间(rangeY)
// 高亮某个 y 值范围(如正常区间)
{
type: 'rangeY',
data: [{ y: 50, y1: 80 }],
encode: { y: 'y', y1: 'y1' },
style: {
fill: '#52c41a',
fillOpacity: 0.08,
},
labels: [
{
text: '正常范围',
position: 'right',
style: { fill: '#52c41a', fontSize: 11 },
},
],
}文字标注(text mark)
// 在指定坐标处添加文字
{
type: 'text',
data: [{ x: 'Mar', y: 91, label: '最高点' }],
encode: { x: 'x', y: 'y', text: 'label' },
style: {
textAlign: 'center',
textBaseline: 'bottom',
fill: '#1890ff',
fontSize: 12,
dy: -6,
},
}图片标注(image mark)
// 在图表中心添加图片标注
{
type: 'image',
data: [{
src: 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg',
x: '50%',
y: '50%'
}],
encode: {
x: 'x',
y: 'y',
src: 'src'
},
style: {
width: 80,
height: 80,
textAlign: 'center',
textBaseline: 'middle'
}
}常见错误与修正
错误:在非 view 容器中直接叠加标注
// ❌ 错误:多个 chart.options() 会互相覆盖
chart.options({ type: 'line', ... });
chart.options({ type: 'lineY', ... }); // 覆盖了折线图!
// ✅ 正确:用 type: 'view' + children 数组叠加
chart.options({
type: 'view',
data,
children: [
{ type: 'line', ... },
{ type: 'lineY', ... },
],
});错误:image 标注未正确设置位置和编码
// ❌ 错误:使用函数返回固定坐标,未绑定到数据通道
{
type: 'image',
data: [{ url: 'https://example.com/image.png' }],
encode: {
x: () => 0, // 固定在中心
y: () => 0 // 固定在中心
},
style: {
img: (d) => d.url,
width: 80,
height: 80
}
}
// ✅ 正确:使用相对百分比坐标并正确映射 src 通道
{
type: 'image',
data: [{
src: 'https://example.com/image.png',
x: '50%',
y: '50%'
}],
encode: {
x: 'x',
y: 'y',
src: 'src'
},
style: {
width: 80,
height: 80
}
}基本用法
import { Chart } from '@antv/g2';
const chart = new Chart({ container: 'container', width: 640, height: 480 });
chart.options({
type: 'interval',
data,
encode: { x: 'month', y: 'revenue' },
axis: {
x: { title: '月份' },
y: { title: '收入(万元)' },
},
});
chart.render();---
增量修改配置
如果已有图表,只想修改某个配置项(如标签颜色),可以使用以下方式:
// 方式一:重新调用 options,只传需要修改的配置
chart.options({
axis: {
y: {
labelFill: 'red', // 只修改标签颜色
},
},
});
chart.render(); // 需要重新渲染
// 方式二:完整配置后修改
const options = {
type: 'line',
data,
encode: { x: 'date', y: 'value' },
axis: { x: { title: '日期' } },
};
chart.options(options);
// 后续修改
options.axis = { y: { labelFill: 'red' } };
chart.options(options);
chart.render();---
完整配置项参考
通用配置
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
position | 坐标轴位置 | `'left' \ | 'right' \ |
animate | 是否开启动画 | boolean | - |
轴标题样式(title)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
title | 标题内容 | `string \ | false` |
titleSpacing | 标题到坐标轴的距离 | number | 10 |
titlePosition | 标题相对坐标轴的位置 | `'top' \ | 'bottom' \ |
titleFontSize | 标题文字大小 | number | - |
titleFontWeight | 标题文字字体粗细 | `number \ | string` |
titleFontFamily | 标题文字字体 | string | - |
titleLineHeight | 标题文字行高 | number | 1 |
titleTextAlign | 标题文字水平对齐方式 | string | 'start' |
titleTextBaseline | 标题文字垂直基线 | string | 'middle' |
titleFill | 标题文字填充色 | string | - |
titleFillOpacity | 标题文字填充透明度 | number | 1 |
titleStroke | 标题文字描边颜色 | string | transparent |
titleStrokeOpacity | 标题文字描边透明度 | number | 1 |
titleLineWidth | 标题文字描边宽度 | number | 0 |
titleLineDash | 标题文字描边虚线配置 | number[] | [] |
titleOpacity | 标题文字整体透明度 | number | 1 |
titleShadowColor | 标题文字阴影颜色 | string | transparent |
titleShadowBlur | 标题文字阴影模糊系数 | number | 0 |
titleShadowOffsetX | 标题文字阴影水平偏移量 | number | 0 |
titleShadowOffsetY | 标题文字阴影垂直偏移量 | number | 0 |
titleCursor | 标题文字鼠标样式 | string | default |
titleDx | 标题文字水平偏移量 | number | 0 |
titleDy | 标题文字垂直偏移量 | number | 0 |
轴线样式(line)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
line | 是否显示轴线 | boolean | false |
arrow | 是否显示箭头 | boolean | true |
lineExtension | 轴线两侧的延长线 | [number, number] | - |
lineArrow | 轴线箭头形状 | DisplayObject | - |
lineArrowOffset | 箭头偏移长度 | number | 15 |
lineArrowSize | 箭头尺寸 | number | - |
lineStroke | 轴线描边颜色 | string | - |
lineStrokeOpacity | 轴线描边透明度 | number | - |
lineLineWidth | 轴线描边宽度 | number | - |
lineLineDash | 轴线描边虚线配置 | [number, number] | - |
lineOpacity | 轴线整体透明度 | number | 1 |
lineShadowColor | 轴线阴影颜色 | string | - |
lineShadowBlur | 轴线阴影模糊系数 | number | - |
lineShadowOffsetX | 轴线阴影水平偏移量 | number | - |
lineShadowOffsetY | 轴线阴影垂直偏移量 | number | - |
lineCursor | 轴线鼠标样式 | string | default |
刻度线样式(tick)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
tick | 是否显示刻度 | boolean | true |
tickCount | 推荐生成的刻度数量 | number | - |
tickMethod | 自定义刻度生成方法 | (start, end, count) => number[] | - |
tickFilter | 刻度线过滤 | (datum, index, data) => boolean | - |
tickFormatter | 刻度线格式化 | (datum, index, data, Vector) => DisplayObject | - |
tickDirection | 刻度朝向 | `'positive' \ | 'negative'` |
tickLength | 刻度线长度 | number | 15 |
tickStroke | 刻度线描边颜色 | string | - |
tickStrokeOpacity | 刻度线描边透明度 | number | - |
tickLineWidth | 刻度线描边宽度 | number | - |
tickLineDash | 刻度线描边虚线配置 | [number, number] | - |
tickOpacity | 刻度线整体透明度 | number | - |
tickShadowColor | 刻度线阴影颜色 | string | - |
tickShadowBlur | 刻度线阴影模糊系数 | number | - |
tickShadowOffsetX | 刻度线阴影水平偏移量 | number | - |
tickShadowOffsetY | 刻度线阴影垂直偏移量 | number | - |
tickCursor | 刻度线鼠标样式 | string | default |
刻度标签样式(label)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
labelFormatter | 标签格式化 | `string \ | (datum, index, data) => string` |
labelFilter | 标签过滤 | (datum, index, data) => boolean | - |
labelAutoRotate | 标签过长时自动旋转 | boolean | - |
labelAutoHide | 标签过密时自动隐藏 | boolean | - |
labelSpacing | 标签与刻度线的间距 | number | - |
labelFontSize | 标签文字大小 | number | - |
labelFontWeight | 标签文字字体粗细 | `number \ | string` |
labelFontFamily | 标签文字字体 | string | - |
labelLineHeight | 标签文字行高 | number | - |
labelTextAlign | 标签文字水平对齐方式 | string | - |
labelTextBaseline | 标签文字垂直基线 | string | - |
labelFill | 标签文字填充色 | string | - |
labelFillOpacity | 标签文字填充透明度 | number | - |
labelStroke | 标签文字描边颜色 | string | - |
labelStrokeOpacity | 标签文字描边透明度 | number | - |
labelLineWidth | 标签文字描边宽度 | number | - |
labelLineDash | 标签文字描边虚线配置 | number[] | - |
labelOpacity | 标签文字整体透明度 | number | - |
labelShadowColor | 标签文字阴影颜色 | string | - |
labelShadowBlur | 标签文字阴影模糊系数 | number | - |
labelShadowOffsetX | 标签文字阴影水平偏移量 | number | - |
labelShadowOffsetY | 标签文字阴影垂直偏移量 | number | - |
labelCursor | 标签文字鼠标样式 | string | default |
labelDx | 标签文字水平偏移量 | number | - |
labelDy | 标签文字垂直偏移量 | number | - |
刻度标签样式(label,补充)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
labelRender | 自定义标签渲染,支持 HTML 字符串,用法同 labelFormatter | `string \ | (datum, index, array) => string` |
labelAlign | 刻度值对齐方式 | `'horizontal' \ | 'parallel' \ |
labelDirection | 刻度值相对轴线的位置 | `'positive' \ | 'negative'` |
labelAutoEllipsis | 自动缩略过长的刻度值 | boolean | - |
labelAutoWrap | 自动换行刻度值 | boolean | - |
网格线样式(grid)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
grid | 是否显示网格线 | boolean | - |
gridAreaFill | 网格线区域填充色,支持交替颜色数组或函数 | `string \ | string[] \ |
gridFilter | 网格线过滤,返回 false 隐藏该网格线 | (datum, index, data) => boolean | - |
gridLength | 网格线长度 | number | 0 |
gridStroke | 网格线描边颜色 | string | - |
gridStrokeOpacity | 网格线描边透明度 | number | - |
gridLineWidth | 网格线描边宽度 | number | - |
gridLineDash | 网格线描边虚线配置 | [number, number] | - |
gridOpacity | 网格线整体透明度 | number | - |
gridShadowColor | 网格线阴影颜色 | string | - |
gridShadowBlur | 网格线阴影模糊系数 | number | - |
gridShadowOffsetX | 网格线阴影水平偏移量 | number | - |
gridShadowOffsetY | 网格线阴影垂直偏移量 | number | - |
gridCursor | 网格线鼠标样式 | string | default |
---
常用配置示例
完整配置示例
chart.options({
type: 'line',
data,
encode: { x: 'date', y: 'value' },
axis: {
x: {
title: '日期',
titleFontSize: 14,
titleFill: '#666',
tickCount: 6,
labelFormatter: 'YYYY-MM',
labelFontSize: 11,
labelFill: '#888',
tick: true,
tickLength: 5,
line: true,
grid: true,
gridLineDash: [4, 4],
},
y: {
title: '收入(万元)',
labelFormatter: (v) => `¥${v}`,
},
},
});刻度相关配置职责速查
刻度控制有三个配置项,职责不同,不能混用:
| 配置项 | 签名 | 职责 | 使用频率 |
|---|---|---|---|
labelFormatter | (value, index, array) => string | 刻度文字内容 | ⭐ 最常用 |
tickMethod | (start, end, tickCount) => number[] | 刻度数值位置 | 偶尔使用 |
tickFormatter | (datum, index, array, vector) => DisplayObject | 刻度线图形 | 极少使用 |
❌ 常见错误:把tickFormatter当labelFormatter用——tickFormatter返回的是图形对象,不是字符串,用错会导致标签不显示。
常用格式化场景
// 数值格式化
axis: { y: { labelFormatter: (v) => `${(v / 1000).toFixed(0)}K` } }
// 百分比格式化
axis: { y: { labelFormatter: (v) => `${(v * 100).toFixed(0)}%` } }
// 货币格式化
axis: { y: { labelFormatter: (v) => `¥${v.toLocaleString()}` } }
// 日期格式化(x 轴为 Date 类型)
axis: { x: { labelFormatter: 'MM/DD' } }
// 保留两位小数(纯 d3-format,不能追加文字单位)
axis: { y: { labelFormatter: '.2f' } } // ✅ 纯 d3-format
// axis: { y: { labelFormatter: '.2f 元' } } // ❌ 无效!d3-format 后不能加文字隐藏坐标轴
// 完全隐藏某轴
axis: { x: false }
// 只隐藏标题
axis: { y: { title: false } }
// 只隐藏网格线
axis: { y: { grid: false } }修改坐标轴文本配色
chart.options({
type: 'line',
data,
encode: { x: 'date', y: 'value' },
axis: {
x: {
labelFill: '#8c8c8c', // 标签文字颜色
labelFontSize: 12,
titleFill: '#595959', // 标题文字颜色
titleFontSize: 13,
titleFontWeight: 'bold',
},
y: {
labelFill: '#8c8c8c',
titleFill: '#595959',
},
},
});网格线区域交替填充(gridAreaFill)
chart.options({
type: 'line',
data,
encode: { x: 'month', y: 'value' },
axis: {
y: {
grid: true,
gridAreaFill: ['rgba(0,0,0,0.04)', 'transparent'], // 交替填充,增强可读性
gridLineWidth: 0, // 隐藏网格线本身,只显示区域色
},
},
});
// 也可以用函数控制
axis: {
y: {
gridAreaFill: (datum, index) => index % 2 === 0 ? 'rgba(0,0,0,0.04)' : '',
},
}断轴(breaks)—— 跳过数据空洞
// 当数据中某段范围远超其他值,用断轴压缩该区间
chart.options({
type: 'interval',
data: [
{ x: 'A', y: 100 },
{ x: 'B', y: 200 },
{ x: 'C', y: 95000 }, // 异常值,导致其他柱看不清
{ x: 'D', y: 150 },
],
encode: { x: 'x', y: 'y' },
axis: {
y: {
breaks: [
{
start: 500, // 断轴起点
end: 90000, // 断轴终点(跳过这段区间)
gap: '3%', // 断轴占画布高度比例
},
],
},
},
});双 y 轴
// 使用 view 容器 + 不同 y 比例尺实现双轴
chart.options({
type: 'view',
data,
children: [
{
type: 'interval',
encode: { x: 'month', y: 'revenue' },
axis: { y: { title: '收入', position: 'left' } },
},
{
type: 'line',
encode: { x: 'month', y: 'growth' },
scale: { y: { key: 'right' } },
axis: { y: { title: '增速', position: 'right' } },
},
],
});---
常见错误与修正
错误 1:axis 写在 encode 或 scale 里
// ❌ 错误:axis 是独立的顶级字段
chart.options({
encode: { x: 'month', y: 'value' },
scale: { x: { title: '月份' } }, // title 不在 scale 里
});
// ✅ 正确:axis 是与 encode/scale 平级的字段
chart.options({
encode: { x: 'month', y: 'value' },
axis: { x: { title: '月份' } },
});错误 2:样式属性名错误
// ❌ 错误的属性名
axis: { x: { fontSize: 12 } } // 不存在
// ✅ 正确的属性名(带前缀)
axis: { x: { labelFontSize: 12 } } // 标签字体大小
axis: { x: { titleFontSize: 14 } } // 标题字体大小错误 3:混淆轴标题与图表标题
// ❌ 轴标题写在 title 里
title: { title: '月份' } // 这是图表标题
// ✅ 轴标题在 axis 里
axis: { x: { title: '月份' } } // 这是 X 轴标题错误 4:用 tickFormatter 格式化标签文字
// ❌ 错误:tickFormatter 返回的是 DisplayObject(图形对象),不是字符串
axis: {
y: {
tickFormatter: (v) => `${v / 1000}K`, // ❌ 返回字符串给 tickFormatter 无效
},
}
// ✅ 正确:标签文字格式化用 labelFormatter
axis: {
y: {
labelFormatter: (v) => `${v / 1000}K`, // ✅ labelFormatter 返回 string
},
}错误 5:在 scale.tickMethod 里格式化标签或接收 scale 对象
// ❌ 错误:tickMethod 参数不是 scale 对象,返回值不是对象数组
scale: {
y: {
tickMethod: (scale) => { // ❌ 参数不是 scale 对象
return scale.ticks().map(v => ({ // ❌ scale.ticks() 不存在
value: v, text: `${v}K` // ❌ 不能返回对象,只能返回 number[]
}));
},
},
}
// ✅ 正确:tickMethod 签名是 (min, max, count) => number[]
// 格式化文字另用 labelFormatter
scale: {
y: {
tickMethod: (min, max, count) => [100, 500, 1000, 5000, 10000], // ✅ number[]
},
},
axis: {
y: {
labelFormatter: (v) => `${v / 1000}K`, // ✅ 文字格式化在 axis
},
}错误 6:labelFormatter 用 d3-format 字符串拼接单位
labelFormatter 与 tooltip.items[].valueFormatter 一样,支持函数或 d3-format 字符串两种形式。d3-format 字符串只格式化数字,不能在后面追加文字单位——'.2f 元'、'.0f 米' 是无效写法。
// ❌ 错误:d3-format 字符串后追加文字单位
axis: {
y: { labelFormatter: '.2f 元' }, // ❌ d3-format 不支持拼接文字,标签异常
x: { labelFormatter: '.0f 米' }, // ❌ 同上
}
// ✅ 正确:需要拼接单位时必须用函数形式
axis: {
y: { labelFormatter: (v) => `${v.toFixed(2)} 元` }, // ✅ 函数,可拼接任意文字
x: { labelFormatter: (v) => `${Math.round(v)} 米` }, // ✅ 函数
}
// ✅ 纯数字格式化(不加单位)可用 d3-format 字符串
axis: {
y: { labelFormatter: '.2f' }, // ✅ 保留两位小数
x: { labelFormatter: ',.0f' }, // ✅ 千分位整数
z: { labelFormatter: '.1%' }, // ✅ 百分比
}错误 7:labelFormatter 回调函数签名错误
labelFormatter 的回调函数签名应为 (datum, index, array) => string,其中:
datum: 当前刻度值(通常是数值或字符串)index: 当前刻度索引array: 所有刻度值组成的数组
// ❌ 错误:参数顺序错误或使用了不存在的参数
axis: {
x: {
labelFormatter: (task, item) => { // ❌ item 参数不存在
return `${item.data.stage}-${task}`;
}
}
}
// ✅ 正确:使用正确的参数签名
axis: {
x: {
labelFormatter: (datum, index, array) => {
// 注意:此时 datum 是原始数据中的字段值,不是整个数据项
return `${datum}`; // 返回字符串即可
}
}
}
// ✅ 更推荐的做法:在 encode 中预处理复合标签
chart.options({
encode: {
x: (d) => `${d.stage} - ${d.task}`, // 在 encode 中构造复合标签
y: 'start',
y1: 'end'
},
axis: {
x: {
labelTransform: 'rotate(30)' // 如需旋转标签防止重叠
}
}
});错误 8:legend.labelFormatter 与 axis.labelFormatter 混淆
虽然两者都用于格式化标签,但它们作用的对象不同。legend.labelFormatter 用于图例标签,而 axis.labelFormatter 用于坐标轴刻度标签。
// ❌ 错误:在 legend 中使用 axis.labelFormatter
legend: {
color: {
labelFormatter: '.0%' // ❌ legend 不支持 axis 的 labelFormatter
}
}
// ✅ 正确:legend 使用自己的 labelFormatter
legend: {
color: {
labelFormatter: (value) => `${Math.round(value)}%` // ✅ 函数形式
}
}错误 9:tooltip.valueFormatter 与 axis.labelFormatter 混淆
tooltip.valueFormatter 用于格式化提示框中的值,而 axis.labelFormatter 用于坐标轴标签。
// ❌ 错误:在 tooltip.items 中使用 axis.labelFormatter
tooltip: {
items: [
{ channel: 'y', labelFormatter: '.2f' } // ❌ tooltip.items 不支持 labelFormatter
]
}
// ✅ 正确:tooltip.items 使用 valueFormatter
tooltip: {
items: [
{ channel: 'y', valueFormatter: '.2f' } // ✅ 使用 valueFormatter
]
}错误 10:cell 图表中 style.inset 设置不当导致渲染空白
在 cell 类型图表中,style.inset 控制单元格的内边距。如果设置过大,可能导致单元格不可见。
// ❌ 错误:inset 设置过大
chart.options({
type: 'cell',
data,
encode: { x: 'x', y: 'y', color: 'value' },
style: {
inset: 10 // ❌ inset 太大,可能使矩形不可见
}
});
// ✅ 正确:合理设置 inset
chart.options({
type: 'cell',
data,
encode: { x: 'x', y: 'y', color: 'value' },
style: {
inset: 0.5 // ✅ 合理的 inset 值
}
});错误 11:legend.layout 配置错误导致布局异常
legend.layout 使用 Flexbox 布局模型,若配置不当会影响图例排版。
// ❌ 错误:justifyContent 写错或不支持的值
legend: {
color: {
layout: { justifyContent: 'centered' } // ❌ 不支持的值
}
}
// ✅ 正确:使用合法的 Flexbox 值
legend: {
color: {
layout: { justifyContent: 'center' } // ✅ 正确值
}
}---
深色背景适配:深色背景下坐标轴标签/标题不可见时,使用theme: 'classicDark'一行解决,或手动设置labelFill/titleFill。详见 深色主题适配
核心概念
AxisRadar 是雷达图专用的坐标轴组件:
- 在极坐标系中显示放射状的轴线
- 支持多个维度的轴标签
- 自动计算轴的角度和位置
特点:
- 自动连接各轴形成网格
- 支持自定义轴样式
- 与极坐标系配合使用
最小可运行示例
import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
width: 640,
height: 480,
});
chart.options({
type: 'line',
coordinate: { type: 'polar' },
data: [
{ item: 'Design', score: 70 },
{ item: 'Development', score: 60 },
{ item: 'Marketing', score: 50 },
{ item: 'Sales', score: 80 },
{ item: 'Support', score: 90 },
],
encode: {
x: 'item',
y: 'score',
},
axis: {
x: {
// 雷达图 X 轴配置
title: false,
tickLine: null,
},
y: {
// 雷达图 Y 轴(放射状轴)
title: 'Score',
grid: true,
gridConnect: 'line', // 网格连接方式
},
},
});
chart.render();常用变体
自定义网格样式
chart.options({
type: 'line',
coordinate: { type: 'polar' },
data,
encode: { x: 'item', y: 'score' },
axis: {
y: {
grid: true,
gridConnect: 'line',
gridLineWidth: 1,
gridStroke: '#e8e8e8',
gridType: 'line',
},
},
});隐藏轴线
chart.options({
type: 'line',
coordinate: { type: 'polar' },
data,
encode: { x: 'item', y: 'score' },
axis: {
x: { line: null },
y: { line: null },
},
});自定义标签
chart.options({
type: 'line',
coordinate: { type: 'polar' },
data,
encode: { x: 'item', y: 'score' },
axis: {
x: {
labelFormatter: (val) => val.toUpperCase(),
labelSpacing: 10,
},
y: {
labelFormatter: (val) => `${val}%`,
},
},
});完整类型参考
interface AxisRadarOptions {
// 基础配置
title?: string | { text: string; style?: object };
tickLine?: null | { length?: number; style?: object };
line?: null | { style?: object };
// 标签配置
labelFormatter?: string | ((val: any) => string);
labelSpacing?: number;
labelStyle?: object;
// 网格配置
grid?: boolean;
gridConnect?: 'line' | 'curve'; // 网格连接方式
gridLineWidth?: number;
gridStroke?: string;
gridType?: 'line' | 'circle';
// 雷达图特有
radar?: {
count: number; // 轴的数量
index: number; // 当前轴的索引
};
}与普通坐标轴的区别
| 特性 | 普通坐标轴 | 雷达图坐标轴 |
|---|---|---|
| 坐标系 | 直角坐标 | 极坐标 |
| 轴方向 | 水平/垂直 | 放射状 |
| 网格 | 矩形 | 多边形/圆形 |
| 标签位置 | 轴两端 | 轴末端外侧 |
常见错误与修正
错误 1:未使用极坐标系
// ❌ 错误:雷达图轴需要极坐标系
chart.options({
type: 'line',
data,
encode: { x: 'item', y: 'score' },
axis: { y: { gridConnect: 'line' } },
});
// ✅ 正确:添加极坐标系
chart.options({
type: 'line',
coordinate: { type: 'polar' },
data,
encode: { x: 'item', y: 'score' },
axis: { y: { gridConnect: 'line' } },
});错误 2:gridConnect 参数错误
// ❌ 错误:gridConnect 只支持 'line' 或 'curve'
axis: { y: { gridConnect: 'polygon' } }
// ✅ 正确
axis: { y: { gridConnect: 'line' } }---
雷达图描边不显示问题
雷达图通过 coordinate: { type: 'polar' } + area + line Mark 组合实现。line Mark 在极坐标下的 stroke 依赖 color scale 推导——如果未显式设置 lineWidth,部分主题/场景下描边可能不可见。
// ❌ 错误:line mark 未设置 lineWidth,在某些主题下描边不可见
chart.options({
type: 'view',
data,
coordinate: { type: 'polar' },
children: [
{ type: 'area', encode: { x: 'item', y: 'score', color: 'type' }, style: { fillOpacity: 0.2 } },
{ type: 'line', encode: { x: 'item', y: 'score', color: 'type' } }, // ❌ 缺少 lineWidth
],
});
// ✅ 正确:显式设置 lineWidth
chart.options({
type: 'view',
data,
coordinate: { type: 'polar' },
children: [
{ type: 'area', encode: { x: 'item', y: 'score', color: 'type' }, style: { fillOpacity: 0.2 } },
{ type: 'line', encode: { x: 'item', y: 'score', color: 'type' }, style: { lineWidth: 2 } },
],
});雷达图主题默认值
G2 主题中雷达图坐标轴(axisRadar)的默认值:
| 属性 | 默认值 | 说明 |
|---|---|---|
gridStrokeOpacity | 0.3 | 网格线透明度 |
gridType | 'surround' | 环绕式网格 |
tick | false | 不显示刻度线 |
titlePosition | 'start' | 标题在轴起始位置 |
gridClosed | true | 网格闭合 |
深色背景适配:雷达图在深色背景下轴标签不可见时,使用theme: 'classicDark'一行解决,或手动设置各轴labelFill/gridStroke。详见 深色主题适配
基本用法
import { Chart } from '@antv/g2';
const chart = new Chart({ container: 'container', width: 640, height: 480 });
chart.options({
type: 'interval',
data,
encode: { x: 'genre', y: 'sold' },
labels: [
{
text: 'sold', // 显示哪个字段的值(字段名字符串或函数)
position: 'outside', // 标签位置
},
],
});
chart.render();常用位置说明
笛卡尔坐标系(interval / point / line / cell 等)
支持 9 种位置:top、left、right、bottom、top-left、top-right、bottom-left、bottom-right、inside。
| position 值 | 适用 Mark | 效果 |
|---|---|---|
'top' | interval | 柱体顶部(紧贴顶端) |
'right' | interval | 柱体右侧 |
'left' | interval | 柱体左侧 |
'bottom' | interval | 柱体底部 |
'inside' | interval | 柱体内部中央 |
'top-left' | interval | 柱体左上角 |
'top-right' | interval | 柱体右上角 |
'bottom-left' | interval | 柱体左下角 |
'bottom-right' | interval | 柱体右下角 |
'top' | point | 点的上方 |
'right' | line | 折线末端右侧 |
非笛卡尔坐标系(arc / 饼图 / 环形图)
支持 outside、inside 两种基本位置,以及特殊位置:
| position | 用途 |
|---|---|
'outside' | 扇区外侧引线 |
'inside' | 扇区内部 |
'spider' | 调整标签沿坐标轴边沿两端对齐,适用于 polar 坐标系(饼图/环形图) |
'surround' | 调整标签环形环绕坐标系,适用于玫瑰图 |
'area' | 将面积图的标签显示在面积区域中心,并设置一定的旋转角度 |
格式化标签文本
labels: [
{
// 推荐:text 函数方式,可访问完整数据行 datum
text: (d) => `${d.sold.toLocaleString()} 万`,
// 或字符串字段名(自动取该字段的值)
// text: 'sold',
},
],formatter 用法(仅格式化已取值的文本)
formatter 接收的第一个参数是 text 已映射的值(非完整 datum),适合对数值进行简单格式化:
labels: [
{
text: 'yield_rate', // 先映射字段 yield_rate 的值
formatter: (val) => `${val}%`, // val 是 yield_rate 的值,非 datum 对象
},
],完整签名:formatter(text, datum, index, data) => string
完整 label 配置项
labels: [
{
text: (d) => d.value.toFixed(1), // 标签文本(推荐用函数直接访问 datum)
position: 'outside', // 位置
// ── 样式(可直接在 label 上配置,也可通过 style 嵌套) ──
fill: '#333',
fontSize: 12,
fontWeight: 'bold',
textAlign: 'center',
lineHeight: 20,
dy: -4, // y 方向偏移(px)
dx: 0, // x 方向偏移
// ── 选择器(只显示部分标签)──────────────
selector: 'last', // 'first' | 'last' | (labels) => filteredLabels
// 过滤(只对满足条件的数据显示标签)
filter: (d) => d.value > 50,
// ── 标签转换(优化标签展示)──────────────
transform: [{ type: 'overlapDodgeY' }],
// ── 连接线(饼图 spider/surround 位置时常用)──
connectorDistance: 5,
connectorStroke: '#aaa',
connectorLineWidth: 1,
// ── 背景框 ───────────────────────────────
background: true,
backgroundFill: '#fff',
backgroundRadius: 4,
backgroundPadding: [8, 12],
},
],selector 选择器
selector 用于选择需要保留显示的标签,支持三种方式:
labels: [
{
text: 'Symbol',
selector: 'first', // 方式一:预置 'first' / 'last'
style: { fill: 'blue' },
},
{
text: 'Symbol',
selector: 'last', // 最后一个
style: { fill: 'red' },
},
{
text: 'Symbol',
selector: (labels) => { // 方式二:自定义函数,参数为所有 label 数组
// labels 内含 bounds 坐标等信息,可用于过滤
return labels.filter(({ bounds }) => {
const [x, y] = bounds[0];
return x > 200 && x < 300 && y > 200 && y < 350;
});
},
style: { fill: '#ac1ce6' },
},
],selector 支持的值:
'first'— 保留第一个标签'last'— 保留最后一个标签(labels) => filteredLabels— 自定义选择器函数,接收全部 label 信息数组,可基于坐标等信息过滤
标签转换(transform)
当标签的展示不符合预期时(如重叠、颜色不明显、溢出等),可以使用标签转换(Label Transform) 来优化标签的展示。
transform 配置方式
标签转换支持两种配置层级:
方式一:在 labels 数组中的单个 label 上配置(推荐)
labels: [
{
text: 'value',
transform: [{ type: 'overlapDodgeY' }],
},
],方式二:在 view 层级通过 labelTransform 全局配置
在 view 层级通过 labelTransform 声明标签转换,作用于该视图下所有标签:
chart.options({
type: 'view',
labelTransform: [{ type: 'overlapHide' }, { type: 'contrastReverse' }],
});标签转换类型一览
| type | 描述 |
|---|---|
| overlapDodgeY | 对位置碰撞的标签在 y 方向上调整,防止标签重叠 |
| contrastReverse | 标签颜色在图形背景上对比度低时,从指定色板选择最优对比颜色 |
| overflowStroke | 标签溢出图形时,从指定色板选择对比度最优的颜色进行描边 |
| overflowHide | 对于标签在图形上放置不下时,隐藏标签 |
| overlapHide | 对位置碰撞的标签进行隐藏,默认保留前一个、隐藏后一个 |
| exceedAdjust | 自动对标签做溢出检测和矫正,超出指定区域时做反方向位移 |
overlapDodgeY — 防重叠(y 方向调整)
对位置碰撞的标签在 y 方向上做位置调整,适合折线图等标签密集场景。
labels: [
{
text: 'price',
transform: [{ type: 'overlapDodgeY' }],
},
],| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| maxIterations | 位置调整的最大迭代次数 | _number_ | 10 |
| padding | 期望调整后标签之间的间距 | _number_ | 1 |
| maxError | 最大误差(实际间距与期望 padding 的误差) | _number_ | 0.1 |
contrastReverse — 对比度反转
标签颜色在图形背景上对比度低时,从指定色板自动选择一个对比度最优的颜色。适用于多颜色的柱状图中颜色和标签接近的场景。
labels: [
{
text: 'genre',
transform: [{ type: 'contrastReverse' }],
},
],| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| threshold | 标签和背景的颜色对比度阈值,超过阈值才推荐提升对比度 | _number_ | 4.5 |
| palette | 对比度提升算法中备选的颜色色板 | _string[]_ | ['#000', '#fff'] |
可以同时搭配 overflowStroke 使用:
labels: [
{
text: 'frequency',
transform: [
{ type: 'contrastReverse' },
{ type: 'overflowStroke' },
],
},
],overflowStroke — 溢出描边
类似字幕黑底白字原理,从指定色板选择一个与标签颜色对比度最优的颜色进行描边,解决标签溢出图形后可读性变差的问题。
labels: [
{
text: 'frequency',
transform: [{ type: 'overflowStroke' }],
},
],| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| threshold | 溢出阈值,越大越不容易触发描边 | _number_ | 2 |
| palette | 描边备选的颜色色板 | _string[]_ | ['#000', '#fff'] |
overflowHide — 溢出隐藏
对于标签在图形上放不下的时候,隐藏标签。适用于每个小图形都映射有 label 标签导致重叠不清的场景(如旭日图、矩形树图等)。
与 overlapDodgeY 的区别:overflowHide针对 label 与 mark 图形之间的溢出问题;overlapDodgeY针对多个 label 之间的重叠问题。
labels: [
{
text: 'name',
transform: [{ type: 'overflowHide' }],
},
],overlapHide — 碰撞隐藏
对位置碰撞的标签进行隐藏,默认保留前一个,隐藏后一个。和 overlapDodgeY 的区别在于 overlapHide 直接隐藏而不是移动位置。
labels: [
{
text: 'price',
transform: [{ type: 'overlapHide' }],
},
],exceedAdjust — 溢出矫正
自动对标签做溢出检测和矫正,当标签超出指定区域时自动做反方向位移。
labels: [
{
text: 'tooltip',
transform: [{ type: 'exceedAdjust' }], // 默认检测 view 边界
},
],// 带完整配置
labels: [
{
text: 'tooltip',
transform: [{
type: 'exceedAdjust',
bounds: 'main', // 检测主区域边界
offsetX: 15, // X 轴偏移附加值
offsetY: 10, // Y 轴偏移附加值
}],
},
],| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| bounds | 指定检测边界的区域类型(5.3.4 开始支持)。'view' 为整个视图区域;'main' 为主区域 | `'view' \ | 'main'` |
| offsetX | 触发自动调整位置时 X 轴偏移附加值(左侧边界向右,右侧边界向左) | _number_ | 0 |
| offsetY | 触发自动调整位置时 Y 轴偏移附加值(上侧边界向下,下侧边界向上) | _number_ | 0 |
标签背景框(background)
标签可以配置背景框样式,格式为 background${style},如 backgroundFill 代表背景框填充色。需要设置 background: true 开启。
labels: [
{
text: 'value',
background: true,
backgroundFill: '#fff',
backgroundRadius: 4,
backgroundPadding: [10, 10, 10, 10],
backgroundOpacity: 0.8,
backgroundStroke: '#000',
backgroundLineWidth: 1,
},
],背景框配置项
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| backgroundFill | 背景框填充色 | _string_ | - |
| backgroundFillOpacity | 背景框填充透明度 | _number_ | - |
| backgroundStroke | 背景框描边 | _string_ | - |
| backgroundStrokeOpacity | 背景框描边透明度 | _number_ | - |
| backgroundLineWidth | 背景框描边宽度 | _number_ | - |
| backgroundLineDash | 背景框描边虚线配置 | _[number,number]_ | - |
| backgroundOpacity | 背景框整体透明度 | _number_ | - |
| backgroundShadowColor | 背景框阴影颜色 | _string_ | - |
| backgroundShadowBlur | 背景框阴影模糊系数 | _number_ | - |
| backgroundShadowOffsetX | 背景框阴影水平偏移 | _number_ | - |
| backgroundShadowOffsetY | 背景框阴影垂直偏移 | _number_ | - |
| backgroundCursor | 鼠标样式 | _string_ | default |
| backgroundRadius | 背景框圆角半径 | _number_ | - |
| backgroundPadding | 背景框内边距 | _number[]_ | - |
推荐 Label Transform 组合
不同场景下的最佳 transform 组合,避免标签可见性问题:
柱状图 inside label(多色柱)
多色柱状图的 label 放在柱体内部时,必须使用 contrastReverse 自动适配背景色,配合 overflowHide 隐藏放不下的标签:
labels: [
{
text: 'value',
position: 'inside',
transform: [{ type: 'contrastReverse' }, { type: 'overflowHide' }],
},
]折线图末端标签(密集系列)
多系列折线图末端标签容易重叠,用 overlapDodgeY 在 Y 方向自动避让,exceedAdjust 防止溢出边界:
labels: [
{
text: 'type',
selector: 'last',
position: 'right',
transform: [{ type: 'overlapDodgeY' }, { type: 'exceedAdjust' }],
},
]饼图外侧标签
饼图 spider 或 outside 位置的标签可能重叠,用 overlapHide 隐藏碰撞标签:
labels: [
{
text: (d) => `${d.name}: ${d.value}%`,
position: 'spider',
transform: [{ type: 'overlapHide' }],
},
]堆叠图 / TreeMap / 旭日图
空间有限的 mark 使用 overflowHide 隐藏放不下的标签,配合 contrastReverse 确保可读性:
labels: [
{
text: 'name',
position: 'inside',
transform: [{ type: 'contrastReverse' }, { type: 'overflowHide' }],
},
]通用安全组合(适用于大多数场景)
不确定该用哪种 transform 时,以下组合覆盖最常见的标签问题:
labels: [
{
text: 'field',
transform: [{ type: 'overlapHide' }, { type: 'exceedAdjust' }],
},
]innerHTML / render 自定义 HTML 标签
除了 text 字段映射,还可以使用 innerHTML 或 render 渲染自定义 HTML 内容。
labels: [
{
// innerHTML 自定义,返回 string 或 HTMLElement
innerHTML: ({ genre, sold }) =>
`<div style="padding:0 4px;border-radius:10px;background:#f5f5f5;border:2px solid #5ea9e6;font-size:11px;">${genre}:${sold}</div>`,
dx: 10,
dy: 50,
style: { fill: 'rgba(0,0,0,0)', color: '#333' },
},
],注意:innerHTML和text同时配置时text会失效。render与innerHTML数据类型一致,传参略有区别:
```ts
type RenderFunc = (text: string, datum: object, index: number, { channel: Record<string, Channel> }) => String | HTMLElement;
```
连接线完整样式(connector)
在饼图和环形图等非笛卡尔坐标系下,使用 position: 'spider' 或 'surround' 时会展示连接线元素。连接线样式格式为 connector${style}。
labels: [
{
text: 'id',
position: 'spider',
connectorDistance: 5, // 文本和连接线的间距
connectorStroke: '#0649f2', // 连接线颜色
connectorLineWidth: 1, // 连接线宽度
connectorLineDash: [3, 4], // 虚线配置
connectorOpacity: 0.8, // 透明度
},
],| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| connectorStroke | 连接线颜色 | _string_ | - |
| connectorStrokeOpacity | 连接线透明度 | _number_ | - |
| connectorLineWidth | 连接线描边宽度 | _number_ | - |
| connectorLineDash | 连接线虚线配置 | _[number,number]_ | - |
| connectorOpacity | 连接线整体透明度 | _number_ | - |
| connectorShadowColor | 连接线阴影颜色 | _string_ | - |
| connectorShadowBlur | 连接线阴影模糊系数 | _number_ | - |
| connectorShadowOffsetX | 连接线阴影水平偏移 | _number_ | - |
| connectorShadowOffsetY | 连接线阴影垂直偏移 | _number_ | - |
| connectorCursor | 鼠标样式 | _string_ | default |
| connectorDistance | 连接线和文本距离 | _number_ | - |
折线末端标签
// 只在每条折线的最后一个点显示系列名称
chart.options({
type: 'line',
data,
encode: { x: 'month', y: 'value', color: 'type' },
labels: [
{
text: 'type', // 显示系列名
selector: 'last', // 只在最后一个数据点显示
position: 'right',
style: { fontSize: 11 },
},
],
});堆叠柱中心标签
chart.options({
type: 'interval',
data,
encode: { x: 'month', y: 'value', color: 'type' },
transform: [{ type: 'stackY' }],
labels: [
{
text: (d) => d.value >= 30 ? d.value : '', // 数值太小时不显示
position: 'inside',
style: { fill: 'white', fontSize: 11 },
},
],
});常见错误与修正
错误:Spec 模式中写成 label(单数)
// ❌ 错误:链式 API 是 .label(),但 Spec 模式是 labels(复数,且是数组)
chart.options({ label: { text: 'value' } });
// ✅ 正确:Spec 中用 labels 数组
chart.options({ labels: [{ text: 'value' }] });错误:text 传入了数字常量
// ❌ 错误:text 为数字 0,所有标签显示 '0'
chart.options({ labels: [{ text: 0 }] });
// ✅ 正确:text 应为字段名字符串或函数
chart.options({ labels: [{ text: 'value' }] });
chart.options({ labels: [{ text: (d) => d.value.toFixed(1) }] });错误:formatter 中把第一个参数当成 datum
// ❌ 错误:formatter 的第一个参数是已映射的文本值,不是 datum
labels: [{
text: 'yield_rate',
formatter: (d) => `${d.yield_rate}%`, // d 是数值,d.yield_rate 为 undefined
}]
// ✅ 方案一:用 text 函数直接访问 datum(推荐)
labels: [{
text: (d) => `${d.yield_rate}%`,
}]
// ✅ 方案二:formatter 正确用法(参数是已取值的文本)
labels: [{
text: 'yield_rate',
formatter: (val) => `${val}%`, // val 是 yield_rate 的值
}]核心概念
LegendCategory 是分类图例组件:
- 显示离散类别的图例项
- 每项包含图标和标签
- 支持交互(点击筛选、hover 高亮)
特点:
- 自动从 color/shape 通道推断
- 支持水平和垂直布局
- 支持自定义图标
最小可运行示例
import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
width: 640,
height: 480,
});
chart.options({
type: 'interval',
data: [
{ category: 'A', type: 'X', value: 100 },
{ category: 'A', type: 'Y', value: 150 },
{ category: 'B', type: 'X', value: 120 },
{ category: 'B', type: 'Y', value: 180 },
],
encode: {
x: 'category',
y: 'value',
color: 'type',
},
legend: {
color: {
position: 'top',
layout: {
justifyContent: 'center',
},
},
},
});
chart.render();常用变体
垂直布局
chart.options({
type: 'interval',
data,
encode: { x: 'category', y: 'value', color: 'type' },
legend: {
color: {
position: 'right',
layout: {
flexDirection: 'column',
},
},
},
});自定义标签格式
chart.options({
type: 'interval',
data,
encode: { x: 'category', y: 'value', color: 'type' },
legend: {
color: {
labelFormatter: (val) => `类型: ${val}`,
},
},
});添加标题
chart.options({
type: 'interval',
data,
encode: { x: 'category', y: 'value', color: 'type' },
legend: {
color: {
title: '类型',
position: 'top',
},
},
});自定义图标
chart.options({
type: 'interval',
data,
encode: { x: 'category', y: 'value', color: 'type' },
legend: {
color: {
itemMarker: 'square', // 'circle' | 'square' | 'line' | ...
itemMarkerSize: 12,
},
},
});网格布局
chart.options({
type: 'interval',
data,
encode: { x: 'category', y: 'value', color: 'type' },
legend: {
color: {
cols: 3, // 每行显示 3 项
layout: { justifyContent: 'center' },
},
},
});禁用交互
chart.options({
type: 'interval',
data,
encode: { x: 'category', y: 'value', color: 'type' },
legend: {
color: {
itemMarker: 'circle',
},
},
interaction: {
legendFilter: false, // 禁用点击筛选
},
});完整类型参考
interface LegendCategoryOptions {
// 位置和布局
position?: 'top' | 'bottom' | 'left' | 'right' | 'center';
layout?: {
flexDirection?: 'row' | 'column';
justifyContent?: 'flex-start' | 'center' | 'flex-end';
flexWrap?: 'wrap' | 'nowrap';
};
cols?: number; // 网格布局列数
// 标题
title?: string | string[];
// 图标
itemMarker?: string | ((id: any, index: number) => string);
itemMarkerSize?: number;
itemMarkerLineWidth?: number;
itemSpacing?: number;
// 标签
labelFormatter?: string | ((val: any) => string);
maxItemWidth?: number;
// 样式
style?: {
fill?: string;
fontSize?: number;
// 更多样式...
};
// 其他
dx?: number;
dy?: number;
}与连续图例的区别
| 特性 | 分类图例 | 连续图例 |
|---|---|---|
| 数据类型 | 离散类别 | 连续数值 |
| 显示方式 | 图标 + 标签列表 | 色带 + 刻度 |
| 交互 | 点击筛选 | 无筛选 |
| 适用场景 | 分类数据 | 数值映射 |
常见错误与修正
错误 1:position 参数错误
// ❌ 错误:position 应该是预定义值
legend: { color: { position: 'top-left' } }
// ✅ 正确
legend: { color: { position: 'top' } }错误 2:未映射 color 通道
// ❌ 错误:没有 color 通道,图例不会显示
chart.options({
type: 'interval',
data,
encode: { x: 'category', y: 'value' },
legend: { color: { position: 'top' } },
});
// ✅ 正确:添加 color 通道
chart.options({
type: 'interval',
data,
encode: { x: 'category', y: 'value', color: 'type' },
legend: { color: { position: 'top' } },
});错误 3:itemMarker 类型错误
// ❌ 错误:itemMarker 应该是预定义形状名或函数
legend: { color: { itemMarker: 'triangle-up' } }
// ✅ 正确:使用支持的形状
legend: { color: { itemMarker: 'triangle' } }
// 或
legend: { color: { itemMarker: (id, i) => i === 0 ? 'circle' : 'square' } }基本用法
import { Chart } from '@antv/g2';
const chart = new Chart({ container: 'container', width: 640, height: 480 });
chart.options({
type: 'interval',
data,
encode: { x: 'month', y: 'value', color: 'type' },
legend: {
color: { // 对应 encode.color 通道的图例
position: 'bottom', // 'top'(默认) | 'bottom' | 'left' | 'right'
},
},
});
chart.render();---
增量修改配置
如果已有图表,只想修改某个配置项(如图例位置),可以使用以下方式:
// 方式一:重新调用 options,只传需要修改的配置
chart.options({
legend: {
color: {
position: 'right', // 只修改位置
},
},
});
chart.render(); // 需要重新渲染
// 方式二:完整配置后修改
const options = {
type: 'interval',
data,
encode: { x: 'month', y: 'value', color: 'type' },
legend: { color: { position: 'top' } },
};
chart.options(options);
// 后续修改
options.legend = { color: { position: 'bottom' } };
chart.options(options);
chart.render();---
完整配置项参考
通用配置(分类图例 & 连续图例)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
position | 图例位置 | `'top' \ | 'right' \ |
orientation | 图例朝向 | `'horizontal' \ | 'vertical'` |
layout | Flex 布局配置 | { justifyContent, alignItems, flexDirection } | - |
size | 图例容器尺寸 | number | - |
length | 图例容器长度 | number | - |
crossPadding | 图例到图表区域的距离 | number | 12 |
order | 布局排序 | number | 1 |
title | 图例标题 | `string \ | string[]` |
分类图例配置
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
cols | 每行显示的图例项数量 | number | - |
colPadding | 图例项横向间隔 | number | 12 |
rowPadding | 图例项纵向间隔 | number | 8 |
maxRows | 图例最大行数 | number | 3 |
maxCols | 图例最大列数 | number | 3 |
itemWidth | 图例项宽度 | number | - |
itemSpan | 图例项图标、标签、值的空间划分 | `number \ | number[]` |
itemSpacing | 图例项内部间距 | `number \ | number[]` |
focus | 是否启用图例聚焦 | boolean | false |
focusMarkerSize | 图例聚焦图标大小 | number | 12 |
defaultSelect | 默认选中的图例项 | string[] | - |
图例项图标样式(itemMarker)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
itemMarker | 图例项图标 | `string \ | (datum, index, data) => string` |
itemMarkerSize | 图标大小 | number | 8 |
itemMarkerFill | 图标填充色 | string | - |
itemMarkerFillOpacity | 图标填充透明度 | number | - |
itemMarkerStroke | 图标描边 | string | - |
itemMarkerStrokeOpacity | 图标描边透明度 | number | - |
itemMarkerLineWidth | 图标描边宽度 | number | - |
itemMarkerRadius | 图标圆角 | number | - |
图例项标签样式(itemLabel)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
itemLabelFill | 标签文字填充色 | string | #333 |
itemLabelFillOpacity | 标签文字填充透明度 | number | - |
itemLabelFontSize | 标签文字大小 | number | 12 |
itemLabelFontFamily | 标签文字字体 | string | - |
itemLabelFontWeight | 标签字体粗细 | `number \ | string` |
itemLabelTextAlign | 标签水平对齐方式 | string | - |
itemLabelTextBaseline | 标签垂直基线 | string | - |
itemLabelStroke | 标签文字描边 | string | - |
itemLabelLineWidth | 标签文字描边宽度 | number | - |
itemLabelDx | 标签水平偏移量 | number | - |
itemLabelDy | 标签垂直偏移量 | number | - |
图例项值样式(itemValue)
图例项右侧可以额外显示一个"值"列(通过 formatter 或数据字段),适合显示数量、百分比等辅助信息。
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
itemValueFill | 值文字填充色 | string | #1D2129 |
itemValueFillOpacity | 值文字填充透明度 | number | 0.65 |
itemValueFontSize | 值文字大小 | number | 12 |
itemValueFontFamily | 值文字字体 | string | - |
itemValueFontWeight | 值文字字体粗细 | `number \ | string` |
itemValueStroke | 值文字描边 | string | - |
itemValueLineWidth | 值文字描边宽度 | number | - |
图例项背景样式(itemBackground)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
itemBackgroundFill | 图例项背景填充色 | string | - |
itemBackgroundFillOpacity | 图例项背景填充透明度 | number | - |
itemBackgroundStroke | 图例项背景描边 | string | - |
itemBackgroundStrokeOpacity | 图例项背景描边透明度 | number | - |
itemBackgroundLineWidth | 图例项背景描边宽度 | number | - |
itemBackgroundRadius | 图例项背景圆角 | number | - |
图例标题样式(title)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
titleFill | 标题填充色 | string | #666 |
titleFillOpacity | 标题填充透明度 | number | - |
titleFontSize | 标题字体大小 | number | 12 |
titleFontFamily | 标题字体 | string | - |
titleFontWeight | 标题字体粗细 | `number \ | string` |
titleStroke | 标题描边 | string | - |
titleLineWidth | 标题描边宽度 | number | - |
titleSpacing | 标题与图例项的间距 | number | - |
连续图例配置
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
color | 色带颜色 | string[] | - |
block | 是否按区间显示 | boolean | false |
type | 连续图例类型 | `'size' \ | 'color'` |
---
常用配置示例
隐藏图例
// 隐藏特定通道的图例
legend: { color: false }
// 全部隐藏(不常用)
legend: false修改图例位置和布局
chart.options({
legend: {
color: {
position: 'bottom',
layout: {
justifyContent: 'center', // 水平居中
alignItems: 'center', // 垂直居中
},
},
},
});修改图例项图标颜色
chart.options({
legend: {
color: {
itemMarkerFill: 'red', // 图标填充色
itemMarkerSize: 10, // 图标大小
itemMarkerStroke: 'darkred', // 图标描边
},
},
});修改图例标签颜色
chart.options({
legend: {
color: {
itemLabelFill: '#333',
itemLabelFontSize: 14,
itemLabelFontWeight: 'bold',
},
},
});修改图例标题样式
chart.options({
legend: {
color: {
title: '产品类型',
titleFill: '#1D2129',
titleFontSize: 14,
titleFontWeight: 'bold',
titleSpacing: 12,
},
},
});饼图图例放底部居中
chart.options({
type: 'interval',
data,
encode: { y: 'value', color: 'type' },
transform: [{ type: 'stackY' }],
coordinate: { type: 'theta', outerRadius: 0.8 },
legend: {
color: {
position: 'bottom',
layout: { justifyContent: 'center' },
},
},
});连续颜色图例(色带)
当 color 通道映射连续数值时,图例自动变为色带形式。
chart.options({
type: 'cell',
data,
encode: { x: 'x', y: 'y', color: 'value' }, // value 是连续数值
scale: { color: { palette: 'Blues' } },
legend: {
color: {
position: 'right',
length: 200,
labelFormatter: (v) => Number(v).toFixed(0), // 注意:v 可能是 string,需先转换为数字
},
},
});更多连续图例配置:连续图例详细文档 涵盖阈值图例、size 通道图例、自定义色带等高级用法。
---
常见错误与修正
错误 1:legend 写成数组
// ❌ 错误:legend 是对象,不是数组
chart.options({ legend: [{ color: { position: 'bottom' } }] });
// ✅ 正确
chart.options({ legend: { color: { position: 'bottom' } } });错误 2:legend.color 与 encode.color 不对应
// ❌ 错误:encode 没有 color 通道,配置 legend.color 无效
chart.options({
encode: { x: 'month', y: 'value' }, // 没有 color
legend: { color: { position: 'bottom' } },
});
// ✅ 正确:只有 encode.color 有映射时,legend.color 才有效
chart.options({
encode: { x: 'month', y: 'value', color: 'type' },
legend: { color: { position: 'bottom' } },
});错误 3:样式属性名错误
// ❌ 错误的属性名
legend: { color: { markerFill: 'red' } } // 不存在
// ✅ 正确的属性名(带前缀)
legend: { color: { itemMarkerFill: 'red' } } // 正确错误 4:混淆图例标题与图表标题
// ❌ 图例标题写在 axis 里
axis: { x: { title: '产品类型' } } // 这是 X 轴标题
// ✅ 图例标题在 legend 里
legend: { color: { title: '产品类型' } } // 这是图例标题---
图例与 Label 的布局冲突
饼图外侧 label + 顶部 legend 重叠
饼图使用 position: 'outside' 或 'spider' 的 label 时,标签分布在饼图周围的上下左右。如果 legend 使用默认的 position: 'top',顶部的 label 和 legend 会发生重叠。
// ❌ 错误:spider label + 默认 top legend → 上方空间冲突
chart.options({
type: 'interval',
data,
encode: { y: 'value', color: 'type' },
transform: [{ type: 'stackY' }],
coordinate: { type: 'theta' },
labels: [{ text: 'type', position: 'spider' }],
// legend 默认 'top',与顶部 spider label 重叠
});
// ✅ 方案一:legend 移到 bottom(推荐)
chart.options({
type: 'interval',
data,
encode: { y: 'value', color: 'type' },
transform: [{ type: 'stackY' }],
coordinate: { type: 'theta' },
labels: [{ text: 'type', position: 'spider' }],
legend: {
color: {
position: 'bottom',
layout: { justifyContent: 'center' },
},
},
});
// ✅ 方案二:增大 paddingTop 留出空间
chart.options({
type: 'interval',
data,
encode: { y: 'value', color: 'type' },
transform: [{ type: 'stackY' }],
coordinate: { type: 'theta' },
labels: [{ text: 'type', position: 'spider' }],
paddingTop: 60,
});适用范围:所有使用 position: 'outside' / 'spider' / 'surround' 标签的非笛卡尔坐标图(饼图、环形图、玫瑰图)。
核心概念
连续图例(Continuous Legend)展示连续数值到视觉通道(通常是颜色)的映射:
- 当
encode.color映射到连续数值字段时,图例自动变为连续图例 - 支持线性比例尺(linear)、阈值比例尺(threshold)、分位数比例尺(quantile/quantize)
- 默认显示为色带(ribbon)形式
最小可运行示例
import { Chart } from '@antv/g2';
const data = Array.from({ length: 100 }, (_, i) => ({
x: i % 10,
y: Math.floor(i / 10),
value: Math.random() * 100,
}));
const chart = new Chart({ container: 'container', width: 640, height: 400 });
chart.options({
type: 'cell',
data,
encode: { x: 'x', y: 'y', color: 'value' }, // value 是连续数值
scale: { color: { palette: 'Blues' } },
legend: {
color: {
position: 'right',
length: 200,
labelFormatter: (v) => Number(v).toFixed(0), // 注意:v 可能是 string,需先转换
},
},
});
chart.render();完整配置项
chart.options({
type: 'cell',
data,
encode: { x: 'x', y: 'y', color: 'value' },
legend: {
color: {
// ── 位置 ─────────────────────────────────
position: 'right', // 'top' | 'bottom' | 'left' | 'right'
layout: {
justifyContent: 'center',
},
// ── 尺寸 ─────────────────────────────────
length: 200, // 色带长度(px)
size: 20, // 色带宽度/高度(px)
// ── 标题 ─────────────────────────────────
title: '数值范围',
titleFontSize: 12,
// ── 标签 ─────────────────────────────────
labelFormatter: (v) => Number(v).toFixed(1), // 注意:v 可能是 string,需先转换
labelAlign: 'value', // 'value' | 'range'
// ── 样式 ─────────────────────────────────
style: {
ribbonFill: 'black', // 默认色带填充色(无颜色映射时)
},
},
},
});常用变体
阈值图例(分段色带)
// 使用 threshold/quantize/quantile 比例尺时,图例自动变为分段
chart.options({
type: 'cell',
data,
encode: { x: 'x', y: 'y', color: 'value' },
scale: {
color: {
type: 'quantize', // 分段比例尺
domain: [0, 100],
range: ['#f7fbff', '#6baed6', '#08519c'], // 3 段颜色
},
},
legend: {
color: {
position: 'right',
},
},
});水平色带
chart.options({
type: 'cell',
data,
encode: { x: 'x', y: 'y', color: 'value' },
legend: {
color: {
position: 'bottom',
length: 400,
size: 15,
layout: { justifyContent: 'center' },
},
},
});自定义色带颜色
chart.options({
type: 'cell',
data,
encode: { x: 'x', y: 'y', color: 'value' },
scale: {
color: {
type: 'linear',
domain: [0, 100],
range: ['#e6f5ff', '#0066cc'], // 渐变范围
},
},
legend: {
color: {
position: 'right',
labelFormatter: (v) => `${Number(v)}°C`, // 注意:v 可能是 string,需先转换
},
},
});size 通道图例
// size 通道也会生成连续图例
chart.options({
type: 'point',
data,
encode: { x: 'x', y: 'y', size: 'value' },
legend: {
size: {
position: 'right',
title: '大小',
},
},
});完整类型参考
interface LegendContinuousOptions {
position?: 'top' | 'bottom' | 'left' | 'right';
layout?: FlexLayout;
title?: string | string[];
length?: number; // 色带长度
size?: number; // 色带宽度
labelFormatter?: string | ((value: number) => string);
labelAlign?: 'value' | 'range';
style?: {
ribbonFill?: string;
[key: string]: any;
};
}连续图例 vs 分类图例
| 特性 | 连续图例 | 分类图例 |
|---|---|---|
| 数据类型 | 连续数值 | 离散分类 |
| 视觉形式 | 色带/块状 | 图例项列表 |
| 比例尺 | linear, threshold, quantize | band, ordinal |
| 适用场景 | 热力图、地图、气泡图 | 柱状图、折线图 |
常见错误与修正
错误 1:分类数据使用连续图例
// ❌ 问题:category 是分类字段,不应使用连续图例
encode: { color: 'category' } // 分类数据
// 连续图例显示效果不佳
// ✅ 正确:分类数据自动使用分类图例
// G2 会根据数据类型自动选择图例类型错误 2:labelFormatter 参数类型错误
// ❌ 问题:labelFormatter 的参数 v 可能是 string 类型(不是 number)
// G2 连续图例传入的刻度值为字符串,直接调用 .toFixed() 会报错
labelFormatter: (v) => v.toFixed(1) // ❌ TypeError: v.toFixed is not a function
labelFormatter: (v) => v * 100 // ❌ 返回数字而不是字符串
// ✅ 正确:先转换为数字,再格式化,最终返回字符串
labelFormatter: (v) => Number(v).toFixed(1) // ✅ 保留 1 位小数
labelFormatter: (v) => `${(Number(v) * 100).toFixed(0)}%` // ✅ 百分比格式
labelFormatter: (v) => `${parseFloat(v).toFixed(0)}m` // ✅ 带单位错误 3:length 设置过小
// ❌ 问题:色带长度太小,标签重叠
legend: { color: { length: 50 } } // 太短
// ✅ 正确:根据标签数量设置合适长度
legend: { color: { length: 200 } } // 合适与 legendCategory 的选择
- 使用连续图例:当 color/size 通道映射到连续数值字段
- 使用分类图例:当 color 通道映射到分类字段
G2 会根据比例尺类型自动选择正确的图例类型,无需手动指定。
最小可运行示例
import { Chart } from '@antv/g2';
// 50 个分类项目
const data = Array.from({ length: 50 }, (_, i) => ({
category: `类别${i + 1}`,
value: Math.random() * 100,
}));
const chart = new Chart({ container: 'container', width: 640, height: 400 });
chart.options({
type: 'interval',
data,
encode: { x: 'category', y: 'value', color: 'category' },
scrollbar: {
x: true, // 启用 X 轴滚动条
},
legend: false,
});
chart.render();---
增量修改配置
如果已有图表,只想修改某个配置项(如滑块颜色),可以使用以下方式:
// 方式一:重新调用 options,只传需要修改的配置
chart.options({
scrollbar: {
x: {
thumbFill: 'red', // 只修改滑块填充色
},
},
});
chart.render(); // 需要重新渲染
// 方式二:完整配置后修改
const options = {
type: 'interval',
data,
encode: { x: 'category', y: 'value' },
scrollbar: { x: true },
};
chart.options(options);
// 后续修改
options.scrollbar = { x: { thumbFill: 'red' } };
chart.options(options);
chart.render();---
完整配置项参考
基础配置
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
ratio | 滚动条的比例,单页显示数据在总数据量上的比例 | number | 0.5 |
value | 滚动条的起始位置(0~1),水平默认 0,垂直默认 1 | number | - |
slidable | 是否可以拖动 | boolean | true |
position | 滚动条相对图表方位 | string | 'bottom' |
isRound | 滚动条样式是否为圆角 | boolean | true |
滑块样式(thumb)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
thumbFill | 滑块填充色 | string | #000 |
thumbFillOpacity | 滑块填充透明度 | number | 0.15 |
thumbStroke | 滑块描边颜色 | string | - |
thumbLineWidth | 滑块描边宽度 | number | - |
thumbStrokeOpacity | 滑块描边透明度 | number | - |
thumbLineDash | 滑块虚线配置 | [number, number] | - |
thumbOpacity | 滑块整体透明度 | number | - |
thumbShadowColor | 滑块阴影颜色 | string | - |
thumbShadowBlur | 滑块阴影模糊系数 | number | - |
thumbShadowOffsetX | 阴影水平偏移 | number | - |
thumbShadowOffsetY | 阴影垂直偏移 | number | - |
thumbCursor | 滑块鼠标样式 | string | default |
滑轨样式(track)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
trackSize | 滑轨宽度 | number | 10 |
trackLength | 滑轨长度 | number | - |
trackFill | 滑轨填充色 | string | - |
trackFillOpacity | 滑轨填充透明度 | number | 0 |
trackStroke | 滑轨描边颜色 | string | - |
trackLineWidth | 滑轨描边宽度 | number | - |
trackStrokeOpacity | 滑轨描边透明度 | number | - |
trackLineDash | 滑轨虚线配置 | [number, number] | - |
trackOpacity | 滑轨整体透明度 | number | - |
trackShadowColor | 滑轨阴影颜色 | string | - |
trackShadowBlur | 滑轨阴影模糊系数 | number | - |
trackShadowOffsetX | 阴影水平偏移 | number | - |
trackShadowOffsetY | 阴影垂直偏移 | number | - |
trackCursor | 滑轨鼠标样式 | string | default |
---
常用配置示例
配置滚动条样式和初始位置
chart.options({
type: 'interval',
data,
encode: { x: 'date', y: 'value' },
scrollbar: {
x: {
ratio: 0.2, // 可视窗口占全部数据的比例
value: 0, // 初始滚动位置(0=最左,1=最右)
// 滑轨样式
trackSize: 14,
trackFill: '#f0f0f0',
trackFillOpacity: 1,
// 滑块样式
thumbFill: '#5B8FF9',
thumbFillOpacity: 0.5,
},
},
});修改滑块颜色为红色
chart.options({
scrollbar: {
x: {
thumbFill: 'red',
thumbFillOpacity: 0.3,
thumbStroke: 'darkred',
thumbLineWidth: 1,
},
},
});Y 轴滚动条
chart.options({
type: 'interval',
data: manyRowsData,
encode: { x: 'value', y: 'category' },
coordinate: { transform: [{ type: 'transpose' }] },
scrollbar: {
y: {
ratio: 0.3, // 每次只显示 30% 的数据
value: 0.5, // 从中间开始
},
},
});同时配置 X 和 Y 滚动条
chart.options({
type: 'interval',
data,
encode: { x: 'letter', y: 'frequency' },
scrollbar: {
x: {
ratio: 0.2,
trackSize: 14,
trackFill: '#000',
trackFillOpacity: 1,
},
y: {
ratio: 0.5,
trackSize: 12,
value: 0.1,
trackFill: '#000',
trackFillOpacity: 1,
},
},
});---
常见错误与修正
错误 1:样式属性名错误
// ❌ 错误的属性名
scrollbar: { x: { fill: 'red' } } // 不存在
// ✅ 正确的属性名(带前缀)
scrollbar: { x: { thumbFill: 'red' } } // 修改滑块颜色
scrollbar: { x: { trackFill: '#f0f0f0' } } // 修改滑轨颜色错误 2:与 slider 混淆
// scrollbar:固定窗口大小,只能移动,不能缩放
scrollbar: { x: { ratio: 0.2 } } // 总是显示 20% 的数据
// slider:可以拖拽两端调整显示范围
slider: { x: { values: [0, 0.2] } } // 可以拖拽调整到任意范围错误 3:数据量不多却使用滚动条
// ❌ 只有 10 个分类,不需要滚动条
chart.options({ scrollbar: { x: true } }); // 多余
// ✅ 通常在 > 20 个类别或时序数据较长时才考虑
// 少量数据时建议直接调整 chart.width 或坐标轴旋转标签错误 4:scrollbar 写在 style 里
// ❌ 错误:样式属性直接写在配置项,不是 style 对象里
scrollbar: { x: { style: { thumbFill: 'red' } } }
// ✅ 正确:样式属性直接写在配置项
scrollbar: { x: { thumbFill: 'red' } }最小可运行示例
import { Chart } from '@antv/g2';
const data = Array.from({ length: 200 }, (_, i) => ({
date: new Date(2020, 0, i + 1).toISOString().split('T')[0],
value: Math.sin(i / 30) * 50 + 100 + Math.random() * 20,
}));
const chart = new Chart({ container: 'container', width: 800, height: 400 });
chart.options({
type: 'line',
data,
encode: { x: 'date', y: 'value' },
slider: {
x: true, // 启用 X 轴缩略轴(默认显示全部范围)
},
});
chart.render();---
增量修改配置
如果已有图表,只想修改某个配置项(如手柄颜色),可以使用以下方式:
// 方式一:重新调用 options,只传需要修改的配置
chart.options({
slider: {
x: {
handleIconFill: 'red', // 只修改手柄图标填充色
},
},
});
chart.render(); // 需要重新渲染
// 方式二:完整配置后,在 render 前修改
const options = {
type: 'line',
data,
encode: { x: 'date', y: 'value' },
slider: { x: true },
};
chart.options(options);
// 后续修改
options.slider = { x: { handleIconFill: 'red' } };
chart.options(options);
chart.render();---
完整配置项参考
基础配置
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
values | 初始选区范围,位于 0~1 区间 | [number, number] | [0, 1] |
slidable | 是否允许拖动选取和手柄 | boolean | true |
brushable | 是否启用刷选 | boolean | true |
labelFormatter | 拖动手柄标签格式化 | (value) => string | - |
showHandle | 是否显示拖动手柄 | boolean | true |
showLabel | 是否显示拖动手柄文本 | boolean | true |
showLabelOnInteraction | 在调整手柄或刷选时才显示手柄文本 | boolean | false |
autoFitLabel | 是否自动调整拖动手柄文本位置 | boolean | true |
padding | 缩略轴内边距 | `number \ | number[]` |
选区样式(selection)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
selectionFill | 选区填充色 | string | #1783FF |
selectionFillOpacity | 选区填充透明度 | number | 0.15 |
selectionStroke | 选区描边 | string | - |
selectionStrokeOpacity | 选区描边透明度 | number | - |
selectionLineWidth | 选区描边宽度 | number | - |
selectionLineDash | 选区描边虚线配置 | [number, number] | - |
selectionOpacity | 选区整体透明度 | number | - |
selectionShadowColor | 选区阴影颜色 | string | - |
selectionShadowBlur | 选区阴影模糊系数 | number | - |
selectionShadowOffsetX | 阴影水平偏移 | number | - |
selectionShadowOffsetY | 阴影垂直偏移 | number | - |
selectionCursor | 选区鼠标样式 | string | default |
滑轨样式(track)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
trackLength | 滑轨长度 | number | - |
trackSize | 滑轨尺寸 | number | 16 |
trackFill | 滑轨填充色 | string | #416180 |
trackFillOpacity | 滑轨填充透明度 | number | 1 |
trackStroke | 滑轨描边 | string | - |
trackStrokeOpacity | 滑轨描边透明度 | number | - |
trackLineWidth | 滑轨描边宽度 | number | - |
trackLineDash | 滑轨描边虚线配置 | [number, number] | - |
trackOpacity | 滑轨整体透明度 | number | - |
trackShadowColor | 滑轨阴影颜色 | string | - |
trackShadowBlur | 滑轨阴影模糊系数 | number | - |
trackShadowOffsetX | 阴影水平偏移 | number | - |
trackShadowOffsetY | 阴影垂直偏移 | number | - |
trackCursor | 滑轨鼠标样式 | string | default |
手柄图标样式(handleIcon)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
handleIconSize | 手柄图标尺寸 | number | 10 |
handleIconRadius | 手柄图标圆角 | number | 2 |
handleIconShape | 手柄图标形状 | `string \ | (type) => DisplayObject` |
handleIconFill | 手柄图标填充色 | string | #f7f7f7 |
handleIconFillOpacity | 手柄图标填充透明度 | number | 1 |
handleIconStroke | 手柄图标描边 | string | #1D2129 |
handleIconStrokeOpacity | 手柄图标描边透明度 | number | 0.25 |
handleIconLineWidth | 手柄图标描边宽度 | number | 1 |
handleIconLineDash | 手柄图标描边虚线配置 | [number, number] | - |
handleIconOpacity | 手柄图标整体透明度 | number | - |
handleIconShadowColor | 手柄图标阴影颜色 | string | - |
handleIconShadowBlur | 手柄图标阴影模糊系数 | number | - |
handleIconShadowOffsetX | 阴影水平偏移 | number | - |
handleIconShadowOffsetY | 阴影垂直偏移 | number | - |
handleIconCursor | 手柄图标鼠标样式 | string | default |
手柄标签样式(handleLabel)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
handleLabelFontSize | 标签文字大小 | number | 12 |
handleLabelFontFamily | 标签文字字体 | string | - |
handleLabelFontWeight | 标签字体粗细 | number | normal |
handleLabelLineHeight | 标签文字行高 | number | - |
handleLabelTextAlign | 标签水平对齐方式 | string | start |
handleLabelTextBaseline | 标签垂直基线 | string | bottom |
handleLabelFill | 标签文字填充色 | string | #1D2129 |
handleLabelFillOpacity | 标签文字填充透明度 | number | 0.45 |
handleLabelStroke | 标签文字描边 | string | - |
handleLabelStrokeOpacity | 标签文字描边透明度 | number | - |
handleLabelLineWidth | 标签文字描边宽度 | number | - |
handleLabelLineDash | 标签文字描边虚线配置 | [number, number] | - |
handleLabelOpacity | 标签整体透明度 | number | - |
handleLabelShadowColor | 标签阴影颜色 | string | - |
handleLabelShadowBlur | 标签阴影模糊系数 | number | - |
handleLabelShadowOffsetX | 阴影水平偏移 | number | - |
handleLabelShadowOffsetY | 阴影垂直偏移 | number | - |
handleLabelCursor | 标签鼠标样式 | string | default |
handleLabelDx | 标签水平偏移量 | number | 0 |
handleLabelDy | 标签垂直偏移量 | number | 0 |
迷你图样式(sparkline)
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
sparklineType | 迷你图类型 | `'line' \ | 'column'` |
sparklineIsStack | 是否堆叠 | boolean | false |
sparklineRange | 值范围 | [number, number] | - |
sparklineColor | 颜色 | `string \ | string[]` |
sparklineSmooth | 平滑曲线 | boolean | false |
sparklineLineStroke | 折线颜色 | string | - |
sparklineLineStrokeOpacity | 折线透明度 | number | - |
sparklineLineLineDash | 折线虚线配置 | [number, number] | - |
sparklineAreaFill | 填充区域颜色 | string | - |
sparklineAreaFillOpacity | 填充区域透明度 | number | - |
sparklineColumnFill | 直方图条形颜色 | string | - |
sparklineColumnFillOpacity | 直方图条形透明度 | number | - |
sparklineIsGroup | 是否分组显示 | boolean | false |
sparklineSpacing | 分组直方间距 | number | 0 |
---
常用配置示例
设置初始显示范围
chart.options({
type: 'line',
data,
encode: { x: 'date', y: 'value' },
slider: {
x: {
values: [0.5, 1.0], // 初始显示后 50% 的数据
},
},
});修改手柄图标为红色
chart.options({
slider: {
x: {
handleIconFill: 'red',
handleIconStroke: 'darkred',
handleIconSize: 12,
},
},
});自定义手柄图标形状
import { Circle } from '@antv/g';
chart.options({
slider: {
x: {
handleIconShape: (type) => {
// type 为 'start' 或 'end',分别表示左右手柄
return new Circle({
style: {
r: 8,
fill: type === 'start' ? '#FF6B9D' : '#00D9FF',
stroke: '#fff',
lineWidth: 2,
},
});
},
handleIconSize: 16,
},
},
});完整样式配置
chart.options({
slider: {
x: {
values: [0.3, 0.7],
// 选区样式
selectionFill: '#1890ff',
selectionFillOpacity: 0.2,
// 滑轨样式
trackFill: '#f0f0f0',
trackSize: 20,
// 手柄图标样式
handleIconFill: '#fff',
handleIconStroke: '#1890ff',
handleIconSize: 14,
handleIconRadius: 4,
// 手柄标签样式
handleLabelFill: '#333',
handleLabelFontSize: 12,
},
},
});---
常见错误与修正
错误 1:values 超出 [0, 1] 范围
// ❌ values 必须在 [0, 1] 区间
chart.options({ slider: { x: { values: [50, 100] } } });
// ✅ values 是数据比例(0~1)
chart.options({ slider: { x: { values: [0.5, 1.0] } } });错误 2:样式属性名错误
// ❌ 错误的属性名
slider: { x: { handleFill: 'red' } } // 不存在
// ✅ 正确的属性名(带前缀)
slider: { x: { handleIconFill: 'red' } } // 正确错误 3:与 scrollbar 混淆
// slider:两端手柄可分别拖动,窗口大小可变
slider: { x: { values: [0.3, 0.7] } }
// scrollbar:固定窗口大小,只能整体滑动
scrollbar: { x: { ratio: 0.4 } }基本用法
import { Chart } from '@antv/g2';
const chart = new Chart({ container: 'container', width: 640, height: 480 });
chart.options({
type: 'interval',
data,
encode: { x: 'month', y: 'value' },
title: {
title: '月度销售额', // 主标题
subtitle: '单位:万元', // 副标题
},
});
chart.render();完整配置项
chart.options({
type: 'interval',
data,
encode: { x: 'month', y: 'value' },
title: {
// ── 文本内容 ────────────────────────────
title: '月度销售趋势分析', // 主标题文本
subtitle: '数据来源:2024年度报告', // 副标题文本(可选)
// ── 对齐 ─────────────────────────────────
align: 'left', // 'left'(默认)| 'center' | 'right'
// ── 间距 ─────────────────────────────────
spacing: 4, // 主标题与副标题之间的间距,默认 2
// ── 主标题样式 ────────────────────────────
titleFontSize: 16,
titleFontWeight: 'bold',
titleFill: '#1d1d1d',
titleSpacing: 8, // 标题与图表内容区域之间的间距
// ── 副标题样式 ────────────────────────────
subtitleFontSize: 12,
subtitleFill: '#8c8c8c',
subtitleFontWeight: 'normal',
},
});居中标题
chart.options({
title: {
title: '季度对比报告',
subtitle: 'Q1-Q4 各季度销售数据',
align: 'center', // 居中对齐
titleFontSize: 18,
titleFontWeight: 600,
subtitleFontSize: 13,
subtitleFill: '#999',
},
});在构造函数中配置
// title 也可以在 Chart 构造函数的选项中配置
const chart = new Chart({
container: 'container',
width: 640,
height: 480,
title: {
title: '销售趋势',
align: 'center',
},
});常见错误与修正
错误:title 写成字符串而不是对象
// ❌ 错误:title 字段必须是配置对象,不能直接写字符串
chart.options({
title: '月度销售额', // ❌ 不支持字符串
});
// ✅ 正确:title 字段是对象,主标题文本在 title.title 中
chart.options({
title: {
title: '月度销售额', // ✅ 正确写法
},
});错误:把图表标题与坐标轴标题混淆
// ❌ 错误:在 axis 里写整体图表标题
chart.options({
axis: { x: { title: '月度销售额' } }, // ❌ 这是 X 轴标题,不是图表标题
});
// ✅ 图表标题用顶层 title 字段
chart.options({
title: { title: '月度销售额' }, // ✅ 图表标题
axis: { x: { title: '月份' } }, // ✅ X 轴标题
});最小可运行示例(启用默认 tooltip)
import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
width: 600,
height: 400,
});
const data = [
{ month: '1月', value: 120, type: '销售额' },
{ month: '2月', value: 180, type: '销售额' },
{ month: '3月', value: 150, type: '销售额' },
];
chart.options({
type: 'line',
data,
encode: { x: 'month', y: 'value', color: 'type' },
// tooltip 默认开启,此配置可自定义
tooltip: {
title: (d) => `${d.month} 数据`, // 自定义标题
items: [
{ channel: 'y', name: '销售额', valueFormatter: (v) => `¥${v}` },
],
},
});
chart.render();多字段 tooltip(显示多个信息项)
const data = [
{ date: '2024-01', revenue: 1200, cost: 800, profit: 400 },
{ date: '2024-02', revenue: 1800, cost: 950, profit: 850 },
{ date: '2024-03', revenue: 1500, cost: 1000, profit: 500 },
];
chart.options({
type: 'line',
data,
encode: { x: 'date', y: 'revenue' },
tooltip: {
title: 'date',
// items 中每项对应一行显示内容
items: [
{ field: 'revenue', name: '收入', valueFormatter: (v) => `¥${v}` },
{ field: 'cost', name: '成本', valueFormatter: (v) => `¥${v}` },
{ field: 'profit', name: '利润', valueFormatter: (v) => `¥${v}` },
],
},
});完全自定义 HTML(render 函数)
chart.options({
type: 'interval',
data,
encode: { x: 'category', y: 'value', color: 'category' },
tooltip: {
render: (event, { title, items }) => {
// 返回 HTML 字符串,完全自定义 tooltip 内容
return `
<div style="padding: 8px 12px; background: #fff; border-radius: 4px; box-shadow: 0 2px 8px rgba(0,0,0,0.15);">
<div style="font-weight: bold; margin-bottom: 6px;">${title}</div>
${items.map(({ name, value, color }) => `
<div style="display: flex; align-items: center; gap: 8px; margin-bottom: 4px;">
<span style="width: 8px; height: 8px; background: ${color}; border-radius: 50%; display: inline-block;"></span>
<span>${name}:</span>
<span style="font-weight: 500;">${value}</span>
</div>
`).join('')}
</div>
`;
},
},
});多系列共享 tooltip(groupKey)
// 多折线图,鼠标悬停时同时显示所有系列的值
chart.options({
type: 'view',
data,
children: [
{
type: 'line',
encode: { x: 'month', y: 'value', color: 'type' },
tooltip: {
// groupKey:按哪个字段合并多系列的 tooltip
// 默认按 x 值合并,所有系列在同一 x 处的点显示在一个 tooltip 中
title: 'month',
},
},
],
interaction: [{ type: 'tooltip', shared: true }], // shared: true 显示共享 tooltip
});完整配置项
chart.options({
type: 'line',
data,
encode: { x: 'month', y: 'value' },
tooltip: {
// 标题
title: 'month', // 字段名 或 函数 (d) => string
// 显示项
items: [
{
field: 'value', // 数据字段名
channel: 'y', // 或者用通道名('x' | 'y' | 'color' 等)
name: '销售额', // 显示名称(覆盖默认)
color: '#1890ff', // 色块颜色
// valueFormatter 接受:
// 函数 (value) => string ← 需要拼接单位时必须用这种形式
// d3-format 字符串 '.2f' ← 只格式化数字本身,不支持追加文字
valueFormatter: (v) => `${v} 万元`, // ✅ 函数形式,可拼接单位
// valueFormatter: '.2f', // ✅ d3-format,仅格式化数字
// valueFormatter: '.0f 米', // ❌ 错误!d3-format 后不能追加文字
},
],
// 渲染
render: (event, { title, items }) => `<div>...</div>`, // 完全自定义 HTML
// 触发方式
// 在 interaction 中配置
},
// tooltip 交互(可补充配置)
interaction: [
{
type: 'tooltip',
shared: true, // 多 Mark 共享 tooltip
crosshairs: true, // 显示十字准线
},
],
});十字准线(crosshairs)
十字准线通过 interaction 中的 tooltip 交互项配置:
chart.options({
type: 'line',
data,
encode: { x: 'month', y: 'value' },
interaction: [
{
type: 'tooltip',
crosshairs: true, // 显示十字准线(默认开启)
crosshairsStroke: '#aaa', // 准线颜色
crosshairsLineWidth: 1, // 准线宽度
crosshairsLineDash: [4, 4], // 虚线样式
},
],
});通过 CSS 自定义 tooltip 样式
当 render 函数的定制化程度不够时,可以通过 CSS 直接覆盖默认样式:
// 方式 1:在页面全局 CSS 中覆盖
// .g2-tooltip { background: #1a1a1a; color: #fff; border-radius: 8px; }
// .g2-tooltip-title { font-size: 14px; font-weight: bold; }
// .g2-tooltip-list-item-value { color: #fadb14; }
// 方式 2:通过 interaction 的 css 参数(局部覆盖)
chart.options({
interaction: [
{
type: 'tooltip',
css: {
'.g2-tooltip': {
background: '#1a1a1a',
color: '#fff',
borderRadius: '8px',
padding: '8px 12px',
},
'.g2-tooltip-title': {
fontSize: '14px',
fontWeight: 'bold',
marginBottom: '6px',
},
'.g2-tooltip-list-item-value': {
color: '#fadb14',
},
},
},
],
});内置 CSS 类名:
.g2-tooltip— tooltip 容器.g2-tooltip-title— 标题.g2-tooltip-list-item— 单条数据项.g2-tooltip-list-item-name-label— 数据项名称.g2-tooltip-list-item-value— 数据项值.g2-tooltip-list-item-marker— 数据项颜色标记点
---
常见错误与修正
错误 1:tooltip.items 字段名与数据不匹配
// ❌ 错误:数据字段是 'revenue' 但 items 写的是 'value'
const data = [{ month: '1月', revenue: 1200 }];
chart.options({
tooltip: {
items: [{ field: 'value' }], // ❌ 数据中没有 'value' 字段
},
});
// ✅ 正确:field 与数据字段名对应
chart.options({
tooltip: {
items: [{ field: 'revenue', name: '收入' }], // ✅
},
});错误 2:render 函数忘记返回字符串
// ❌ 错误:render 函数没有 return 语句
chart.options({
tooltip: {
render: (event, { title, items }) => {
const html = `<div>${title}</div>`;
// 忘记 return!
},
},
});
// ✅ 正确:必须返回 HTML 字符串
chart.options({
tooltip: {
render: (event, { title, items }) => {
return `<div>${title}</div>`; // ✅
},
},
});错误 3:valueFormatter 用 d3-format 字符串拼接单位
valueFormatter 支持两种形式:函数 (v) => string 或 d3-format 字符串(如 '.2f')。d3-format 字符串只格式化数字本身,不能在后面追加文字单位——带空格的写法如 '.0f 米' 会被当作无效格式符,导致显示异常或直接报错。
// ❌ 错误:d3-format 字符串后追加文字单位
chart.options({
tooltip: {
items: [
{ field: 'distance', name: '距离', valueFormatter: '.0f 米' }, // ❌ 无效格式,d3-format 不支持拼接文字
{ field: 'price', name: '价格', valueFormatter: '.2f 元' }, // ❌ 同上
],
},
});
// ✅ 正确:需要拼接单位时必须用函数形式
chart.options({
tooltip: {
items: [
{ field: 'distance', name: '距离', valueFormatter: (v) => `${Math.round(v)} 米` }, // ✅ 函数形式
{ field: 'price', name: '价格', valueFormatter: (v) => `¥${v.toFixed(2)}` }, // ✅ 函数形式
],
},
});
// ✅ 仅格式化数字(不需要单位)时可用 d3-format 字符串
chart.options({
tooltip: {
items: [
{ field: 'ratio', name: '占比', valueFormatter: '.1%' }, // ✅ 纯 d3-format,无文字
{ field: 'value', name: '数值', valueFormatter: ',.0f' }, // ✅ 千分位整数
],
},
});错误 4:多系列 tooltip 未配置 shared
// ❌ 问题:多折线图 tooltip 只显示当前 hover 的那条线
chart.options({
type: 'view',
children: [
{ type: 'line', encode: { x: 'month', y: 'value', color: 'type' } },
],
// 没有 shared: true,tooltip 只显示鼠标直接悬停的那条线
});
// ✅ 正确:设置 shared: true 显示所有系列
chart.options({
type: 'view',
children: [
{ type: 'line', encode: { x: 'month', y: 'value', color: 'type' } },
],
interaction: [{ type: 'tooltip', shared: true }], // ✅
});---
深色背景适配:深色背景下 tooltip 样式需要适配时,使用theme: 'classicDark'自动切换,或通过interaction.tooltip.css手动控制。详见 深色主题适配
最小可运行示例(12 个月圆形分面)
import { Chart } from '@antv/g2';
// 每个月的每日数据
const data = [];
const months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
months.forEach((month, mi) => {
for (let day = 1; day <= 10; day++) {
data.push({ month, day, value: Math.random() * 100 });
}
});
const chart = new Chart({ container: 'container', width: 640, height: 640 });
chart.options({
type: 'facetCircle',
data,
encode: { position: 'month' }, // 按月份分面(决定每个子图的位置)
children: [
{
type: 'interval',
encode: { x: 'day', y: 'value', color: 'value' },
scale: { color: { type: 'sequential', palette: 'blues' } },
style: { lineWidth: 0 },
coordinate: { type: 'polar' }, // 每个子图用极坐标
},
],
});
chart.render();常见错误与修正
错误:children 中没有用 coordinate: polar——子图是矩形而非环形
// ❌ facetCircle 虽然分面排列是圆形,但子图本身仍可以是直角坐标
// 通常需要在 children 中指定 polar 坐标系才有圆形效果
chart.options({
type: 'facetCircle',
encode: { position: 'month' },
children: [
{
type: 'interval',
encode: { x: 'day', y: 'value' },
// ❌ 没有 coordinate: polar,子图是普通柱状图,排列在圆圈上但不是极坐标
},
],
});
// ✅ 通常在子图中加上 polar 坐标
children: [
{
type: 'interval',
encode: { x: 'day', y: 'value' },
coordinate: { type: 'polar' }, // ✅
},
]Related skills
FAQ
Which animation phases does antv-g2-chart configure?
antv-g2-chart covers AntV G2 v5 animate timing for enter (first render), update (data changes), and exit (removal). Each phase accepts built-in animation types with duration, delay, and easing overrides.
What built-in G2 animations does antv-g2-chart document?
antv-g2-chart lists fadeIn/Out, scaleInX/Y, growInX/Y, waveIn, zoomIn/Out, morphing, and pathIn as built-in animate types on G2 v5 charts. Developers pick a type per phase instead of writing custom keyframes.
Is Antv G2 Chart safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.