渲染流程:https://whimsical.com/8zmkVcuVP6RzeRCPeCfcNJ

G2 5.0 底层将根据一套规范(Specification)去渲染图表,同时暴露尽量兼容 G2 4.0 的 API。所以 G2 的架构有以下两个核心模块。

  • runtime: 根据指定的配置去渲染图表。
  • api:基于 runtime 封装兼容 G2 4.0 的 API。

runtime 的主要任务就是把输入的 JavaScript Object 转换成一些列图形。为了代码的可读性、鲁棒性、可扩展性、易测试性,将整个转换过程拆分成一系列函数,每个函数对应一个组件。每个组件的首字母大写,返回一个函数,数组或者对象,同时每个组件具有 props 去提供在 runtime 里面使用的一些信息。

  1. export type G2ComponentProps = {
  2. async?: boolean;
  3. [key: string]: any;
  4. };
  5. export type G2Component<R extends Function | object | any[], O = {}> = {
  6. (options: O): R;
  7. props: G2ComponentProps;
  8. };
  1. // linear scale
  2. type ScaleOptions = {
  3. domain: number[],
  4. range: any[],
  5. };
  6. export const Scale: ScaleComponent<ScaleOptions> = (options) => {
  7. const {domain, range} = options;
  8. const [d0, d1] = domain;
  9. const [r0, r1] = range;
  10. return x => {
  11. const t = (x - d0) / (d1 - d0);
  12. return r0 * (1 - t) + r1 * t;
  13. }
  14. }
  15. Scale.props = {
  16. quantitative: true,
  17. }

按照功能的不同将组建分为了以下种类,其中每一类都是一个独立的模块,它们会在 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()

    1. G2.createRuntime(rendererOptions[,builtins=createLibrary()])
    根据指定的 renderOptions 创建一个新的渲染环境,默认使用内置的标准库 builtins

renderOptions 是渲染器相关的配置,如果是客户端(在浏览器中运行)的渲染器,具有 container 等属性;如果是在服务端(在 Node 中运行)的渲染器则需要其他属性。默认的渲染环境的种类是 canvas。

  1. import { createRuntime } from '@antv/g2';
  2. const runtime = createRuntime({container: 'chart'});
  3. const data = [
  4. { genre: 'Sports', sold: 275 },
  5. { genre: 'Strategy', sold: 115 },
  6. { genre: 'Action', sold: 120 },
  7. { genre: 'Shooter', sold: 350 },
  8. { genre: 'Other', sold: 150 },
  9. ];
  10. runtime.render({
  11. type: 'inteval',
  12. data,
  13. encode: {
  14. x: 'genre',
  15. y: 'sold',
  16. }
  17. });
  1. // 目标支持以下种类的渲染器
  2. type G2RenderOptions = {
  3. type: 'canvas' | 'svg' | 'canvas-sketchy' | 'svg-sketchy' | 'server'
  4. }

如果指定 builtins,该对象的每一个属性定义了一个在渲染过程中使用的组件。如果没有指定 builtins,将默认使用 createLibrary() 返回的内置标准库。同时可以定义一个新的组件,或者覆盖一个存在的。

  1. import { createRuntime, createLibrary } from '@antv/g2';
  2. // 定义一个新的 Geometry
  3. const Link = () => {};
  4. Link.props = {type: 'link'};
  5. // 扩展标准库
  6. const library = Object.assign(createLibrary(), {'geometry.link': Link});
  7. const runtime = createRuntime({container}, library);
  8. // 绘制
  9. runtime.render({
  10. type: 'link', // 使用定义的 link 几何图形
  11. });

这里有几点需要说明:

  • rendererOptions 为什么不做为图表描述(Options)的一部分:希望图表的描述是和渲染环境无关的,这样在不同渲染环境里面不需要更改图表的描述,去需要修改运行是的渲染参数即可。
  • 为什么不使用 new Runtime 而使用 createRuntime:不把对象直接暴露给用户,防止用户直接继承这个对象,在之后的升级过程中产生冲突。后面的 createLibrary 同理。
  • 为什么使用两个参数,而不是合并成一个参数,比如 createRuntime(options): renderOptions 是必选的,builtins 是可选的,分开可以让函数签名更加简洁。

    Runtime.render()

    1. Runtime.render(options)
    根据指定的配置项去渲染图表,所有的选项都是可选的。

该函数的返回值由渲染器的选项决定。如果是客户端的渲染器,那么应该返回 container 节点;如果是服务端的渲染器,应该返回渲染出来的图片数据或者 Lottie 文件。

  1. import { createRuntime } from '@antv/g2';
  2. const data = [
  3. { genre: 'Sports', sold: 275 },
  4. { genre: 'Strategy', sold: 115 },
  5. { genre: 'Action', sold: 120 },
  6. { genre: 'Shooter', sold: 350 },
  7. { genre: 'Other', sold: 150 },
  8. ];
  9. const runtime = createRuntime({container: 'chart'});
  10. runtime.render({
  11. type: 'inteval',
  12. data,
  13. encode: {
  14. x: 'genre',
  15. y: 'sold',
  16. }
  17. });

Runtime.dispose()

  1. Runtime.dispose();

销毁内部创建的实例。如果是在客户端的运行环境,这意味着还要销毁定时器,取消事件的监听等等。

Stdlib

G2.createLibrary()

  1. G2.createLibrary()

创建一个 runtime 使用的标准库,该标准库是一个平铺的对象。该对象的每一个属性是一个函数,对应一个组件。

  1. import { createLibrary } from '@antv/g2';
  2. createLibrary();
  3. /*
  4. {
  5. 'scale.linear': Linear,
  6. 'geometry.point': Point,
  7. ...
  8. }
  9. */

API

G2.Chart()

Todo

Chart.*()

Todo

Transform

数据预处理组件,将任意类型数据转换成扁平的数据。将之前 DataSet 的部分能力迁移过来。

  1. export type TransformFunction = (data?: any) => any;
  2. export type TransformComponent<O = {}> = G2Component<TransformFunction, O>;
  1. import {TransformComponent as TC} from '../runtime';
  2. export type SortOptions = {
  3. callback?: (a: any, b: any) => boolean;
  4. };
  5. export const Sort: TC<SortOptions> = (options) => {
  6. const {callback = (a, b) => a - b} = options;
  7. return data => data.sort(callback);
  8. }
  9. Sort.props = {};
  • Connector
    • fetch
  • Transform
    • sortBy
    • filterBy
  • Layout
    • force graph
    • tree graph
    • circle packing
    • treemap
    • word cloud
    • sankey

      Encode

      提取通道值组件,从原始数据中提取通道值。对应图形语法中的 Data 操作,目前只内置4个比较常用的,之后可以扩展。(比如针对科学可视化等)
      1. export type EncodeFunction = (data?: any) => any[];
      2. export type EncodeComponent<O = {}> = G2Component<EncodeFunction, O>;
      ```typescript import {EncodeComponent as EC} from ‘../runtime’;

export type ConstantOptions = { value?: any; };

export const Constant: EC = (options) => { const {value} = props; return data => Array.from(data, () => value); }

Constant.props = {};

  1. - constant
  2. - field
  3. - transform
  4. - statistic
  5. <a name="yme2S"></a>
  6. # Statistic
  7. 通道值处理组件,新增或者改变通道的值。
  8. ```typescript
  9. export type StatisticValue = { index: number[]; value: any[] };
  10. export type StatisticFunction = (value?: StatisticValue) => StatisticValue;
  11. export type StatisticComponent<O = {}> = G2Component<StatisticFunction, O>;
  1. import {StatisticComponent as SC} from "../runtime";
  2. export type SelectLastOptions = {};
  3. export const SelectLast: SC<SelectLastOptions> = (options) => {
  4. return ({index, value}) => ({
  5. index: index[index.length - 1],
  6. value
  7. })
  8. }
  9. SelectLast.props = {};

Scale

通道映射组件,将数据映射为图形元素的通道。

  1. export type Scale = any;
  2. export type ScaleComponent<O = {}> = G2Component<Scale, O>;
  1. import {Linear as LinearScale, LinearOptions} from '@antv/scale';
  2. import {ScaleFuntion as SF} from '../runtime';
  3. export type LinearOptions;
  4. export const Linear: SF<LinearOptions> = (options) => {
  5. const scale = new Linear(options);
  6. return scale;
  7. }
  8. Linear.props = {};

Infer

推断配置组件,简单根据数据和配置推断一些配置。

  1. export type InferFunction = (encodes: Record<string, Encode>) => Record<string, Encode>;
  2. export type InferComponent<O = {}> = G2Component<InferFunction, O>;
  1. import {InferComponent as IC} from '../runtime';
  2. export type MaybeZeroY2Options = {};
  3. export const MaybeZeroY2: IC<MaybeZeroY2Options> = (options) => {
  4. return (encodes) => {
  5. const {y: Y, ...rest} = encodes;
  6. if (Array.isArray(Y[0]) || Y[0].length >= 2) {
  7. return encodes;
  8. }
  9. return {y: Y.map(d => [[d].flat(Infinity), 0]), ...rest};
  10. };
  11. };
  12. MaybeZeroY2.props = {};

Palette

颜色通道使用的色板,返回用于比例尺值域的颜色。每一个主题都有一组默认的色板。

  1. export type Palette = string[];
  2. export type PaletteComponent<O = {}> = G2Component<Palette, O>;
  1. import {PaletteComponent as PC} from "../runtime";
  2. export type AntVPaletteOptions = {};
  3. export const AntVPalette: PC<AntVPaletteOptions> = (options) => {
  4. return ['red', 'yellow', 'green', 'steelblue'];
  5. }
  6. AntVPalette.props = {};

Coordinate

坐标系变换组件,将归一化的点转换成画布坐标系的点。除了 @antv/coord 能力之外,还会具备 d3-geo 的一些地理坐标系的能力。

  1. export type CoordinateFunction = (p: [number, number]) => [number, number];
  2. export type CoordinateComponent<O = {}> = G2Component<CoordinateFunction, O>;
  1. import {CoordinateComponent as CC} from "../runtime";
  2. export PolarOptions = {};
  3. export const Polar: CC<PolarOptions> = (options) => {
  4. const {startAngle, endAngle, innerRadius, outerRadius} = options;
  5. return ['polar', startAngle, endAngle, innerRadius, outerRadius];
  6. };
  7. Polar.props = {};

Component

辅助组件,返回一个绘制组件的函数。

  1. export type ComponentFunction = (
  2. scale: Record<ChannelTypes, Scale>,
  3. dimensions: {x?:number, y?:number, width?:number, height?:number},
  4. coordinate: Coordinate
  5. ) => GShape;
  6. export type ComponentComponent<O = {}> = G2Component<ComponentFunction, O>;
  1. import { Continuous } from '@antv/gui';
  2. import { ComponentComponent as CC } from '../runtime';
  3. export ContinuousOptions = {};
  4. export const ContinuousLegend: CC<ContinuousOptions> = (options) => {
  5. return (scale, dimensions, coordinate) => {
  6. const {x, y, width, height} = dimensions;
  7. const {domain} = scale;
  8. return new Continuous({
  9. color: domain,
  10. x, y, width, height,
  11. });
  12. }
  13. }
  14. ContinuousLegend.props = {};

Geometry

绘制图形组件,确定几何元素的绘制需要的点。

  1. export type GeometryFunction = (
  2. index: number[],
  3. scale: Record<ChannelTypes, Scale>,
  4. value: Record<ChannelTypes, any[]>,
  5. style: Record<string, string>,
  6. coordinate: Coordiante,
  7. ) => [number, nnumber][];
  8. export type GeometryComponent<O = {}> = G2Component<GeometryFunction, O>;
  1. import {GeometryComponent as GC} from '../runtime';
  2. import {key as k} from '../utils';
  3. export type PointGeometryProps = {};
  4. export const PointGeometry: GC<PointGeometryProps> = (options) => {
  5. return (index, scale, value, styles, coordinate) => {
  6. const {x:X, y:Y, size:R} = value;
  7. const [width, height] = coordinate.getSize();
  8. return index.map(i => {
  9. const r = R[i] || styles.r;
  10. const a = r / width;
  11. const b = r / height;
  12. const p1 = [x - a, y - b];
  13. const p2 = [x + a, y + b];
  14. return [p1, p2].map(coordinate.map);
  15. });
  16. }
  17. }
  18. PointGeometry.props = {};

Shape

计算几何图形的形组件,根据坐标数据和坐标系给 selection 添加形状相关的信息。

  1. export type ShapeFunction = (
  2. index: number[],
  3. points: [number, number][],
  4. value: Record<ChannelTypes, any[]>,
  5. coordinate: Coordinate
  6. ) => any;
  7. export type ShapeComponent<O = {}> = G2Component<ShapeFunction, O>;
  1. import { Circle} from '@antv/g'
  2. import { ShapeComponent as SC } from '../runtime';
  3. export type PointOptions = {};
  4. export const PointShape: SC<PointOptions> = () => {
  5. return (index, points, value, styles, coordinate) => {
  6. const {color: C} = value;
  7. return Array.from(index, i => {
  8. const [p1, p2] = points[i];
  9. const [x1, y1] = p1;
  10. const [x2, y2] = p2;
  11. const x = (x1 + x2) / 2;
  12. const y = (y1 + y2) / 2;
  13. const r = Math.min(x2 - x1, y2 - y1);
  14. const color = C[i];
  15. return new Circle({
  16. style: {
  17. ...styles,
  18. r,
  19. x,
  20. y,
  21. fill: color
  22. }
  23. });
  24. });
  25. }
  26. }
  27. PointShape.props = {
  28. geometry: 'point',
  29. }

Adjust

调整位置通道组件,根据容器大小和比例尺去调整位置坐标。

  1. export type AdjustFunction = (
  2. points: [number, number][],
  3. coordinate: Coordinate,
  4. path: Path[],
  5. ) => void;
  6. export type AdjustComponent<O = {}> = G2Component<AdjustFunction, O>;
  1. import { AdjustComponent as AC} from '../runtime';
  2. export type PackOptions = {};
  3. export const Pack: AC<PackOptions> = (options) => {
  4. // @todo
  5. return (points, coordinate, path) => {};
  6. }
  7. Pack.props = {};

Annotation

标注图表的关键信息组件,基于 geometry 和 shape 封装的有标注能力的视觉元素。这个也可以支持 shape。

  1. export type AnnotationFunction = GeometryFunction;
  2. export type AnnotationComponent<O = {}> = G2Component<AnnotationFunction, O>;

和 Geometry 类似,只不过需要绘制复杂的图形。

Animation

视觉元素动画组件,返回对应的动画描述。(参考:https://g-next.antv.vision/zh/docs/api/animation

  1. export type Transition = { attribute: string; from?: number; to?: number };
  2. export type Animation = Transition[];
  3. export type AnimationComponent<O = {}> = G2Component<Animation, O>;
  1. import { AnimationComponent as AC } from '../runtime';
  2. export type FadeInOptions = {};
  3. export type FadeIn: AC<FadeInOptions> = (options) => {
  4. return {
  5. keyframes: [
  6. {opacity: 0},
  7. {opacity: 1}
  8. ],
  9. options,
  10. }
  11. }
  12. FadeIn.props = {};

Action

事件处理组件,用于修改图表状态。

  1. export type ActionFunction = (event: Event, Store: store) => any;
  2. export type ActionComponent<O = {}> = G2Component<ActionFunction, O>;
  1. import {ActionComponent as AC} from '../runtime';
  2. export type HighlightOptions = {};
  3. export const Highlight: ActionComponent<HighlightOptions> = (options) => {
  4. const { color } = options;
  5. return (state, payload) => {
  6. const { event } = payload;
  7. const { id } = event.target;
  8. const { style, ...rest } = state;
  9. // 更新这个 id 对应元素的 state
  10. style.set(id, { fill: color });
  11. return {
  12. ...rest,
  13. style
  14. }
  15. };
  16. }
  17. Highlight.props = {};

Interaction

应用交互组件,基于 trigger 和 action 封装一系列交互。

  1. export type Interaction = {
  2. showEnable?: any[];
  3. start: any[];
  4. processing?: any[];
  5. end?: any[];
  6. rollback?: any[];
  7. };
  8. export type InteractionComponent<O = {}> = G2Component<Interaction, O>;
  1. import {InteractionComponent as IC} from '../runtime';
  2. export type HighlightElementOptions = {};
  3. export const HighlightElement: IC<HighlightElementOptions> = () => {
  4. return {
  5. start: {trigger: 'element:enter', action: 'highlight'}
  6. }
  7. }
  8. HighlightElememt.props = {};

Theme

  1. export type Theme = Record<string, string>;
  2. export type ThemeComponent<O = {}> = G2Component<Theme, O>;
  1. import { ThemeComponent } from '../runtime';
  2. export type LightThemeOptions = {};
  3. export const LightTheme = (options) => {
  4. return {
  5. ...options,
  6. background: 'black',
  7. };
  8. };
  9. LightTheme.props = {};

Composition

Todo

Renderer

  1. export type Renderer = any;
  2. export type RendererComponent<O = {}> = G2Component<Renderer, O>;
  1. import { Renderer } from '@antv/g-canvas';
  2. import { RendererComponent as RC } from '../runtime';
  3. export type CanvasOptions = {
  4. container?: string;
  5. };
  6. export const Canvas: RendererComponent<CanvasOptions> = (options) => {
  7. const renderer = new Renderer();
  8. return new Canvas({renderer, ...options});
  9. }
  10. CanvasRenderer.props = {};