关于 flutter-chart
flutter-chart 是帮助开发者使用 Flutter 的 Graphic 库构建数据可视化的技能。它涵盖声明式图表配置和自定义渲染,可用于标准图表,也可扩展形状、提示框与标注。
主要功能
- 01配置声明式图表层
- 02创建常见图表类型
- 03自定义形状与提示框
- 04设置交互、选择与动画
- 05添加坐标轴和标注
- 06处理动态数据
适用场景
- 01在 Flutter 应用中展示业务数据
- 02构建标准图表未覆盖的可视化
- 03为图表添加交互提示和选择
- 04实现带动画的数据更新
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ entronad/ graphic --skill flutter-chart安装后在 Claude Code 中输入/flutter-chart确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/algebra.mdanimation.mdannotations.mdchart-widget.mdcoordinates.mdcustomization.mdencodes.mdexamples.mdguides.mdmarks.mdmodifiers.mdscales.mdselections.mdshapes.mdstyling.mdtransforms.md详细介绍
使用 Graphic 构建 Flutter 图表
一项帮助用户使用 Graphic 库在 Flutter 中构建数据可视化的技能。Graphic 是一款基于图形语法的图表库。
适用场景
- 用户想在 Flutter 中创建任何类型的图表(柱状图、折线图、面积图、饼图、散点图、热力图等)
- 用户需要配置图表的外观、交互性或动画
- 用户询问 Graphic 库的 API 或使用模式
- 用户想将数据转换为可视化形式
- 用户想创建自定义、专属的可视化效果——Graphic 的定制系统是其最强大的功能,也是 AI 辅助开发的一大优势
为什么要创建自定义图表?
标准图表类型(柱状图、折线图、饼图)只能满足部分数据可视化需求。Graphic 基于图形语法理论构建,这意味着每个视觉图层都可以独立定制:
- 自定义形状——渲染任意几何图形(三角形、棒棒糖图、箭头、仪表盘、子弹图、迷你图等)
- 自定义工具提示——使用任意布局创建完全自定义的交互式叠加层
- 自定义注释——在数据位置或绝对位置绘制任意图形
- 自定义编码器——使用任意逻辑将数据映射为视觉效果
- 自定义修改器——定义自定义的碰撞和排列行为
这让 AI 辅助开发尤其有价值:AI 可以编写自定义形状渲染器、坐标计算和绘图代码,而手动实现这些内容会很繁琐。
如果用户的需求与标准图表类型不完全匹配,请务必考虑使用定制功能。 请参阅 references/customization.md,了解完整的定制指南。
快速入门
安装
将以下内容添加到 pubspec.yaml:
dependencies:
graphic: ^latest
然后运行 flutter pub get。
导入
import 'package:graphic/graphic.dart';
最小示例
Chart(
data: [
{'category': 'A', 'value': 10},
{'category': 'B', 'value': 20},
{'category': 'C', 'value': 15},
],
variables: {
'category': Variable(
accessor: (Map map) => map['category'] as String,
),
'value': Variable(
accessor: (Map map) => map['value'] as num,
),
},
marks: [IntervalMark()],
axes: [Defaults.horizontalAxis, Defaults.verticalAxis],
)
核心概念
Graphic 遵循图形语法理论。图表由相互独立的声明式图层组成:
data → Variable → Scale → Encode → Mark → Shape → Render
所有配置都通过单个 Chart<D> 组件构造函数完成。没有命令式 API——所有配置均为声明式。
Chart 组件
Chart<D> 是唯一的公开组件。类型参数 D 表示数据项类型。主要参数:
| 参数 | 类型 | 用途 |
|---|---|---|
data | List<D> | 必填。 要可视化的数据 |
variables | Map<String, Variable<D, dynamic>> | 必填。 如何从数据中提取值 |
marks | List<Mark> | 必填。 要渲染的几何类型 |
coord | Coord? | 坐标系(默认值:RectCoord) |
axes | List<AxisGuide>? | 坐标轴配置 |
tooltip | TooltipGuide? | 交互时显示的工具提示 |
crosshair | CrosshairGuide? | 交互时显示的十字准线 |
annotations | List<Annotation>? | 静态注释 |
selections | Map<String, Selection>? | 命名选择行为 |
transforms | List<VariableTransform>? | 数据转换(筛选、排序、比例) |
padding | EdgeInsets Function(Size)? | 绘图区周围的内边距 |
transition | — | 在每个 Mark 上设置,而不是在 Chart 上设置 |
完整参数详情请参阅 references/chart-widget.md。
变量
变量定义原始数据如何映射为抽象值:
variables: {
'date': Variable(
accessor: (MyData d) => d.date,
scale: TimeScale(formatter: (t) => DateFormat.MMMd().format(t)),
),
'value': Variable(
accessor: (MyData d) => d.value,
scale: LinearScale(min: 0),
),
}
每个变量都可以有一个 Scale,用于控制从定义域到值域的映射。请参阅 references/scales.md。
标记
标记是用于表示数据的几何元素:
| 标记 | 使用场景 | 默认形状 |
|---|---|---|
IntervalMark | 柱状图、直方图、饼图 | RectShape |
LineMark | 折线图、迷你图 | BasicLineShape |
AreaMark | 面积图、流图 | BasicAreaShape |
PointMark | 散点图、气泡图 | CircleShape |
PolygonMark | 热力图、树图 | HeatmapShape |
CustomMark | K 线图、自定义形状 | 任意 Shape |
参数请参阅 references/marks.md,形状选项请参阅 references/shapes.md。
编码(视觉映射)
编码会将数据值映射到视觉属性。每种编码都支持三种模式:
- 固定值:
ColorEncode(value: Colors.blue) - 变量映射:
ColorEncode(variable: 'type', values: Defaults.colors10) - 自定义函数:
ColorEncode(encoder: (tuple) => myColorLogic(tuple))
可用的编码:ColorEncode、SizeEncode、ShapeEncode、LabelEncode、GradientEncode、ElevationEncode。
详情请参阅 references/encodes.md。
位置代数(Varset)
位置通过 Varset 代数指定,支持三个运算符:
| 运算符 | 名称 | 效果 |
|---|---|---|
* | 交叉 | 将变量分配到不同维度(x、y) |
+ | 混合 | 在同一维度上组合变量 |
/ | 嵌套 | 按变量对数据分组 |
// x=date, y=value, grouped by type
position: Varset('date') * Varset('value') / Varset('type')
详情请参阅 references/algebra.md。
坐标
RectCoord— 笛卡尔坐标(默认)。支持transposed、horizontalRange、verticalRange。PolarCoord— 用于饼图、雷达图和玫瑰图的极坐标/径向坐标。支持startAngle、endAngle、startRadius、endRadius。
详情请参阅 references/coordinates.md。
交互
定义命名选择,并在编码更新器中使用它们:
selections: {
'tap': PointSelection(dim: Dim.x),
},
marks: [
IntervalMark(
color: ColorEncode(
value: Colors.blue,
updaters: {
'tap': {
true: (color) => color.withAlpha(255), // selected
false: (color) => color.withAlpha(100), // not selected
},
},
),
),
],
有关选择类型和手势配置,请参阅 references/selections.md。
修饰器
修饰器用于处理几何图形的碰撞/排列:
StackModifier()— 堆叠元素(堆叠柱状图、堆叠面积图)DodgeModifier()— 并排放置(分组柱状图)JitterModifier()— 随机散布(条带图)SymmetricModifier()— 对称居中(河流图)
请参阅 references/modifiers.md。
动画
IntervalMark(
transition: Transition(duration: Duration(seconds: 1), curve: Curves.easeOut),
entrance: {MarkEntrance.y}, // Animate from y=0
tag: (tuple) => tuple['id'].toString(), // Element matching for transitions
)
请参阅 references/animation.md。
常见图表示例
柱状图
marks: [IntervalMark()]
coord: RectCoord() // default
横向柱状图
marks: [IntervalMark()]
coord: RectCoord(transposed: true)
分组柱状图
marks: [
IntervalMark(
position: Varset('x') * Varset('y') / Varset('group'),
color: ColorEncode(variable: 'group', values: Defaults.colors10),
modifiers: [DodgeModifier()],
),
]
堆叠柱状图
marks: [
IntervalMark(
position: Varset('x') * Varset('y') / Varset('group'),
color: ColorEncode(variable: 'group', values: Defaults.colors10),
modifiers: [StackModifier()],
),
]
折线图
marks: [LineMark()]
平滑折线图
marks: [
LineMark(shape: ShapeEncode(value: BasicLineShape(smooth: true))),
]
面积图
marks: [AreaMark()]
饼图
transforms: [Proportion(variable: 'value', as: 'percent')],
marks: [
IntervalMark(
position: Varset('percent') / Varset('category'),
color: ColorEncode(variable: 'category', values: Defaults.colors10),
modifiers: [StackModifier()],
),
],
coord: PolarCoord(transposed: true, dimCount: 1),
散点图
marks: [
PointMark(
size: SizeEncode(variable: 'magnitude', values: [2, 20]),
color: ColorEncode(variable: 'type', values: Defaults.colors10),
),
]
玫瑰图
marks: [IntervalMark(color: ColorEncode(variable: 'name', values: Defaults.colors10))],
coord: PolarCoord(startRadius: 0.15),
更多完整示例请参阅 references/examples.md。
自定义图表开发
Graphic 最大的优势是其完全可定制的渲染管线。当标准图表类型无法满足需求时,可以通过实现自定义形状、工具提示、注释和编码器来创建自定义可视化。
自定义形状 — 核心扩展点
通过扩展 Shape 基类并实现 drawGroupPrimitives(),创建全新的图表几何图形:
class LollipopShape extends IntervalShape {
LollipopShape({this.radius = 6});
final double radius;
@override
List<MarkElement> drawGroupPrimitives(
List<Attributes> group, CoordConv coord, Offset origin,
) {
final rst = <MarkElement>[];
for (var item in group) {
if (item.position.any((p) => !p.dy.isFinite)) continue;
final style = getPaintStyle(item, false, 0, null, null);
final base = coord.convert(item.position[0]);
final tip = coord.convert(item.position[1]);
// Stem line
rst.add(PolylineElement(
points: [base, tip],
style: PaintStyle(strokeColor: style.fillColor, strokeWidth: 2),
tag: item.tag,
));
// Circle head
rst.add(CircleElement(
center: tip, radius: radius, style: style, tag: item.tag,
));
}
return rst;
}
@override
bool equalTo(Object other) =>
other is LollipopShape && radius == other.radius;
}
可用的基类:IntervalShape、LineShape、AreaShape、PointShape、PolygonShape
可用的绘图图元:RectElement、CircleElement、PolygonElement、PolylineElement、ArcElement、SectorElement、SplineElement、PathElement、LabelElement、GroupElement
自定义工具提示渲染器
tooltip: TooltipGuide(
renderer: (Size size, Offset anchor, Map<int, Tuple> selected) {
final t = selected.values.first;
return [
RectElement(
rect: Rect.fromCenter(center: anchor, width: 100, height: 36),
borderRadius: BorderRadius.circular(6),
style: PaintStyle(fillColor: Colors.black87, elevation: 4),
),
LabelElement(
text: '${t['name']}: ${t['value']}',
anchor: anchor,
style: LabelStyle(
textStyle: TextStyle(color: Colors.white, fontSize: 12),
align: Alignment.center,
),
),
];
},
)
自定义编码器函数
所有编码都支持通过 encoder 实现任意逻辑:
color: ColorEncode(encoder: (tuple) {
final v = tuple['value'] as num;
return v > 100 ? Colors.red : v > 50 ? Colors.orange : Colors.green;
}),
label: LabelEncode(encoder: (tuple) => Label(
'${tuple['value']}%',
LabelStyle(textStyle: TextStyle(
fontSize: (tuple['value'] as num) > 50 ? 14 : 10,
fontWeight: FontWeight.bold,
)),
)),
自定义开发的关键类
| 类 | 用途 |
|---|---|
Attributes | 编码后的数据元素 — 包含 position、color、gradient、size、label、tag |
CoordConv | 通过 convert()/invert() 将归一化的 [0,1] 位置转换为画布像素坐标 |
PaintStyle | 完整的绘制样式规范 — 填充、描边、渐变、虚线、仰角、阴影 |
MarkElement | 绘图图元 — 自定义渲染的构建模块 |
getPaintStyle() | 从 Attributes 中提取 PaintStyle 的工具函数 |
全面指南请参阅 references/customization.md,其中包括坐标处理、所有绘图图元、自定义注释、自定义修饰器和最佳实践。
指南与注释
- 坐标轴:快速设置可使用
Defaults.horizontalAxis、Defaults.verticalAxis,也可使用AxisGuide自定义。参见references/guides.md。 - 工具提示:使用
TooltipGuide(),可选自定义渲染器。参见references/guides.md。 - 十字线:使用
CrosshairGuide()。参见references/guides.md。 - 注释:
LineAnnotation、RegionAnnotation、TagAnnotation、CustomAnnotation。参见references/annotations.md。
样式
PaintStyle— 填充/描边颜色、渐变、虚线样式、阴影LabelStyle— 文本样式、对齐方式、旋转、偏移Defaults— 内置调色板(colors10、colors20)、预设坐标轴、默认样式
参见 references/styling.md。
事件流
图表通过 StreamController 参数公开事件,以便与外部事件联动:
gestureStream— 发送/接收手势事件resizeStream— 响应尺寸变化事件changeDataStream— 响应数据变化事件selectionStream(在 Mark 上)— 以编程方式设置选中项
动态数据
只需通过 setState() 更新 data 参数:
setState(() {
data = newData;
});
设置 tag 后,图表会自动重新渲染,并播放过渡动画。
重要说明
Chart小部件是唯一的公共小部件 — 所有配置都通过其构造函数完成- 编码中的
color和gradient互斥 - 饼图需要
Proportion变换以及PolarCoord(transposed: true, dimCount: 1) - 在标记上使用
tag,可在数据状态之间实现平滑的过渡动画 - 分组(多系列、堆叠、并列)需要使用
Varset的/(嵌套)运算符 - 在相等性比较中,函数类型的属性始终被视为“未更改”
参考文件
| 文件 | 内容 |
|---|---|
references/customization.md | 自定义图表开发指南 — 形状、工具提示、注释、编码器、绘图基本元素 |
references/chart-widget.md | Chart 小部件参数完整参考 |
references/marks.md | 所有标记类型及其参数 |
references/encodes.md | 视觉属性编码参考 |
references/shapes.md | 各标记对应的形状类型 |
references/scales.md | 比例类型及配置 |
references/coordinates.md | 坐标系参考 |
references/guides.md | 坐标轴、工具提示、十字线参考 |
references/annotations.md | 注释类型参考 |
references/selections.md | 选择与交互参考 |
references/modifiers.md | 几何修饰符参考 |
references/transforms.md | 数据变换参考 |
references/algebra.md | Varset 代数参考 |
references/animation.md | 过渡动画与入场动画参考 |
references/styling.md | PaintStyle、LabelStyle、Defaults 参考 |
references/examples.md | 完整图表示例 |
回答用户问题时,请阅读源代码,以获取最准确、最新的 API 详情。该库广泛使用代码注释作为文档。关键源代码目录:
lib/src/chart/— Chart 小部件lib/src/mark/— 标记类型lib/src/encode/— 编码类型lib/src/shape/— 形状实现lib/src/scale/— 比例类型lib/src/coord/— 坐标系lib/src/guide/— 坐标轴、工具提示、十字线、注释lib/src/interaction/— 选择、手势lib/src/variable/— 变量与变换lib/src/algebra/— Varset 代数lib/src/common/— 共享类型(Label、PaintStyle、Defaults)