G2 5.0 底层将根据一套规范(Specification)去渲染图表,同时暴露尽量兼容 G2 4.0 的 API。所以 G2 的架构有以下两个核心模块。
- runtime: 根据指定的配置去渲染图表。
- api:基于 runtime 封装兼容 G2 4.0 的 API。
runtime 的主要任务就是把输入的 JavaScript Object 转换成一些列图形。为了代码的可读性、鲁棒性、可扩展性、易测试性,将整个转换过程拆分成一系列函数,每个函数对应一个组件。每个组件的首字母大写,返回一个函数,数组或者对象,同时每个组件具有 props 去提供在 runtime 里面使用的一些信息。
export type G2ComponentProps = {async?: boolean;[key: string]: any;};export type G2Component<R extends Function | object | any[], O = {}> = {(options: O): R;props: G2ComponentProps;};
// linear scaletype ScaleOptions = {domain: number[],range: any[],};export const Scale: ScaleComponent<ScaleOptions> = (options) => {const {domain, range} = options;const [d0, d1] = domain;const [r0, r1] = range;return x => {const t = (x - d0) / (d1 - d0);return r0 * (1 - t) + r1 * t;}}Scale.props = {quantitative: true,}
按照功能的不同将组建分为了以下种类,其中每一类都是一个独立的模块,它们会在 runtime 里面被串联起来使用。
- transform:数据预处理组件,将任意类型数据转换成扁平的数据。
- encode:提取通道值组件,从原始数据中提取通道值。
- statistic:通道值处理组件,新增或者改变通道的值。
- scale:通道映射组件,将数据映射为图形元素的通道。
- infer:推断配置组件,简单根据数据和配置推断一些确实的配置。
- palette:颜色通道使用的色板,返回用于比例尺值域的颜色。(需要增强分析的参与)
- coordinate:坐标系变换组件,将归一化的点转换成画布坐标系的点。
- component:辅助组件,一系列提高信息传递效率辅助。
- geometry:绘制图形组件,将处理好的数据绘制到画布上。
- shape: 计算几何图形的形组件,根据坐标数据和坐标系给 selection 添加形状相关的信息。
- adjust:调整位置通道组件,根据容器大小和比例尺去调整位置坐标。
- annotation:标注图表的关键信息组件,基于 geometry 和 shape 封装的有标注能力的视觉元素。
- animation:视觉元素动画组件,一系列定义好视觉动画。(需要设计师的参与)
- action:事件处理组件,用于修改图表状态。
- interaction: 应用交互组件,基于 trigger 和 action 封装一系列交互。
- theme:图表主题组件,用于改变图表的整体样式。
- composition: 视图复合组件。
- renderer:使用的渲染器,可以在不同端,渲染不同风格的图表。
最后会有一个 stdlib 模块将 G2 5.0 内置的标准组件导出。
- stdlib:导出一些 G2 默认使用的组件。
还有一个 shared 文件夹放一些公有的函数。
- shared:stdlib 和 runtime 都会使用的函数。
Runtime
G2.createRuntime()
根据指定的 renderOptions 创建一个新的渲染环境,默认使用内置的标准库 builtins。G2.createRuntime(rendererOptions[,builtins=createLibrary()])
renderOptions 是渲染器相关的配置,如果是客户端(在浏览器中运行)的渲染器,具有 container 等属性;如果是在服务端(在 Node 中运行)的渲染器则需要其他属性。默认的渲染环境的种类是 canvas。
import { createRuntime } from '@antv/g2';const runtime = createRuntime({container: 'chart'});const data = [{ genre: 'Sports', sold: 275 },{ genre: 'Strategy', sold: 115 },{ genre: 'Action', sold: 120 },{ genre: 'Shooter', sold: 350 },{ genre: 'Other', sold: 150 },];runtime.render({type: 'inteval',data,encode: {x: 'genre',y: 'sold',}});
// 目标支持以下种类的渲染器type G2RenderOptions = {type: 'canvas' | 'svg' | 'canvas-sketchy' | 'svg-sketchy' | 'server'}
如果指定 builtins,该对象的每一个属性定义了一个在渲染过程中使用的组件。如果没有指定 builtins,将默认使用 createLibrary() 返回的内置标准库。同时可以定义一个新的组件,或者覆盖一个存在的。
import { createRuntime, createLibrary } from '@antv/g2';// 定义一个新的 Geometryconst Link = () => {};Link.props = {type: 'link'};// 扩展标准库const library = Object.assign(createLibrary(), {'geometry.link': Link});const runtime = createRuntime({container}, library);// 绘制runtime.render({type: 'link', // 使用定义的 link 几何图形});
这里有几点需要说明:
- rendererOptions 为什么不做为图表描述(Options)的一部分:希望图表的描述是和渲染环境无关的,这样在不同渲染环境里面不需要更改图表的描述,去需要修改运行是的渲染参数即可。
- 为什么不使用 new Runtime 而使用 createRuntime:不把对象直接暴露给用户,防止用户直接继承这个对象,在之后的升级过程中产生冲突。后面的 createLibrary 同理。
- 为什么使用两个参数,而不是合并成一个参数,比如
createRuntime(options): renderOptions 是必选的,builtins 是可选的,分开可以让函数签名更加简洁。Runtime.render()
根据指定的配置项去渲染图表,所有的选项都是可选的。Runtime.render(options)
该函数的返回值由渲染器的选项决定。如果是客户端的渲染器,那么应该返回 container 节点;如果是服务端的渲染器,应该返回渲染出来的图片数据或者 Lottie 文件。
import { createRuntime } from '@antv/g2';const data = [{ genre: 'Sports', sold: 275 },{ genre: 'Strategy', sold: 115 },{ genre: 'Action', sold: 120 },{ genre: 'Shooter', sold: 350 },{ genre: 'Other', sold: 150 },];const runtime = createRuntime({container: 'chart'});runtime.render({type: 'inteval',data,encode: {x: 'genre',y: 'sold',}});
Runtime.dispose()
Runtime.dispose();
销毁内部创建的实例。如果是在客户端的运行环境,这意味着还要销毁定时器,取消事件的监听等等。
Stdlib
G2.createLibrary()
G2.createLibrary()
创建一个 runtime 使用的标准库,该标准库是一个平铺的对象。该对象的每一个属性是一个函数,对应一个组件。
import { createLibrary } from '@antv/g2';createLibrary();/*{'scale.linear': Linear,'geometry.point': Point,...}*/
API
G2.Chart()
Todo
Chart.*()
Todo
Transform
数据预处理组件,将任意类型数据转换成扁平的数据。将之前 DataSet 的部分能力迁移过来。
export type TransformFunction = (data?: any) => any;export type TransformComponent<O = {}> = G2Component<TransformFunction, O>;
import {TransformComponent as TC} from '../runtime';export type SortOptions = {callback?: (a: any, b: any) => boolean;};export const Sort: TC<SortOptions> = (options) => {const {callback = (a, b) => a - b} = options;return data => data.sort(callback);}Sort.props = {};
- Connector
- fetch
- Transform
- sortBy
- filterBy
- Layout
- force graph
- tree graph
- circle packing
- treemap
- word cloud
- sankey
Encode
提取通道值组件,从原始数据中提取通道值。对应图形语法中的 Data 操作,目前只内置4个比较常用的,之后可以扩展。(比如针对科学可视化等)
```typescript import {EncodeComponent as EC} from ‘../runtime’;export type EncodeFunction = (data?: any) => any[];export type EncodeComponent<O = {}> = G2Component<EncodeFunction, O>;
export type ConstantOptions = { value?: any; };
export const Constant: EC
Constant.props = {};
- constant- field- transform- statistic<a name="yme2S"></a># Statistic通道值处理组件,新增或者改变通道的值。```typescriptexport type StatisticValue = { index: number[]; value: any[] };export type StatisticFunction = (value?: StatisticValue) => StatisticValue;export type StatisticComponent<O = {}> = G2Component<StatisticFunction, O>;
import {StatisticComponent as SC} from "../runtime";export type SelectLastOptions = {};export const SelectLast: SC<SelectLastOptions> = (options) => {return ({index, value}) => ({index: index[index.length - 1],value})}SelectLast.props = {};
Scale
通道映射组件,将数据映射为图形元素的通道。
export type Scale = any;export type ScaleComponent<O = {}> = G2Component<Scale, O>;
import {Linear as LinearScale, LinearOptions} from '@antv/scale';import {ScaleFuntion as SF} from '../runtime';export type LinearOptions;export const Linear: SF<LinearOptions> = (options) => {const scale = new Linear(options);return scale;}Linear.props = {};
Infer
推断配置组件,简单根据数据和配置推断一些配置。
export type InferFunction = (encodes: Record<string, Encode>) => Record<string, Encode>;export type InferComponent<O = {}> = G2Component<InferFunction, O>;
import {InferComponent as IC} from '../runtime';export type MaybeZeroY2Options = {};export const MaybeZeroY2: IC<MaybeZeroY2Options> = (options) => {return (encodes) => {const {y: Y, ...rest} = encodes;if (Array.isArray(Y[0]) || Y[0].length >= 2) {return encodes;}return {y: Y.map(d => [[d].flat(Infinity), 0]), ...rest};};};MaybeZeroY2.props = {};
Palette
颜色通道使用的色板,返回用于比例尺值域的颜色。每一个主题都有一组默认的色板。
export type Palette = string[];export type PaletteComponent<O = {}> = G2Component<Palette, O>;
import {PaletteComponent as PC} from "../runtime";export type AntVPaletteOptions = {};export const AntVPalette: PC<AntVPaletteOptions> = (options) => {return ['red', 'yellow', 'green', 'steelblue'];}AntVPalette.props = {};
Coordinate
坐标系变换组件,将归一化的点转换成画布坐标系的点。除了 @antv/coord 能力之外,还会具备 d3-geo 的一些地理坐标系的能力。
export type CoordinateFunction = (p: [number, number]) => [number, number];export type CoordinateComponent<O = {}> = G2Component<CoordinateFunction, O>;
import {CoordinateComponent as CC} from "../runtime";export PolarOptions = {};export const Polar: CC<PolarOptions> = (options) => {const {startAngle, endAngle, innerRadius, outerRadius} = options;return ['polar', startAngle, endAngle, innerRadius, outerRadius];};Polar.props = {};
Component
辅助组件,返回一个绘制组件的函数。
export type ComponentFunction = (scale: Record<ChannelTypes, Scale>,dimensions: {x?:number, y?:number, width?:number, height?:number},coordinate: Coordinate) => GShape;export type ComponentComponent<O = {}> = G2Component<ComponentFunction, O>;
import { Continuous } from '@antv/gui';import { ComponentComponent as CC } from '../runtime';export ContinuousOptions = {};export const ContinuousLegend: CC<ContinuousOptions> = (options) => {return (scale, dimensions, coordinate) => {const {x, y, width, height} = dimensions;const {domain} = scale;return new Continuous({color: domain,x, y, width, height,});}}ContinuousLegend.props = {};
Geometry
绘制图形组件,确定几何元素的绘制需要的点。
export type GeometryFunction = (index: number[],scale: Record<ChannelTypes, Scale>,value: Record<ChannelTypes, any[]>,style: Record<string, string>,coordinate: Coordiante,) => [number, nnumber][];export type GeometryComponent<O = {}> = G2Component<GeometryFunction, O>;
import {GeometryComponent as GC} from '../runtime';import {key as k} from '../utils';export type PointGeometryProps = {};export const PointGeometry: GC<PointGeometryProps> = (options) => {return (index, scale, value, styles, coordinate) => {const {x:X, y:Y, size:R} = value;const [width, height] = coordinate.getSize();return index.map(i => {const r = R[i] || styles.r;const a = r / width;const b = r / height;const p1 = [x - a, y - b];const p2 = [x + a, y + b];return [p1, p2].map(coordinate.map);});}}PointGeometry.props = {};
Shape
计算几何图形的形组件,根据坐标数据和坐标系给 selection 添加形状相关的信息。
export type ShapeFunction = (index: number[],points: [number, number][],value: Record<ChannelTypes, any[]>,coordinate: Coordinate) => any;export type ShapeComponent<O = {}> = G2Component<ShapeFunction, O>;
import { Circle} from '@antv/g'import { ShapeComponent as SC } from '../runtime';export type PointOptions = {};export const PointShape: SC<PointOptions> = () => {return (index, points, value, styles, coordinate) => {const {color: C} = value;return Array.from(index, i => {const [p1, p2] = points[i];const [x1, y1] = p1;const [x2, y2] = p2;const x = (x1 + x2) / 2;const y = (y1 + y2) / 2;const r = Math.min(x2 - x1, y2 - y1);const color = C[i];return new Circle({style: {...styles,r,x,y,fill: color}});});}}PointShape.props = {geometry: 'point',}
Adjust
调整位置通道组件,根据容器大小和比例尺去调整位置坐标。
export type AdjustFunction = (points: [number, number][],coordinate: Coordinate,path: Path[],) => void;export type AdjustComponent<O = {}> = G2Component<AdjustFunction, O>;
import { AdjustComponent as AC} from '../runtime';export type PackOptions = {};export const Pack: AC<PackOptions> = (options) => {// @todoreturn (points, coordinate, path) => {};}Pack.props = {};
Annotation
标注图表的关键信息组件,基于 geometry 和 shape 封装的有标注能力的视觉元素。这个也可以支持 shape。
export type AnnotationFunction = GeometryFunction;export type AnnotationComponent<O = {}> = G2Component<AnnotationFunction, O>;
Animation
视觉元素动画组件,返回对应的动画描述。(参考:https://g-next.antv.vision/zh/docs/api/animation)
export type Transition = { attribute: string; from?: number; to?: number };export type Animation = Transition[];export type AnimationComponent<O = {}> = G2Component<Animation, O>;
import { AnimationComponent as AC } from '../runtime';export type FadeInOptions = {};export type FadeIn: AC<FadeInOptions> = (options) => {return {keyframes: [{opacity: 0},{opacity: 1}],options,}}FadeIn.props = {};
Action
事件处理组件,用于修改图表状态。
export type ActionFunction = (event: Event, Store: store) => any;export type ActionComponent<O = {}> = G2Component<ActionFunction, O>;
import {ActionComponent as AC} from '../runtime';export type HighlightOptions = {};export const Highlight: ActionComponent<HighlightOptions> = (options) => {const { color } = options;return (state, payload) => {const { event } = payload;const { id } = event.target;const { style, ...rest } = state;// 更新这个 id 对应元素的 statestyle.set(id, { fill: color });return {...rest,style}};}Highlight.props = {};
Interaction
应用交互组件,基于 trigger 和 action 封装一系列交互。
export type Interaction = {showEnable?: any[];start: any[];processing?: any[];end?: any[];rollback?: any[];};export type InteractionComponent<O = {}> = G2Component<Interaction, O>;
import {InteractionComponent as IC} from '../runtime';export type HighlightElementOptions = {};export const HighlightElement: IC<HighlightElementOptions> = () => {return {start: {trigger: 'element:enter', action: 'highlight'}}}HighlightElememt.props = {};
Theme
export type Theme = Record<string, string>;export type ThemeComponent<O = {}> = G2Component<Theme, O>;
import { ThemeComponent } from '../runtime';export type LightThemeOptions = {};export const LightTheme = (options) => {return {...options,background: 'black',};};LightTheme.props = {};
Composition
Todo
Renderer
export type Renderer = any;export type RendererComponent<O = {}> = G2Component<Renderer, O>;
import { Renderer } from '@antv/g-canvas';import { RendererComponent as RC } from '../runtime';export type CanvasOptions = {container?: string;};export const Canvas: RendererComponent<CanvasOptions> = (options) => {const renderer = new Renderer();return new Canvas({renderer, ...options});}CanvasRenderer.props = {};
