在part-2中我们重点讨论了G6的数据灌入与Node/Edge实例的创建。第三章,我们来讨论,这些数据挂载在group中是如何绘制的。
这里的核心函数便是canavs.draw()
render() {
Util.each(data.nodes, node => { self.add(NODE, node)});
Util.each(data.edges, edge => {self.add(EDGE, edge)});
self.paint();
}
paint() {
this.emit('beforepaint');
this.get('canvas').draw();
this.emit('afterpaint');
}
这块的逻辑是这样的。
- G支持canvas和svg两种绘图方式,因此this._cfg.painter就是通过用户配置的render后获取不同painter实例
- 查看下图的调用栈,可知,draw —> _drawGroup—>递归执行_drawGroup得到最后一层children 即用户添加的shapes —> 执行drawShape
shape是谁?
是用户自定义shape,它由group.addShape()方法创建,实例化的过程如下 /g/src/core/group.js
Shape在 /g/src/shapes/*.js
addShape(type, cfg) {
const canvas = this.get('canvas');
cfg.canvas = canvas;
cfg.type = type;
const rst = new Shape[shapeType](cfg);
this.add(rst);
return rst;
},
Shape.drawInner在哪?
很显然,Circle实例的drawInner方法继承与Shape,/g/src/core/shape.js
,在父类Shape上,没有createPath等方法,需要子类自己去实现。
Util.augment(Shape, isPointInPath, {
isShape: true,
drawInner(context) {
const self = this;
self.createPath(context);
self.afterPath(context);
},
})
核心!createPath
我们以Circle为例,createPath完成核心的绘制工作 /g/src/shapes/circle.js
这里就只有canvas API,详见MDN
const Util = require('../util/index');
const Shape = require('../core/shape');
const Circle = function(cfg) {
Circle.superclass.constructor.call(this, cfg);
};
Util.extend(Circle, Shape);
Util.augment(Circle, {
type: 'circle',
createPath(context) {
const attrs = this._attrs;
const cx = attrs.x;
const cy = attrs.y;
const r = attrs.r;
context.beginPath();
context.arc(cx, cy, r, 0, Math.PI * 2, false);
context.closePath();
}
});
module.exports = Circle;