### Site/Docs/Tutorial/Advanced/Custom View
---
title: 自定义 View
order: 1
---
在 F2 中,为了让显示更加灵活和自定义,我们把所有的组件都进行了高阶组件(HOC)的封装,形成了 `withXXX` 的逻辑封装。下面以 `Legend` 为例,来演示如何实现自定义 View。
## Legend 的使用
```jsx
import { Canvas, Chart, Legend } from '@antv/f2';
```
除了 `Legend` 之外,还有 `withLegend` 和 `LegendView` 这两个对象,而 `Legend = withLegend(LegendView)`。所以我们只要定义自己的 `LegendView` 就能达到自定义 View 的效果。
## 定义自定义 View
```jsx
const CustomLegendView = (props) => {
const { items } = props;
return (
{items.map((item) => {
const { name, color } = item;
return (
);
})}
);
}
```
## 使用自定义 View
```jsx
import { Canvas, Chart, withLegend } from '@antv/f2';
// 自定义 View
const CustomLegendView = (props) => {
const { items } = props;
return (
{items.map((item) => {
const { name, color } = item;
return (
);
})}
);
}
// 使用自定义 view 的组件
const Legend = withLegend(CustomLegendView);
```
在 `CustomLegendView` 中,用户可以拿到计算逻辑后的结果 props,也可以使用 Legend 组件的 public function。
## 完整示例
- [自定义 Legend](/zh/examples/component/legend#custom)
---
### Site/Docs/Tutorial/Framework/Jsx Transform.Zh
---
title: 配置 JSX Transform
order: 15
---
F2 使用 JSX 语法来构建图表,所以需要在运行前对 JSX 语法进行编译。JSX 更多细节可参考 React 的官方文档 [JSX 简介](https://zh-hans.reactjs.org/docs/introducing-jsx.html)。
Babel 和 TypeScript 都可以编译 JSX 语法,并且在编译时 JSX 语法时,会有 2 种编译模式,在实际项目中可根据实际情况选择和使用。
JSX 2 种编译的差别可见:
- https://babeljs.io/docs/en/babel-plugin-transform-react-jsx#runtime
- https://zh-hans.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html
## Babel
在 Babel 中是使用 [@babel/plugin-transform-react-jsx](https://babeljs.io/docs/en/babel-plugin-transform-react-jsx) 这个插件来编译 JSX 的。
### 安装
```bash
npm install --save-dev @babel/plugin-transform-react-jsx
```
### 配置 babel.config
#### Classic 模式
```json
{
"plugins": [
[
"@babel/plugin-transform-react-jsx",
{
"pragma": "jsx",
"pragmaFrag": "Fragment"
}
]
]
}
```
#### Automatic 模式
```json
{
"plugins": [
[
"@babel/plugin-transform-react-jsx",
{
"runtime": "automatic",
"importSource": "@antv/f2"
}
]
]
}
```
## TypeScript
在 TypeScript 中也分别支持这 2 种编译模式。
### 配置 tsconfig.json
#### Classic 模式
```json
{
"compilerOptions": {
"jsxFactory": "jsx",
"jsxFragmentFactory": "Fragment"
}
}
```
#### Automatic 模式
```json
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@antv/f2"
}
}
```
---
### Site/Docs/Tutorial/Framework/Miniprogram.En
---
title: 小程序上渲染 F2
order: 13
redirect_from:
- /zh/docs/tutorial/manual/miniprogram
---
F2 是基于 [CanvasRenderingContext2D](https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D) 的标准接口绘制的,所以只要能提供标准 [CanvasRenderingContext2D](https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D) 接口的实现对象,F2 就能进行图表绘制。
## 封装思路
在小程序中提供的 `context` 对象不是标准的 [CanvasRenderingContext2D](https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D),所以封装的核心思路是将 `context` 和 [CanvasRenderingContext2D](https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D) 对齐。F2 针对支付宝和微信这两个常见场景做了一层 `context` 的对齐,详见:https://github.com/antvis/f2-context。其他小程序也可以按同样的思路封装。
## 小程序组件
为了方便使用,我们针对支付宝和微信分别封装了对应的自定义组件。
### 支付宝小程序
F2 的支付宝小程序版本。
- [GitHub: my-f2](https://github.com/antvis/my-f2)
- [使用文档](https://github.com/antvis/my-f2/blob/master/README.md)
### 微信小程序
F2 的微信小程序图表组件。
- [GitHub: wx-f2](https://github.com/antvis/wx-f2)
- [使用文档](https://github.com/antvis/wx-f2/blob/master/README.md)
> **注意**:详细使用说明请参考 [小程序集成教程](/tutorial/framework/miniprogram.zh.md)。
---
### Site/Docs/Tutorial/Framework/Miniprogram.Zh
---
title: 如何在小程序中使用
order: 13
---
## 前置配置
### 安装依赖
```bash
# 安装 F2 依赖
npm i @antv/f2 --save
# 支付宝小程序
npm i @antv/f-my --save
# 微信小程序
npm i @antv/f-wx --save
```
### 配置 JSX Transform
如果项目已有 JSX 编译,可忽略此步骤。
详见:[配置 JSX Transform](/tutorial/framework/jsx-transform.zh.md)
### 添加 JSX 编译脚本
package.json:
```json
{
"scripts": {
"beforeCompile": "babel pages --out-dir pages --only **/*.jsx"
}
}
```
## 支付宝小程序
### 双 Canvas 模式说明
在小程序生态中,F2 提供了两套小程序组件:`f-my`(默认 NativeCanvas 实现)与 `f-my-web`(基于 WebCanvas 实现)。通过引入不同组件包来选择 Canvas 类型。
- `f-my`:使用 NativeCanvas(原生 Canvas 实现),对齐 Web Canvas API,适用于对原生特性有依赖或兼容性要求较高的场景
- `f-my-web`:使用 WebCanvas(在小程序内基于 web 技术栈实现的 Canvas),在包含大量同层组件或频繁跨层通信的复杂页面中,通常能显著降低总耗时,获得更优的交互性能
- 兼容性:F2 已屏蔽两者的 API 差异,图表代码无需修改即可在 `f-my` 与 `f-my-web` 之间复用
### 配置编译脚本
mini.project.json:
```json
{
"scripts": {
"beforeCompile": "npm run beforeCompile"
}
}
```
### 使用示例
#### 使用 NativeCanvas (f-my)
page.json:
```json
{
"usingComponents": {
"f2": "@antv/f-my"
}
}
```
page.axml:
```jsx
```
#### 使用 WebCanvas (f-my-web)
page.json:
```json
{
"usingComponents": {
"f2": "@antv/f-my-web"
}
}
```
page.axml:
```jsx
```
#### 样式定义
page.acss:
```css
.container {
width: 100%;
height: 600rpx;
}
```
#### 图表组件
chart.jsx:
```jsx
import { Chart, Interval, Axis } from '@antv/f2';
export default (props) => {
const { data } = props;
return (
);
}
```
#### 页面入口
page.jsx:
```jsx
import Chart from './chart';
const data = [
{ genre: 'Sports', sold: 275 },
{ genre: 'Strategy', sold: 115 },
{ genre: 'Action', sold: 120 },
{ genre: 'Shooter', sold: 350 },
{ genre: 'Other', sold: 150 },
];
Page({
data: {},
onRenderChart() {
return ;
},
})
```
#### createElement 方式
如果不想在入口文件写 JSX 语法,可以使用 createElement 方式:
page.js:
```jsx
import { createElement } from '@antv/f2';
import Chart from './chart';
const data = [
{ genre: 'Sports', sold: 275 },
{ genre: 'Strategy', sold: 115 },
{ genre: 'Action', sold: 120 },
{ genre: 'Shooter', sold: 350 },
{ genre: 'Other', sold: 150 },
];
Page({
data: {},
onRenderChart() {
return createElement(Chart, {
data: data,
});
},
})
```
### 完整示例
[GitHub 示例](https://github.com/antvis/FEngine/tree/master/packages/f-my/examples)
## 微信小程序
### 使用示例
#### 页面配置
page.json:
```json
{
"usingComponents": {
"f2": "@antv/f-wx"
}
}
```
#### 页面模板
page.wxml:
```jsx
```
#### 样式定义
page.wxss:
```css
.container {
width: 100%;
height: 600rpx;
}
```
#### 图表组件
chart.jsx:
```jsx
import { Chart, Interval, Axis } from '@antv/f2';
export default (props) => {
const { data } = props;
return (
);
}
```
#### 页面入口
page.jsx:
```jsx
import Chart from './chart';
const data = [
{ genre: 'Sports', sold: 275 },
{ genre: 'Strategy', sold: 115 },
{ genre: 'Action', sold: 120 },
{ genre: 'Shooter', sold: 350 },
{ genre: 'Other', sold: 150 },
];
Page({
data: {
onRenderChart() {
return ;
},
},
})
```
#### createElement 方式
page.js:
```jsx
import { createElement } 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 },
];
Page({
data: {
onRenderChart() {
return createElement(Chart, {
data: data,
});
},
},
})
```
### 完整示例
[GitHub 示例](https://github.com/antvis/FEngine/tree/master/packages/f-wx/examples)
---
### Site/Docs/Tutorial/Framework/Nodejs.Zh
---
title: 如何在 Node.js 中使用
order: 14
---
在 Node.js 环境中使用 F2,可以通过 `canvas` 库提供 Canvas 实现,从而生成图表图片。
## 配置 JSX Transform
详见:[配置 JSX Transform](/tutorial/framework/jsx-transform.zh.md)
## 安装依赖
```bash
npm install @antv/f2 --save
npm install canvas --save
```
## 使用示例
```jsx
import { Canvas, Chart, Interval, Axis } from '@antv/f2';
import { createCanvas } from 'canvas';
import fs from 'fs';
import path from 'path';
const canvas = createCanvas(200, 200);
const ctx = canvas.getContext('2d');
const data = [
{ genre: 'Sports', sold: 275 },
{ genre: 'Strategy', sold: 115 },
{ genre: 'Action', sold: 120 },
{ genre: 'Shooter', sold: 350 },
{ genre: 'Other', sold: 150 },
];
(async () => {
const { props } = (
);
const fcanvas = new Canvas(props);
await fcanvas.render();
const out = fs.createWriteStream(path.join(__dirname, 'chart.png'));
const stream = canvas.createPNGStream();
stream.pipe(out);
out.on('finish', () => {
process.exit();
});
})();
```
## 说明
- 使用 `canvas` 库的 `createCanvas` 方法创建 Canvas 实例
- 将 Canvas 的 2D context 传递给 F2 的 `Canvas` 组件
- 设置 `animate={false}` 关闭动画,因为图片导出场景不需要动画
- 使用 `createPNGStream` 将 Canvas 内容输出为 PNG 图片文件
---
### Site/Docs/Tutorial/Framework/Overview.Zh
---
title: 多端适配
order: 10
---
在 5.0 中,F 系列基于移动端特点和共性进行了移动端底层架构(Fengine)的统一,对接于最新的 G 5.0 之上。我们利用 Fengine 提供的多端适配,可以快速适配各种框架/端。
## 架构概览
其中:
- `@antv/f-engine` — 无框架(原生 JS)
- `@antv/f-react` — React 框架
- `@antv/f-vue` — Vue 框架
- `@antv/f-my` — 支付宝小程序端
- `@antv/f-wx` — 微信小程序端
## 使用方式
F2 默认引入 `@antv/f-engine` 中的 canvas。使用者根据框架/端,引入不同端的 canvas 以及 F2, 即可快速搭建可视化图表。具体使用方式可查看对应文档:
- [React 集成](/tutorial/framework/react.zh.md)
- [Vue 集成](/tutorial/framework/vue.zh.md)
- [小程序集成](/tutorial/framework/miniprogram.zh.md)
- [Node.js 集成](/tutorial/framework/nodejs.zh.md)
- [SVG 渲染器](/tutorial/framework/svg-renderer.zh.md)
## 封装思路
F2 是基于 [CanvasRenderingContext2D](https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D) 的标准接口绘制的,所以只要能提供标准 [CanvasRenderingContext2D](https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D) 接口的实现对象,F2 就能进行图表绘制。
因为在小程序中提供的 `context` 对象不是标准的 [CanvasRenderingContext2D](https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D),所以封装的核心思路是将 `context` 和 [CanvasRenderingContext2D](https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D) 对齐。F2 针对支付宝和微信这两个常见场景做了一层 `context` 的对齐,详见:https://github.com/antvis/f2-context。其他小程序也可以按同样的思路封装。
---
### Site/Docs/Tutorial/Framework/React.Zh
---
title: 如何在 React 中使用
order: 11
---
因为 F2 也是使用声明式构建图表 UI,也内置了一套统一的组件,可以很容易地与 React 生态结合,使用时可以完全按 React 组件库的方式来使用。
## 安装依赖
```bash
npm install @antv/f2 --save
npm install @antv/f-react --save
```
## 完整示例
```jsx
import React from 'react';
import ReactDOM from 'react-dom';
import Canvas from '@antv/f-react';
import { Chart, Interval } 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 },
];
ReactDOM.render(
,
document.getElementById('root')
)
```
## 完整示例参考
- [CodeSandbox 示例](https://codesandbox.io/s/f-react-forked-lcrxqf)
- [GitHub 示例](https://github.com/antvis/FEngine/tree/master/packages/f-react/examples)
---
### Site/Docs/Tutorial/Framework/Svg Renderer.Zh
---
title: 使用 SVG 渲染
order: 16
---
借助 G 的 [渲染器](https://g.antv.antgroup.com/api/renderer/svg),F2 也可以使用 SVG 渲染。
## 安装依赖
```bash
npm install @antv/g-mobile-svg --save
```
## 使用步骤
### 1. 定义渲染容器
```html
```
### 2. 使用 SVG 渲染器
```jsx
import { Canvas, Chart, Interval, jsx, Axis } from '@antv/f2';
import { Renderer } from '@antv/g-mobile-svg';
const container = document.getElementById('container');
// 实例化 SVG 渲染器
const renderer = new Renderer();
const { props } = (
// 声明渲染容器和渲染器
);
const canvas = new Canvas(props);
canvas.render();
```
## 完整示例
[CodeSandbox 示例](https://codesandbox.io/s/prod-fire-nk4d8x)
## 说明
- SVG 渲染器适用于需要矢量输出或可缩放图表的场景
- 通过 `renderer` 属性将 SVG 渲染器传递给 Canvas 组件
- SVG 渲染器会生成 SVG DOM 元素,可以方便地进行后续操作(如导出 SVG 文件)
---
### Site/Docs/Tutorial/Framework/Vue.Zh
---
title: 如何在 Vue 中使用
order: 12
---
为了方便 Vue 项目的使用,Fengine 也封装了一个 Vue 组件。
## 安装依赖
```bash
npm install @antv/f2 --save
npm install @antv/f-vue --save
```
## 配置 JSX 编译
### webpack (vue-cli)
安装 Babel 插件:
```bash
npm install @babel/plugin-transform-react-jsx --save-dev
```
打开 `vue.config.js` 添加如下配置:
```js
{
chainWebpack: (config) => {
config.module
.rule('F2')
.test(/\.jsx$/)
.use('babel')
.loader('babel-loader')
.options({
plugins: [
[
'@babel/plugin-transform-react-jsx',
{
runtime: 'automatic',
importSource: '@antv/f2',
},
],
],
})
.end();
},
}
```
### Vite
安装依赖:
```bash
npm install @rollup/plugin-babel --save-dev
npm install @babel/plugin-transform-react-jsx --save-dev
```
打开 `vite.config.js` 添加如下配置:
```js
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import { babel } from '@rollup/plugin-babel';
export default defineConfig({
plugins: [
babel({
plugins: [
[
'@babel/plugin-transform-react-jsx',
{
runtime: 'automatic',
importSource: '@antv/f2',
},
],
],
}),
vue(),
vueJsx(),
],
});
```
## 使用示例
```vue
```
## 完整示例参考
- [CodeSandbox 示例](https://codesandbox.io/s/f-vue-wlwtkb?file=/src/App.vue)
- [GitHub 示例](https://github.com/antvis/FEngine/tree/master/packages/f-vue/examples)
---
### Site/Docs/Tutorial/Question/With React Typescript.Zh
---
title: 和 React 同时使用时,TS 类型报错
order: 1
---
当和 React 同时使用时,遇到 `group`、`circle`、`rect` 等标签的类型提示错误,如下图所示:
## 问题原因
因为 React SVG 的标签类型里也有 `circle`、`rect` 等标签,这些和 F2 定义的冲突了,需要单独引入 F2 标签定义的命名空间。
## 解决方式
### 1. 确定当前项目的 JSX 编译模式
打开 `tsconfig.json`,找到 `compilerOptions` 下的 `jsx` 配置项。如果没有则默认为 `react`。
- `react` 为 [Classic 编译模式](/tutorial/framework/jsx-transform.zh.md#classic-模式)
- `react-jsx` 为 [Automatic 编译模式](/tutorial/framework/jsx-transform.zh.md#automatic-模式)
### 2. Classic 编译模式
在文件顶部增加如下注释和模块引用:
```jsx
/** @jsx jsx */
import { jsx } from '@antv/f2';
```
### 3. Automatic 编译模式
在文件顶部增加如下注释:
```jsx
/** @jsxImportSource @antv/f2 */
```
完成后即可解决类型错误问题:
## 注意事项
因为代码编译是以文件为单位的,在一个文件里只能使用一种标签类型。如果需要在同一文件中混用,需要将 F2 图表代码拆分到新文件中。
---
### Site/Docs/Tutorial/Animation.Zh
---
title: 动画属性 - Animation
order: 8
---
F2 动画定义与 [Web Animations API](https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Animations_API) 靠齐,除了组件层面,每个图形标签也都可以添加自定义动画。目前只支持基于 Keyframe 的动画,可定义动画执行阶段,以及变化效果 KeyframeEffect。
## 动画执行阶段
动画执行阶段分为 appear、update 以及 leave:
| 阶段 | 说明 | 触发时机 |
|------|------|----------|
| `appear` | 初始化时的入场动画 | render 阶段 |
| `update` | 数据更新时的更新动画 | props 发生改变 |
| `leave` | 销毁前的离场动画 | destroy 阶段 |
每个阶段都可以配置相应的 animation。
## Animation 属性
### 基础属性
| 属性 | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `easing` | `string` | `'linear'` | 缓动函数,动画持续效果 |
| `duration` | `number` | - | 动画持续时间(毫秒) |
| `delay` | `number` | `0` | 开始动画前的延迟(毫秒) |
| `fill` | `string` | `'none'` | 定义图形在动画执行前后的表现,可选值:`'none'`、`'forwards'`、`'backwards'`、`'both'` |
| `iterations` | `number` | `1` | 循环次数,`Infinity` 为无限循环 |
| `iterationStart` | `number` | `0` | 从何处执行动画 |
| `property` | `string[]` | - | 声明需要变换的属性 |
| `start` | `Keyframe` | - | 开始帧状态 |
| `end` | `Keyframe` | - | 结束帧状态 |
| `clip` | `Clip` | - | 裁剪区域动画,见[裁剪](/tutorial/shape-attrs.zh.md#裁剪) |
### easing 缓动函数
缓动函数,默认为 `linear`,并且内置提供以下缓动函数,可参考[效果](https://easings.net/):
| 恒速 | 加速 | 减速 | 加速-减速 | 减速-加速 |
|------|------|------|-----------|-----------|
| `linear` | `ease-in` / `in` | `ease-out` / `out` | `ease-in-out` / `in-out` | `ease-out-in` / `out-in` |
| `ease` | `in-sine` | `out-sine` | `in-out-sine` | `out-in-sine` |
| `steps` | `in-quad` | `out-quad` | `in-out-quad` | `out-in-quad` |
| `step-start` | `in-cubic` | `out-cubic` | `in-out-cubic` | `out-in-cubic` |
| `step-end` | `in-quart` | `out-quart` | `in-out-quart` | `out-in-quart` |
| - | `in-quint` | `out-quint` | `in-out-quint` | `out-in-quint` |
| - | `in-expo` | `out-expo` | `in-out-expo` | `out-in-expo` |
| - | `in-circ` | `out-circ` | `in-out-circ` | `out-in-circ` |
| - | `in-back` | `out-back` | `in-out-back` | `out-in-back` |
| - | `in-bounce` | `out-bounce` | `in-out-bounce` | `out-in-bounce` |
| - | `in-elastic` | `out-elastic` | `in-out-elastic` | `out-in-elastic` |
| - | `spring` / `spring-in` | `spring-out` | `spring-in-out` | `spring-out-in` |
### Keyframe 支持的属性
目前支持变换的属性:
| 属性 | 类型 | 说明 |
|------|------|------|
| `transform` | `string` | 和 [CSS Transform](https://developer.mozilla.org/zh-CN/docs/Web/CSS/transform) 保持一致 |
| `opacity` | `number` | 透明度 |
| `strokeOpacity` | `number` | 描边透明度 |
| `fill` | `string` | 填充色 |
| `stroke` | `string` | 描边色 |
| `lineWidth` | `number` | 线宽 |
| `r` | `number` | Circle 的半径 |
| `rx` | `number` | Ellipse 的 x 半径 |
| `ry` | `number` | Ellipse 的 y 半径 |
| `width` | `number` | Rect/Image 的宽度 |
| `height` | `number` | Rect/Image 的高度 |
| `x` | `number` | 位置 x 坐标 |
| `y` | `number` | 位置 y 坐标 |
| `x1` | `number` | Line 的起点 x 坐标 |
| `y1` | `number` | Line 的起点 y 坐标 |
| `x2` | `number` | Line 的终点 x 坐标 |
| `y2` | `number` | Line 的终点 y 坐标 |
| `offsetDistance` | `number` | 路径偏移,和 [CSS Offset](https://developer.mozilla.org/en-US/docs/Web/CSS/offset-distance) 保持一致 |
| `lineDash` | `number[]` | 实线和间隔的长度 |
| `lineDashOffset` | `number` | 虚线的偏移量,可实现蚂蚁线效果 |
| `path` | `string` | Path 的定义,可做形变动画 |
## 基础用法
### 入场动画
```jsx
```
### 更新动画
```jsx
```
### 离场动画
```jsx
```
### 多属性动画
```jsx
```
### 变换动画
```jsx
```
### 裁剪动画
```jsx
```
### 循环动画
```jsx
```
### 延迟动画
```jsx
```
## 路径动画
让图形沿着某个路径移动,在 CSS 中可通过 [MotionPath](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Motion_Path) 实现,F2 可通过图形标签上设置 offset 属性实现,目前支持 `` 和 ``。
### 基础路径动画
```jsx
```
### Line 组件路径动画
F2 在组件 Line 中内置了该功能,提供 `endView` 接口,可设置沿着线段移动的元素,具体可见 [demo](/examples/creative/case/#line-race)。
## TypeScript 类型定义
```typescript
interface Animation {
appear?: AnimationConfig
update?: AnimationConfig | AnimationConfig[]
leave?: AnimationConfig
}
interface AnimationConfig {
easing?: string
duration?: number
delay?: number
fill?: 'none' | 'forwards' | 'backwards' | 'both'
iterations?: number
iterationStart?: number
property?: string[]
start?: Keyframe
end?: Keyframe
clip?: ClipAnimation
}
interface Keyframe {
transform?: string
opacity?: number
strokeOpacity?: number
fill?: string
stroke?: string
lineWidth?: number
r?: number
rx?: number
ry?: number
width?: number
height?: number
x?: number
y?: number
x1?: number
y1?: number
x2?: number
y2?: number
offsetDistance?: number
lineDash?: number[]
lineDashOffset?: number
path?: string
}
interface ClipAnimation {
type: 'circle' | 'rect' | 'polygon'
property?: string[]
style: Record
start?: Record
end?: Record
}
```
## 常见问题
### 如何让动画无限循环?
设置 `iterations: Infinity`:
```jsx
animation={{
appear: {
easing: 'linear',
duration: 2000,
iterations: Infinity,
property: ['opacity'],
start: { opacity: 0 },
end: { opacity: 1 },
},
}}
```
### 如何让动画结束时保持最终状态?
设置 `fill: 'forwards'`:
```jsx
animation={{
appear: {
easing: 'linear',
duration: 1000,
fill: 'forwards',
property: ['x'],
start: { x: 0 },
end: { x: 100 },
},
}}
```
### 如何创建弹簧动画效果?
使用 `spring` 系列缓动函数:
```jsx
animation={{
appear: {
easing: 'spring',
duration: 1000,
property: ['x'],
start: { x: 0 },
end: { x: 100 },
},
}}
```
### 如何同时动画多个属性?
在 `property` 数组中声明多个属性:
```jsx
animation={{
appear: {
easing: 'ease-in-out',
duration: 1000,
property: ['x', 'y', 'width', 'height', 'opacity'],
start: {
x: 100,
y: 100,
width: 0,
height: 0,
opacity: 0,
},
end: {
x: 50,
y: 50,
width: 100,
height: 100,
opacity: 1,
},
},
}}
```
## 相关文档
- [图形标签](/tutorial/shape.zh.md)
- [绘图属性](/tutorial/shape-attrs.zh.md)
- [图形事件](/tutorial/event.zh.md)
- [图形使用](/tutorial/graphic.zh.md)
---
### Site/Docs/Tutorial/Component.Zh
---
title: 自定义组件
order: 9
---
F2 提供了完整的组件化能力,你可以创建自定义组件来扩展图表功能。组件结构基本保持和 React 一致,如果你了解 React,相信你一看就会。
## 为什么需要自定义组件
- **复用性**: 将常用的可视化元素封装成组件,在多处复用
- **模块化**: 将复杂的图表拆分成多个小组件,便于维护
- **扩展性**: 创建 F2 内置组件无法满足的特殊可视化需求
## 组件定义
### 基础结构
自定义组件需要继承 `Component` 基类并实现 `render` 方法:
```jsx
import { Component } from '@antv/f2';
class MyComponent extends Component {
render() {
const { props } = this;
const { text, x, y } = props;
return ;
}
}
```
### 完整生命周期
Component 提供完整的生命周期钩子:
```jsx
import { Component } from '@antv/f2';
class Hello extends Component {
constructor(props) {
super(props);
// 初始化状态
this.state = {
count: 0,
};
}
// 组件即将挂载
willMount() {
console.log('组件即将挂载');
}
// 组件挂载完成
didMount() {
console.log('组件已挂载');
// 可以执行副作用操作,如动画、请求等
}
// 判断是否需要更新
shouldUpdate(nextProps) {
// 返回 false 跳过更新
return true;
}
// 接收新属性
willReceiveProps(nextProps) {
console.log('即将接收新属性', nextProps);
}
// 组件即将更新
willUpdate() {
console.log('组件即将更新');
}
// 组件更新完成
didUpdate() {
console.log('组件已更新');
}
// 渲染组件
render() {
const { props, state } = this;
const { color } = props;
const { count } = state;
return (
);
}
// 组件即将卸载
willUnmount() {
console.log('组件即将卸载');
// 清理资源,如取消事件监听等
}
// 组件卸载完成
didUnmount() {
console.log('组件已卸载');
}
}
```
## 生命周期流程图
```
挂载阶段:
constructor() → willMount() → render() → didMount()
更新阶段:
willReceiveProps() → shouldUpdate() → willUpdate() → render() → didUpdate()
卸载阶段:
willUnmount() → didUnmount()
```
## 组件状态管理
### setState
使用 `setState` 更新组件状态:
```jsx
class Counter extends Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
handleClick() {
// 更新状态
this.setState({
count: this.state.count + 1,
});
// 或使用函数形式
this.setState((prevState) => ({
count: prevState.count + 1,
}));
// 可以传入回调函数
this.setState(
{ count: this.state.count + 1 },
() => {
console.log('状态已更新', this.state.count);
}
);
}
render() {
const { count } = this.state;
return ;
}
}
```
### forceUpdate
强制组件更新,跳过 `shouldUpdate` 检查:
```jsx
class MyComponent extends Component {
forceRefresh() {
this.forceUpdate(() => {
console.log('组件已强制更新');
});
}
}
```
## 组件属性
### 属性类型定义
使用 TypeScript 定义组件属性:
```tsx
interface MyComponentProps {
title: string;
value: number;
color?: string;
}
class MyComponent extends Component {
render() {
const { props } = this;
const { title, value, color = 'red' } = props;
return ;
}
}
```
### 默认属性值
```jsx
class MyComponent extends Component {
static defaultProps = {
color: 'red',
size: 12,
};
render() {
const { color, size } = this.props;
return ;
}
}
```
## 使用上下文
组件可以通过 `this.context` 访问上下文信息:
```jsx
class ContextAwareComponent extends Component {
didMount() {
const { context } = this;
const { px2hd, theme, layout } = context;
// 像素单位转换
const x = px2hd(100);
// 访问主题
const primaryColor = theme.primaryColor;
// 访问布局信息
const { width, height } = layout;
}
render() {
const { context } = this;
const { px2hd } = context;
return (
);
}
}
```
### IContext 接口
| 属性 | 类型 | 说明 |
|------|------|------|
| `px2hd` | `(value: any) => any` | 像素单位转换函数 |
| `theme` | `Record` | 主题配置对象 |
| `layout` | `{ left, top, width, height }` | 画布布局信息 |
## 组件使用
### 基础使用
```jsx
import { Canvas } from '@antv/f2';
import Hello from './hello';
```
### 在图表中使用
```jsx
import { Canvas, Chart, Interval } from '@antv/f2';
import DataLabel from './data-label';
```
## 实用示例
### 数据标签组件
创建一个显示数据标签的组件:
```jsx
class DataLabel extends Component {
render() {
const { props, context } = this;
const { data, xField, yField } = props;
const { px2hd } = context;
return (
{data.map((item) => {
const x = px2hd(item[xField]);
const y = px2hd(item[yField]);
return (
);
})}
);
}
}
// 使用
```
### 自定义图例组件
```jsx
class CustomLegend extends Component {
render() {
const { props } = this;
const { items, onClick } = props;
const { x = 10, y = 10 } = props;
return (
{items.map((item, index) => (
onClick(item)}
>
))}
);
}
}
```
### 条件渲染组件
```jsx
class ConditionalComponent extends Component {
render() {
const { props } = this;
const { data, threshold } = props;
const shouldRender = data.some(item => item.value > threshold);
if (!shouldRender) {
return null;
}
return ;
}
}
```
### 动画组件
```jsx
class AnimatedComponent extends Component {
constructor(props) {
super(props);
this.state = {
progress: 0,
};
}
didMount() {
const { animate } = this.props;
if (animate) {
this.startAnimation();
}
}
startAnimation() {
let progress = 0;
const timer = setInterval(() => {
progress += 0.1;
if (progress >= 1) {
progress = 1;
clearInterval(timer);
}
this.setState({ progress });
}, 50);
}
render() {
const { props, state } = this;
const { progress } = state;
const { maxValue } = props;
const height = maxValue * progress;
return (
);
}
willUnmount() {
// 清理定时器
if (this.timer) {
clearInterval(this.timer);
}
}
}
```
## 组件通信
### 父子组件通信
```jsx
// 父组件
class ParentComponent extends Component {
render() {
return (
);
}
handleItemClick = (item) => {
console.log('子组件被点击', item);
};
}
// 子组件
class ChildComponent extends Component {
render() {
const { props } = this;
const { data, onItemClick } = props;
return (
{data.map((item) => (
onItemClick(item)}
/>
))}
);
}
}
```
## 性能优化
### 使用 shouldUpdate
避免不必要的渲染:
```jsx
class OptimizedComponent extends Component {
shouldUpdate(nextProps) {
// 只有当关键属性变化时才更新
return nextProps.value !== this.props.value;
}
render() {
const { props } = this;
return ;
}
}
```
### 避免在 render 中创建对象
```jsx
// 错误示例
class BadComponent extends Component {
render() {
const style = { color: 'red' }; // 每次渲染都创建新对象
return ;
}
}
// 正确示例
class GoodComponent extends Component {
render() {
return ;
}
}
```
## 相关文档
- [Component API](/api/component.zh.md)
- [图形语法](/tutorial/grammar.zh.md)
- [图形属性](/tutorial/shape-attrs.zh.md)
---
### Site/Docs/Tutorial/Coordinate.En
---
title: Coordinate System
order: 5
---
A coordinate system is a 2D positioning system that combines two position scales, describing how data is mapped to the plane where graphics are located.
F2 provides two types of coordinate systems: Cartesian (rect) and Polar. All coordinate systems are 2-dimensional.
## Coordinate System Types
| Type | Description | Use Cases |
|------|-------------|-----------|
| `rect` | Cartesian coordinate system, formed by two perpendicular x and y axes | Bar charts, line charts, scatter plots, etc. |
| `polar` | Polar coordinate system, formed by angle and radius dimensions | Pie charts, rose charts, radar charts, etc. |
### Coordinate System Comparison
Transforming coordinate system types changes the shape of geometry marks. For example, bar charts transform into various types under different coordinate systems:
| Chart Type | Cartesian | Polar (Not Transposed) | Polar (Transposed) |
|------------|------------|------------------------|---------------------|
| Stacked Bar | | | |
| Bar | | | |
## How to Set Coordinate System
F2 uses Cartesian coordinate system by default. To switch coordinate systems, set the `coord` attribute on the `Chart` component:
```jsx
{/* ... */}
```
## Cartesian Coordinate System
The Cartesian coordinate system (rect) is the default coordinate system type, formed by two perpendicular x and y axes.
### Configuration Syntax
```jsx
```
### Transposed Coordinate System
Swap x and y axes, suitable for bar charts:
```jsx
```
## Polar Coordinate System
The polar coordinate system is formed by angle and radius dimensions, suitable for visualizing periodic data such as time and direction.
### Configuration Syntax
```jsx
{/* ... */}
```
### CoordConfig Type Definition
```typescript
interface CoordConfig {
type?: 'rect' | 'polar'; // Coordinate system type
transposed?: boolean; // Whether to transpose
startAngle?: number; // Start angle (polar only)
endAngle?: number; // End angle (polar only)
innerRadius?: number; // Inner radius (polar only)
radius?: number; // Outer radius (polar only)
}
```
### Angle Description
The default start and end angles for F2 polar coordinates are shown below:
- Default start angle: -π (9 o'clock direction)
- Default end angle: 0 (3 o'clock direction)
## Chart Examples
### Pie Chart
Draw a pie chart using polar coordinates:
```jsx
const data = [
{ name: 'Movie A', percent: 0.4, a: '1' },
{ name: 'Movie B', percent: 0.2, a: '1' },
{ name: 'Movie C', percent: 0.18, a: '1' },
{ name: 'Movie D', percent: 0.15, a: '1' },
{ name: 'Movie E', percent: 0.05, a: '1' },
{ name: 'Others', percent: 0.02, a: '1' },
];
```
### Rose Chart
Draw a rose chart using polar coordinates:
```jsx
const data = [
{ name: 'Jan', value: 30 },
{ name: 'Feb', value: 40 },
{ name: 'Mar', value: 35 },
{ name: 'Apr', value: 50 },
{ name: 'May', value: 45 },
{ name: 'Jun', value: 60 },
];
```
### Donut Chart
Set inner radius to draw a donut chart:
```jsx
```
### Semi-Circle Pie Chart
Adjust start and end angles:
```jsx
```
### Radar Chart
Use transposed mode of polar coordinates:
```jsx
const data = [
{ item: 'Attack', value: 80 },
{ item: 'Defense', value: 70 },
{ item: 'Speed', value: 90 },
{ item: 'Power', value: 60 },
{ item: 'Stamina', value: 75 },
];
```
### Bar Chart
Use transposed Cartesian coordinates:
```jsx
```
### Stacked Bar Chart
```jsx
```
## Advanced Configuration
### Dynamic Coordinate System Switching
```jsx
class SwitchableChart extends Component {
state = {
coordType: 'rect',
};
handleSwitch = () => {
this.setState({
coordType: this.state.coordType === 'rect' ? 'polar' : 'rect',
});
};
render() {
const { coordType } = this.state;
return (
);
}
}
```
### Custom Coordinate System
```jsx
{/* ... */}
```
## Common Questions
### How to draw a semi-circle pie chart?
Adjust start and end angles:
```jsx
coord={{
type: 'polar',
startAngle: -Math.PI / 2, // Start from top
endAngle: Math.PI / 2, // End at top
}}
```
### How to draw a donut chart?
Set the `innerRadius` attribute:
```jsx
coord={{
type: 'polar',
innerRadius: 0.5, // 50% inner radius
}}
```
### How to draw a rose chart?
Use transposed mode of polar coordinates:
```jsx
coord={{
type: 'polar',
transposed: true, // Transpose
}}
```
### How to swap x and y axes?
Use the `transposed` attribute:
```jsx
coord={{
type: 'rect',
transposed: true, // Swap x and y axes
}}
```
## Related Documentation
- [Chart Grammar](/tutorial/grammar.en.md)
- [Scale](/tutorial/scale.en.md)
- [Core Concepts](/tutorial/understanding.en.md)
---
### Site/Docs/Tutorial/Coordinate.Zh
---
title: 坐标系
order: 5
---
坐标系是将两种位置标度结合在一起组成的 2 维定位系统,描述了数据是如何映射到图形所在的平面。
F2 提供了直角坐标系和极坐标系两种类型,所有坐标系均是 2 维的。
## 坐标系类型
| 类型 | 说明 | 适用场景 |
|------|------|----------|
| `rect` | 直角坐标系,由 x、y 两个互相垂直的坐标轴构成 | 柱状图、折线图、散点图等 |
| `polar` | 极坐标系,由角度和半径两个维度构成 | 饼图、玫瑰图、雷达图等 |
### 坐标系对比
坐标系类型的变换会改变几何标记的形状。例如,柱状图在不同坐标系下会变换成各种类型:
| 图表类型 | 直角坐标系 | 极坐标(未转置) | 极坐标(转置) |
|----------|------------|------------------|----------------|
| 层叠柱状图 | | | |
| 柱状图 | | | |
## 如何设置坐标系
F2 默认使用直角坐标系。切换坐标系时,在 `Chart` 组件上设置 `coord` 属性:
```jsx
{/* ... */}
```
## 直角坐标系
直角坐标系(笛卡尔坐标系)是默认的坐标系类型,由 x、y 两个互相垂直的坐标轴构成。
### 配置语法
```jsx
```
### 转置坐标系
将 x 轴和 y 轴交换,适用于条形图:
```jsx
```
## 极坐标系
极坐标系由角度和半径两个维度构成,适用于周期性数据的可视化,如时间和方向数据。
### 配置语法
```jsx
{/* ... */}
```
### CoordConfig 类型定义
```typescript
interface CoordConfig {
type?: 'rect' | 'polar'; // 坐标系类型
transposed?: boolean; // 是否转置
startAngle?: number; // 起始弧度(仅极坐标)
endAngle?: number; // 结束弧度(仅极坐标)
innerRadius?: number; // 内半径(仅极坐标)
radius?: number; // 外半径(仅极坐标)
}
```
### 角度说明
F2 极坐标的默认起始角度和结束角度如下图所示:
- 默认起始角度:-π(9 点钟方向)
- 默认结束角度:0(3 点钟方向)
## 图表示例
### 饼图
使用极坐标系绘制饼图:
```jsx
const data = [
{ name: '芳华', percent: 0.4, a: '1' },
{ name: '妖猫传', percent: 0.2, a: '1' },
{ name: '机器之血', percent: 0.18, a: '1' },
{ name: '心理罪', percent: 0.15, a: '1' },
{ name: '寻梦环游记', percent: 0.05, a: '1' },
{ name: '其他', percent: 0.02, a: '1' },
];
```
### 玫瑰图
使用极坐标系绘制玫瑰图:
```jsx
const data = [
{ name: '一月', value: 30 },
{ name: '二月', value: 40 },
{ name: '三月', value: 35 },
{ name: '四月', value: 50 },
{ name: '五月', value: 45 },
{ name: '六月', value: 60 },
];
```
### 环形图
设置内半径绘制环形图:
```jsx
```
### 半圆饼图
调整起始和结束角度:
```jsx
```
### 雷达图
使用极坐标系的转置模式:
```jsx
const data = [
{ item: '攻击力', value: 80 },
{ item: '防御力', value: 70 },
{ item: '速度', value: 90 },
{ item: '力量', value: 60 },
{ item: '耐力', value: 75 },
];
```
### 条形图
使用转置的直角坐标系:
```jsx
```
### 层叠条形图
```jsx
```
## 高级配置
### 动态切换坐标系
```jsx
class SwitchableChart extends Component {
state = {
coordType: 'rect',
};
handleSwitch = () => {
this.setState({
coordType: this.state.coordType === 'rect' ? 'polar' : 'rect',
});
};
render() {
const { coordType } = this.state;
return (
);
}
}
```
### 自定义坐标系统
```jsx
{/* ... */}
```
## 常见问题
### 如何绘制半圆饼图?
调整起始和结束角度:
```jsx
coord={{
type: 'polar',
startAngle: -Math.PI / 2, // 顶部开始
endAngle: Math.PI / 2, // 顶部结束
}}
```
### 如何绘制环形图?
设置 `innerRadius` 属性:
```jsx
coord={{
type: 'polar',
innerRadius: 0.5, // 50% 内半径
}}
```
### 如何绘制玫瑰图?
使用极坐标系的转置模式:
```jsx
coord={{
type: 'polar',
transposed: true, // 转置
}}
```
### 如何切换 x 和 y 轴?
使用 `transposed` 属性:
```jsx
coord={{
type: 'rect',
transposed: true, // 交换 x 和 y 轴
}}
```
## 相关文档
- [图形语法](/tutorial/grammar.zh.md)
- [度量](/tutorial/scale.zh.md)
- [核心概念](/tutorial/understanding.zh.md)
---
### Site/Docs/Tutorial/Data.En
---
title: Data Processing
order: 3
---
Data is the most fundamental part of creating charts. F2 requires data sources to be in JSON array format, where each element is a standard JSON object.
## Basic Data Format
F2's basic data format is a JSON array:
```jsx
const data = [
{ year: 2010, sales: 40 },
{ year: 2011, sales: 30 },
{ year: 2012, sales: 50 },
{ year: 2013, sales: 60 },
{ year: 2014, sales: 70 },
{ year: 2015, sales: 80 },
{ year: 2016, sales: 80 },
{ year: 2017, sales: 90 },
{ year: 2018, sales: 120 },
];
```
Using data:
```jsx
```
## Data Format Requirements
| Requirement | Description |
|-------------|-------------|
| **Array Format** | Data source must be an array |
| **Object Elements** | Array elements must be objects |
| **Field Names** | Object keys serve as field names for mapping to chart properties |
| **Field Values** | Supports string, number, array, date, and other types |
## Special Chart Data Formats
### Pie Chart
When drawing a pie chart, each record in the dataset **must include a constant field (and must be of string type)**:
```jsx
const data = [
{ name: 'Movie A', percent: 0.4, a: '1' },
{ name: 'Movie B', percent: 0.2, a: '1' },
{ name: 'Movie C', percent: 0.18, a: '1' },
{ name: 'Movie D', percent: 0.15, a: '1' },
{ name: 'Movie E', percent: 0.05, a: '1' },
{ name: 'Others', percent: 0.02, a: '1' },
];
```
**Why is a constant field needed?**
Pie charts use polar coordinate systems where all data needs to be mapped to the same angular range. The constant field (e.g., `a: '1'`) ensures all data points share the same angular starting position.
### Interval Bar Chart
When data on the x-axis or y-axis is an array, it will automatically be mapped to an interval, creating an interval bar chart:
```jsx
const data = [
{ x: 'Category 1', y: [76, 100] },
{ x: 'Category 2', y: [56, 108] },
{ x: 'Category 3', y: [38, 129] },
{ x: 'Category 4', y: [58, 155] },
{ x: 'Category 5', y: [45, 120] },
{ x: 'Category 6', y: [23, 99] },
{ x: 'Category 7', y: [18, 56] },
{ x: 'Category 8', y: [18, 34] },
];
```
The array represents the minimum and maximum values of the interval: `[minimum, maximum]`
### Candlestick Chart
Candlestick charts require open, close, highest, and lowest prices, using array format:
```jsx
const data = [
{ date: '2023-01', value: [100, 110, 95, 120] }, // [open, close, lowest, highest]
{ date: '2023-02', value: [110, 105, 100, 115] },
{ date: '2023-03', value: [105, 120, 102, 125] },
];
```
**Array format:** `[open, close, lowest, highest]`
- `open` - Opening price
- `close` - Closing price
- `lowest` - Lowest price
- `highest` - Highest price
### Scatter Plot (Bubble Chart)
Scatter plots can include additional dimensions (such as size):
```jsx
const data = [
{ x: 10, y: 20, size: 5, category: 'A' },
{ x: 15, y: 25, size: 10, category: 'B' },
{ x: 20, y: 18, size: 8, category: 'A' },
];
```
## Data Processing
### Data Filtering
Before passing to Chart, you can use JavaScript array methods to filter data:
```jsx
const rawData = [
{ year: 2010, sales: 40, category: 'A' },
{ year: 2011, sales: 30, category: 'B' },
{ year: 2012, sales: 50, category: 'A' },
{ year: 2013, sales: 60, category: 'B' },
];
// Keep only data where category is 'A'
const data = rawData.filter(item => item.category === 'A');
```
### Data Sorting
```jsx
const rawData = [
{ name: 'A', value: 30 },
{ name: 'B', value: 50 },
{ name: 'C', value: 20 },
];
// Sort by value in descending order
const data = [...rawData].sort((a, b) => b.value - a.value);
```
### Data Aggregation
```jsx
const rawData = [
{ category: 'A', value: 10 },
{ category: 'A', value: 20 },
{ category: 'B', value: 30 },
{ category: 'B', value: 40 },
];
// Aggregate by category (sum)
const aggregated = {};
rawData.forEach(item => {
if (!aggregated[item.category]) {
aggregated[item.category] = 0;
}
aggregated[item.category] += item.value;
});
const data = Object.entries(aggregated).map(([category, value]) => ({
category,
value,
}));
// Result: [{ category: 'A', value: 30 }, { category: 'B', value: 70 }]
```
### Data Transformation
```jsx
const rawData = [
{ date: '2023-01-01', value: 100 },
{ date: '2023-02-01', value: 120 },
];
// Transform date format
const data = rawData.map(item => ({
...item,
date: new Date(item.date),
// Or add computed fields
valueFormatted: item.value.toFixed(2),
}));
```
## Data Updates
F2 supports dynamic data updates with animated transitions:
```jsx
let chart = null;
// Initial data
const data1 = [
{ genre: 'Sports', sold: 275 },
{ genre: 'Strategy', sold: 115 },
];
const { props } = (
);
chart = new Canvas(props);
chart.render();
// Update data
const data2 = [
{ genre: 'Sports', sold: 350 },
{ genre: 'Strategy', sold: 200 },
];
const { props: newProps } = (
);
chart.update(newProps); // Automatically triggers animation
```
## Common Issues
### Handling Empty Data
```jsx
// Display empty state when data is empty
const data = [];
if (data.length === 0) {
// Show empty state
return ;
}
return (
);
```
### Handling Missing Values
```jsx
const data = [
{ year: 2010, sales: 40 },
{ year: 2011, sales: null }, // Missing value
{ year: 2012, sales: 50 },
];
// Filter out missing values
const cleanData = data.filter(item => item.sales != null);
// Or fill with default value
const filledData = data.map(item => ({
...item,
sales: item.sales ?? 0,
}));
```
### Handling Large Datasets
For large datasets, consider:
1. **Data Sampling**: Random sampling on the frontend
2. **Data Pagination**: Only load current page data
3. **Server-side Aggregation**: Complete aggregation calculations on the server
```jsx
// Data sampling example
function sampleData(data, maxSize) {
if (data.length <= maxSize) return data;
const step = Math.ceil(data.length / maxSize);
return data.filter((_, index) => index % step === 0);
}
const largeData = [...]; // Large dataset
const sampledData = sampleData(largeData, 1000);
```
## Complete Example
```jsx
import { Canvas, Chart, Interval, Axis, Tooltip } from '@antv/f2';
const rawData = [
{ month: 'Jan', sales: 100, profit: 20 },
{ month: 'Feb', sales: 120, profit: 25 },
{ month: 'Mar', sales: 90, profit: 15 },
{ month: 'Apr', sales: 150, profit: 35 },
{ month: 'May', sales: 180, profit: 40 },
{ month: 'Jun', sales: 200, profit: 45 },
];
// Data processing: Add profit rate field
const data = rawData.map(item => ({
...item,
profitRate: (item.profit / item.sales * 100).toFixed(2) + '%',
}));
const context = document.getElementById('container').getContext('2d');
const { props } = (
);
const canvas = new Canvas(props);
canvas.render();
```
## Data Source Types
### Static Data
Constant data defined directly in code:
```jsx
const data = [
{ x: 1, y: 2 },
{ x: 2, y: 4 },
];
```
### API Data
Fetched from remote API:
```jsx
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
const { props } = (
);
const canvas = new Canvas(props);
canvas.render();
}
fetchData();
```
### User Input
Responsive to user interactions:
```jsx
function updateChart(userInput) {
const data = processData(userInput);
const { props: newProps } = (
);
chart.update(newProps);
}
```
## More Examples
- [Pie Chart Example](/examples#pie-pie)
- [Interval Bar Chart Example](/examples#column-column)
- [Candlestick Chart Example](/examples#candlestick-candlestick)
- [Dynamic Data Example](/examples#dynamic-data)
## Related Documentation
- [Scale](/tutorial/scale.en.md)
- [Core Concepts](/tutorial/understanding.en.md)
- [Chart Grammar](/tutorial/grammar.en.md)
---
### Site/Docs/Tutorial/Data.Zh
---
title: 数据处理
order: 3
---
数据是绘制图表最基本的部分。F2 要求数据源为 JSON 数组格式,数组的每个元素是一个标准 JSON 对象。
## 基本数据格式
F2 的基本数据格式是 JSON 数组:
```jsx
const data = [
{ year: 2010, sales: 40 },
{ year: 2011, sales: 30 },
{ year: 2012, sales: 50 },
{ year: 2013, sales: 60 },
{ year: 2014, sales: 70 },
{ year: 2015, sales: 80 },
{ year: 2016, sales: 80 },
{ year: 2017, sales: 90 },
{ year: 2018, sales: 120 },
];
```
使用数据:
```jsx
```
## 数据格式要求
| 要求 | 说明 |
|------|------|
| **数组格式** | 数据源必须是数组 |
| **对象元素** | 数组元素必须是对象 |
| **字段名** | 对象的键作为字段名,用于映射到图表属性 |
| **字段值** | 支持字符串、数字、数组、日期等类型 |
## 特殊图表的数据格式
### 饼图
绘制饼图时,数据集中的每条记录**必须包含一个常量字段(且必须是字符串类型)**:
```jsx
const data = [
{ name: '芳华', percent: 0.4, a: '1' },
{ name: '妖猫传', percent: 0.2, a: '1' },
{ name: '机器之血', percent: 0.18, a: '1' },
{ name: '心理罪', percent: 0.15, a: '1' },
{ name: '寻梦环游记', percent: 0.05, a: '1' },
{ name: '其他', percent: 0.02, a: '1' },
];
```
**为什么需要常量字段?**
饼图使用极坐标系,所有数据需要映射到相同的角度范围。常量字段(如 `a: '1'`)确保所有数据点共享相同的角度起始位置。
### 区间柱状图
当 x 轴或 y 轴的数据为数组时,会自动映射为区间,绘制区间柱状图:
```jsx
const data = [
{ x: '分类一', y: [76, 100] },
{ x: '分类二', y: [56, 108] },
{ x: '分类三', y: [38, 129] },
{ x: '分类四', y: [58, 155] },
{ x: '分类五', y: [45, 120] },
{ x: '分类六', y: [23, 99] },
{ x: '分类七', y: [18, 56] },
{ x: '分类八', y: [18, 34] },
];
```
数组表示区间的最小值和最大值:`[最小值, 最大值]`
### 股票图(K线图)
股票图需要包含开盘价、收盘价、最高价、最低价,使用数组格式:
```jsx
const data = [
{ date: '2023-01', value: [100, 110, 95, 120] }, // [open, close, lowest, highest]
{ date: '2023-02', value: [110, 105, 100, 115] },
{ date: '2023-03', value: [105, 120, 102, 125] },
];
```
**数组格式说明:** `[open, close, lowest, highest]`
- `open` - 开盘价
- `close` - 收盘价
- `lowest` - 最低价
- `highest` - 最高价
### 散点图(气泡图)
散点图可以包含额外的维度(如大小):
```jsx
const data = [
{ x: 10, y: 20, size: 5, category: 'A' },
{ x: 15, y: 25, size: 10, category: 'B' },
{ x: 20, y: 18, size: 8, category: 'A' },
];
```
## 数据处理
### 数据过滤
在传递给 Chart 前,可以使用 JavaScript 的数组方法过滤数据:
```jsx
const rawData = [
{ year: 2010, sales: 40, category: 'A' },
{ year: 2011, sales: 30, category: 'B' },
{ year: 2012, sales: 50, category: 'A' },
{ year: 2013, sales: 60, category: 'B' },
];
// 只保留 category 为 'A' 的数据
const data = rawData.filter(item => item.category === 'A');
```
### 数据排序
```jsx
const rawData = [
{ name: 'A', value: 30 },
{ name: 'B', value: 50 },
{ name: 'C', value: 20 },
];
// 按 value 降序排列
const data = [...rawData].sort((a, b) => b.value - a.value);
```
### 数据聚合
```jsx
const rawData = [
{ category: 'A', value: 10 },
{ category: 'A', value: 20 },
{ category: 'B', value: 30 },
{ category: 'B', value: 40 },
];
// 按 category 聚合求和
const aggregated = {};
rawData.forEach(item => {
if (!aggregated[item.category]) {
aggregated[item.category] = 0;
}
aggregated[item.category] += item.value;
});
const data = Object.entries(aggregated).map(([category, value]) => ({
category,
value,
}));
// 结果: [{ category: 'A', value: 30 }, { category: 'B', value: 70 }]
```
### 数据转换
```jsx
const rawData = [
{ date: '2023-01-01', value: 100 },
{ date: '2023-02-01', value: 120 },
];
// 转换日期格式
const data = rawData.map(item => ({
...item,
date: new Date(item.date),
// 或添加计算字段
valueFormatted: item.value.toFixed(2),
}));
```
## 数据更新
F2 支持动态更新数据,实现动画过渡效果:
```jsx
let chart = null;
// 初始化数据
const data1 = [
{ genre: 'Sports', sold: 275 },
{ genre: 'Strategy', sold: 115 },
];
const { props } = (
);
chart = new Canvas(props);
chart.render();
// 更新数据
const data2 = [
{ genre: 'Sports', sold: 350 },
{ genre: 'Strategy', sold: 200 },
];
const { props: newProps } = (
);
chart.update(newProps); // 自动触发动画
```
## 常见问题
### 空数据处理
```jsx
// 数据为空时显示空状态
const data = [];
if (data.length === 0) {
// 显示空状态提示
return ;
}
return (
);
```
### 缺失值处理
```jsx
const data = [
{ year: 2010, sales: 40 },
{ year: 2011, sales: null }, // 缺失值
{ year: 2012, sales: 50 },
];
// 过滤掉缺失值
const cleanData = data.filter(item => item.sales != null);
// 或使用默认值填充
const filledData = data.map(item => ({
...item,
sales: item.sales ?? 0,
}));
```
### 大数据量处理
对于大数据量,建议:
1. **数据抽样**:在前端进行随机抽样
2. **数据分页**:只加载当前页的数据
3. **服务端聚合**:在服务端完成聚合计算
```jsx
// 数据抽样示例
function sampleData(data, maxSize) {
if (data.length <= maxSize) return data;
const step = Math.ceil(data.length / maxSize);
return data.filter((_, index) => index % step === 0);
}
const largeData = [...]; // 大数据集
const sampledData = sampleData(largeData, 1000);
```
## 完整示例
```jsx
import { Canvas, Chart, Interval, Axis, Tooltip } from '@antv/f2';
const rawData = [
{ month: '1月', sales: 100, profit: 20 },
{ month: '2月', sales: 120, profit: 25 },
{ month: '3月', sales: 90, profit: 15 },
{ month: '4月', sales: 150, profit: 35 },
{ month: '5月', sales: 180, profit: 40 },
{ month: '6月', sales: 200, profit: 45 },
];
// 数据处理:添加利润率字段
const data = rawData.map(item => ({
...item,
profitRate: (item.profit / item.sales * 100).toFixed(2) + '%',
}));
const context = document.getElementById('container').getContext('2d');
const { props } = (
);
const canvas = new Canvas(props);
canvas.render();
```
## 数据源类型
### 静态数据
直接定义在代码中的常量数据:
```jsx
const data = [
{ x: 1, y: 2 },
{ x: 2, y: 4 },
];
```
### API 数据
从远程 API 获取:
```jsx
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
const { props } = (
);
const canvas = new Canvas(props);
canvas.render();
}
fetchData();
```
### 用户输入
响应用户交互:
```jsx
function updateChart(userInput) {
const data = processData(userInput);
const { props: newProps } = (
);
chart.update(newProps);
}
```
## 更多示例
- [饼图示例](/examples#pie-pie)
- [区间柱状图示例](/examples#column-column)
- [股票图示例](/examples#candlestick-candlestick)
- [动态数据示例](/examples#dynamic-data)
## 相关文档
- [度量](/tutorial/scale.zh.md)
- [核心概念](/tutorial/understanding.zh.md)
- [图形语法](/tutorial/grammar.zh.md)
---
### Site/Docs/Tutorial/Event.Zh
---
title: 事件属性 - Event
order: 9
---
5.x 版本中,F2 的事件系统也得以升级,基于 PointerEvent 标准监听封装了移动端事件。得益于底层引擎的事件系统以及拾取系统,F2 支持在图形标签上直接监听常见的移动端事件。
### 事件属性
| 事件名 | 类型 | 描述 |
| ------------------- | ------- | -------------------------- |
| `onClick` | function | 点击事件 |
| `onPanStart` | function | 手指触摸图形时触发 0 |
| `onPan` | function | 手指在图形上移动时触发 |
| `onPanEnd` | function | 手指从图形上离开时触发 |
| `onTouchStart` | function | 手指触摸图形时触发 |
| `onTouchMove` | function | 手指在图形上移动时触发 |
| `onTouchEnd` | function | 手指从图形上离开时触发 |
| `onTouchEndOutside` | function | 手指从图形外离开时触发 |
| `onPressStart` | function | 手指在图形上开始按压时触发 |
| `onPress` | function | 手指在图形上按压时触发 |
| `onPressEnd` | function | 手指在图形上结束按压时触发 |
| `onSwipe` | function | 手指快扫时触发 |
| `onPinchStart` | function | 手指开始缩放时触发 |
| `onPinch` | function | 手指缩放时触发 |
| `onPinchEnd` | function | 手指结束缩放时触发 |
---
### Site/Docs/Tutorial/Getting Started.En
---
title: Quick Start
order: 0
---
This guide will help you get started with F2, from installation to rendering your first chart.
## Features
Starting from F2 4.0, we use declarative programming to build charts, providing a more intuitive development experience:
### Declarative
Declarative programming makes code more intuitive and concise, avoiding complex API calls. F2 uses JSX syntax, which is not only easy to use but also integrates seamlessly with frameworks like React and Vue.
### Component-Based
Components are essential for building complex visualizations. F2 follows React's design patterns and provides a complete set of component capabilities, making it simple to encapsulate your own components.
## Installation
### Install via npm
[](https://npmjs.com/package/@antv/f2) [](https://npmjs.com/package/@antv/f2)
```bash
npm install @antv/f2 --save
```
### Install via CDN
```html
```
## Configure JSX Transform
F2 uses JSX syntax to build charts, so you need to configure JSX transformation tools.
> Note: If your project is already using React, refer to [How to use with React](/tutorial/framework/react.en.md)
For detailed configuration instructions, see: [Configure JSX Transform](/tutorial/framework/jsx-transform.zh.md)
## One-Minute Quick Start
### 1. Create a canvas element
Create a `