ZRender源码解析
2026-05-02 14:37:16
452
分类:echarts
zrender作为echarts的绘图库,具有强大便捷的canvas绘图功能,内置了一些常用图形并可以自定义图形。
zrender现在已经4.0版本了,但是我从新从1.0看起,了解整个项目的变化。1.0是从2013年开始的,代码里面只看到一个作者-林峰。
设计模式-MVC模式
MVC核心封装实现图形仓库、视图渲染和交互控制:
Stroage(M) : shape数据CURD管理
Painter(V) : canvase元素生命周期管理,视图渲染,绘画,更新控制
Handler(C) : 事件交互处理,实现完整dom事件模拟封装
shape : 图形实体,分而治之的图形策略,可定义扩展
tool : 绘画扩展相关实用方法,工具及脚手架
下面是zrender的代码分析:
V1.0.0版本
没有做代码分割,zrender对象,Stroage,Painter,Handler都在核心脚本zrender.js中。根据目录,有动画类、图形形状类、工具类。

var self = {};
var zrender = self; // 提供MVC内部反向使用静态方法
...
/**
* zrender初始化
* 不让外部直接new ZRender实例,为啥?
* 不为啥,提供全局可控同时减少全局污染和降低命名冲突的风险!
*
* @param {HTMLElement} dom dom对象,不帮你做document.getElementById了
* @param {Object=} params 个性化参数,如自定义shape集合,带进来就好
*
* @return {ZRender} ZRender实例
*/
self.init = function(dom, params){...}
self.dispose = function(zi){...}
...
/**
* ZRender接口类,对外可用的所有接口都在这里!!
* storage(M)、painter(V)、handler(C)为内部私有类,外部接口不可见
* 非get接口统一返回self支持链式调用~
*
* @param {string} id 唯一标识
* @param {HTMLElement} dom dom对象,不帮你做document.getElementById
* @param {Object=} params 个性化参数,如自定义shape集合,带进来就好
*
* @return {ZRender} ZRender实例
*/
function ZRender(id, dom, params){
...
var storage = new Storage(shapeLibrary);
var painter = new Painter(dom, storage, shapeLibrary);
var handler = new Handler(dom, storage, painter, shapeLibrary);
// 动画控制
var Animation = require('./animation/animation');
...
}
/**
* 内容仓库 (M)
* @param {Object} shape 图形库
*/
function Storage(shape){...}
/**
* 绘图类 (V)
* @param {HTMLElement} root 绘图区域
* @param {storage} storage Storage实例
* @param {Object} shape 图形库
*/
function Painter(root, storage, shape){
...
var _domList = {}; //canvas dom元素
var _ctxList = {}; //canvas 2D context对象,与domList对应
var _maxZlevel = 0; //最大zlevel,缓存记录
var _loadingTimer;
var _domRoot = document.createElement('div');
// 避免页面选中的尴尬
_domRoot.onselectstart = function() {
return false;
};
...
function _init() {
...
//下面就是很关键的创建canvas的部分了
//创建各层canvas
//背景
_domList['bg'] = _createDom('bg','div');
_domRoot.appendChild(_domList['bg']);
//实体
for (var i = 0; i <= _maxZlevel; i++) {
_domList[i] = _createDom(i,'canvas');
_domRoot.appendChild(_domList[i]);
if (G_vmlCanvasManager) {
G_vmlCanvasManager.initElement(_domList[i]);
}
_ctxList[i] = _domList[i].getContext('2d');
}
//高亮
_domList['hover'] = _createDom('hover','canvas');
_domList['hover'].id = '_zrender_hover_';
_domRoot.appendChild(_domList['hover']);
if (G_vmlCanvasManager) {
G_vmlCanvasManager.initElement(_domList['hover']);
}
_ctxList['hover'] = _domList['hover'].getContext('2d');
}
}
/**
* 控制类 (C)
* @param {HTMLElement} root 绘图区域
* @param {storage} storage Storage实例
* @param {painter} painter Painter实例
* @param {Object} shape 图形库
*
* 分发事件支持详见config.EVENT
*/
function Handler(root, storage, painter, shape){...}ZRender的实例

V2.0.0版本
发布于2014年7月
当更新到2.0版本的时候发现zrender已经和Stroage,Painter,Handler分离。而且ZRender类采用了原型的写法。

下面是ZRender的实例,Stroage,Painter,Handler的实例也都暴露了出来。

到这里为止,我发现多图形的动画还是有点卡,没有缓存功能。缓存可以分为数据缓存,即用二进制数组实现,特别是当数据图形比较多的时候。还可以用canvas图形缓存,特别是图形有重复且很多动画的情况。
v2.1.0版本
发布于2015年6月
加入了混入模式,其他代码细节改动非常大。
混入模式参考:http://blog.vr-seesee.com/detail/129
v3.0.0版本
发布于2016年1月
这个版本整个结构改动都非常大,但是依然是MVC模式。
v3.6.0