antvis/G2

渲染进 @antv/g DisplayObject #4211

pearmini posted onGitHub

渲染进 @antv/g Group 元素

G2 除了能把 options 渲染成一个真实的 Canvas 或者 SVG 元素之外,还可以把图表渲染进一个 g 中的 DisplayObject。

开始使用

// 底层的使用方式
import { Canvas, Group } from '@antv/g';
import { Renderer } from '@antv/g-canvas';
import { renderToMountedElement } from 'runtime';

// 创建一个 group 并且挂载
const canvas = new Canvas({
  container: 'app',
  renderer: new Renderer()
});
const g = new Group();
canvas.append(g);

// 把图表渲染进这个挂载好的 group
const context = { group: g };
renderToMountedElement(options);
// 上层的使用方式
import { Canvas, Group } from '@antv/g';
import { Renderer } from '@antv/g-canvas';
import { Chart } from '@antv/g2';

// 创建一个 group 并且挂载
const canvas = new Canvas({
  container: 'app',
  renderer: new Renderer()
});
const g = new Group();
canvas.append(g);

// 把图表渲染进这个挂载好的 group
const chart = new Chart({
  container: g
});

// 声明可视化 ....

chart.render();

设计

  1. runtime 新增 renderToMountedElement 方法,该方法和 render 有以下两点不同:
  • context 参数中的 Canvas 替换成一个 Group 元素,并且 context 是必选的。同时 context 提供的 Group 元素是挂载好的,否者不能正常执行动画。
  • 返回值从一个真实的 DOM 节点,变成了一个 G 的 Group。
import { Group } from '@anvt/g';

const context = {
  group: new Group()
};

// 第一次渲染
renderToMountedElement(options, context);
// 第二次渲染
renderToMountedElement(newOptions, context);

这里新增 renderToMountedElement 而不是把该能力放入 render 里面的原因是:runtime 里面的方法是比较底层的,所以希望每个方法更干净一点,不要有这种分支判断。就像 React 里面的 render 和 renderToString 一样。上层 API 合成一个就好(对用户友好)。

  1. chart api 的 container 支持 g 中的 element。如果 container 类型是 g 里面的 DisplayObject,chart.render 调用 runtime 的 renderToMountedElement 方法;否者原有逻辑。

任务

  • 第一个 PR:runtime 增加 renderToMountedElement 方法
  • 第二个 PR:api 通过 render 方法提供 renderToMountedElement 的能力

基本规范

为了减少 CR 成本,请遵循以下的基本规范:

  • 合理设计函数接口,让每个函数做的事情合理。
  • 命名原则:尽量简洁,不要太长。
    // Primitive
    // 根据上下文命名即可,不需要突出类型
    const count = 1;
    const name = 'jim';
    

// Array const fruits = ['apple', 'orange', 'pear']; // 复数 const X = [1, 2, 3]; // 首字母大写(X) const matrix = [[1, 2, 3], [4, 5, 6,]]; // 特定语意

// Object // 单数形式 const scale = { x: new ScaleLinear(), y: new ScaleOrdinal() }

// Set 或者 WeakSet,同 Array const marks = new Set();

// Map 或者 WeakMap // 根据 id 获得名字 const idName = new Map(); // 两个单词:第一个是 key,第二个是 value

// 特殊语意 const circle = new Circle(); const store = new Map(); store.set(circle, { fill: 'red' });


- 非循环情况不要用 let。
```js
// Bad
let a;
if (b === 1) {
  a = 1;
} else if (b === 2) {
  a = 2;
} else {
  a = 3
}

// Good
function getA() {
  if (b === 1) {
    return 1;
  } else if (b === 2) {
    return 2;
  } else {
    return 3;
  }
}

const a = getA();
  • 使用可迭代容器的原生方法,这类方法不要使用 lodash 或者 antv/util 里的方法。
// Bad
import { map } from '@antv/util';
const A = [1, 2, 3];
const B = map(a, d => d * 2);

// Good
const A = [1, 2, 3];
const B = A.map(d => d * 2);
  • 复用逻辑抽象成一个函数,不要出现直接 copy 代码的情况。

现在 Lottie 播放器设计的 API 也是类似的,把 Lottie 渲染到一个已挂载的 Group(或者任意元素)上:

import { loadAnimation } from '@antv/g-lottie-player';

// 解析 Lottie 文件
const ballAnimation = loadAnimation(bouncy_ball_json, { loop: true });

canvas.addEventListener(CanvasEvent.READY, () => {
  // 提供一个已挂载的元素
  const wrapper = new Group();
  canvas.appendChild(wrapper);

  // 将 Lottie 渲染到该元素上
  ballAnimation.renderToMountedDisplayObject(wrapper);
  ballAnimation.pause();

  // 进行其它变换,例如平移
  wrapper.translate(100, 100);
});
posted by xiaoiver over 2 years ago

嗯嗯,直接叫 renderToGroup 确实不太准确,但我感觉 renderToMountedDisplayObject 会不会太长了?不过这个名字很准确!

posted by pearmini over 2 years ago

Fund this Issue

$0.00
Funded

Pull requests