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中。根据目录,有动画类、图形形状类、工具类。

QQ截图20181024174448.png

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的实例

image.png

V2.0.0版本

发布于2014年7月

当更新到2.0版本的时候发现zrender已经和Stroage,Painter,Handler分离。而且ZRender类采用了原型的写法。

image.png

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

image.png

到这里为止,我发现多图形的动画还是有点卡,没有缓存功能。缓存可以分为数据缓存,即用二进制数组实现,特别是当数据图形比较多的时候。还可以用canvas图形缓存,特别是图形有重复且很多动画的情况。

v2.1.0版本

发布于2015年6月

加入了混入模式,其他代码细节改动非常大。

混入模式参考:http://blog.vr-seesee.com/detail/129

v3.0.0版本

发布于2016年1月

这个版本整个结构改动都非常大,但是依然是MVC模式。

v3.6.0