zrender源碼分析1:總體結構


開始

zrender(Zlevel Render) 是一個輕量級的Canvas類庫,這里是GitHub的網址 點我, 類似的類庫有Kinetic.JSEaselJS。 但貌似都沒有zrender好用(可能是更加符合國人的習慣),強大的圖表工具echarts就是在zrender基礎上建立, 用zrender和echarts做了兩個關於canvas的兩個可視化項目之后,忍不住看了下zrender的項目代碼(也有需要修改源代碼的緣故), 但是翻開之后,代碼的結構比較清晰,注釋也都是中文,比較容易讀懂。最大的感想就是,沒有像jQuery之類的對於代碼極(bian)度(tai)的精簡追求,各種意圖一看便知。 如果對於zrender的api不熟悉,請移步github上,這里只對源碼進行了一些詳(qian)細(xian)的分析。

總體結構

關於總體結構,最貼切的描述恐怕也沒這一張圖來的爽: zrender結構圖 從github將項目clone下來之后,打開src/zrender.js之后,有如下發現:


var _instances = {};    //ZRender實例map索引

var zrender = {};
zrender.version = '2.0.0';

/**
 * zrender初始化
 * 不讓外部直接new ZRender實例,為啥?
 * 不為啥,提供全局可控同時減少全局污染和降低命名沖突的風險!
 *
 * @param {HTMLElement} dom dom對象,不幫你做document.getElementById了
 * @param {Object=} params 個性化參數,如自定義shape集合,帶進來就好
 *
 * @return {ZRender} ZRender實例
 */
zrender.init = function(dom, params) {
    var zi = new ZRender(guid(), dom, params || {});
    _instances[zi.id] = zi;
    return zi;
};

我想這里已經很明顯,用zrender.init(dom)初始化的時候,直接new一個內部的ZRender對象進行返回,原因我想作者已經寫的很明白了(提供全局可控同時減少全局污染和降低命名沖突的風險!) 總比每次new ZRender()好多了,最起碼看起來是這樣,並且把每個實例就行保存,便於維護。 至於周圍的其他的三個方法,dispose,getInstance,delInstance 就沒什么可說的了,不過在項目中,也怎么用得上。


/**
 * zrender實例銷毀,記在_instances里的索引也會刪除了
 * 管生就得管死,可以通過zrender.dispose(zi)銷毀指定ZRender實例
 * 當然也可以直接zi.dispose()自己銷毀
 *
 * @param {ZRender=} zi ZRender對象,不傳則銷毀全部
 */
zrender.dispose = function (zi) {
    if (zi) {
        zi.dispose();
    }
    else {
        for (var key in _instances) {
            _instances[key].dispose();
        }
        _instances = {};
    }

    return zrender;
};

/**
 * 獲取zrender實例
 *
 * @param {string} id ZRender對象索引
 */
zrender.getInstance = function (id) {
    return _instances[id];
};

/**
 * 刪除zrender實例,ZRender實例dispose時會調用,
 * 刪除后getInstance則返回undefined
 * ps: 僅是刪除,刪除的實例不代表已經dispose了~~
 *     這是一個擺脫全局zrender.dispose()自動銷毀的后門,
 *     take care of yourself~
 *
 * @param {string} id ZRender對象索引
 */
zrender.delInstance = function (id) {
    delete _instances[id];
    return zrender;
};

接下來就是核心的ZRender構造函數,這里可以很清晰的看到M(Storage)V(Painter)C(Handler)的結構.


/**
 * ZRender接口類,對外可用的所有接口都在這里!!
 * storage(M)、painter(V)、handler(C)為內部私有類,外部接口不可見
 * 非get接口統一返回支持鏈式調用~
 *
 * @param {string} id 唯一標識
 * @param {HTMLElement} dom dom對象,不幫你做document.getElementById
 *
 * @return {ZRender} ZRender實例
 */
function ZRender(id, dom) {
    this.id = id;
    this.env = require('./tool/env');

    this.storage = new Storage();
    this.painter = new Painter(dom, this.storage);
    this.handler = new Handler(dom, this.storage, this.painter);

    // 動畫控制
    this.animatingShapes = [];
    this.animation = new Animation({
        stage : {
            update : getAnimationUpdater(this)
        }
    });
    this.animation.start();
}
  • Storage只是JS對象級別的對於Shape圖形的增(add/addHover)刪(del,delHover)改(mod)查(get/iterShape/getMaxZlevel等),更像一個數據結構的東西
  • Painter負責真正的繪圖操作,這里是比較繁重的部分
    • 1.負責canvas及其周邊DOM元素的創建與處理
    • 2.負責調用各個Shape(預定義好的)進行繪制
    • 3.提供基本的操作方法,渲染(render)、刷新(refresh)、尺寸變化(resize)、擦除(clear)等
  • Handler負責事件處理,解決基礎的瀏覽器兼容問題、進行事件的注冊與轉發、拖動

至於附加在ZRender的prototype的其他方法,除了關於動畫部分的,其他的都是調用的Storage、Painter、Handler,這里就不再贅述了。

結尾

能力有限,盡力而為,接下來,再詳盡分析各個小模塊吧。 大家也可以觀摩經過我加工過的更加詳細注釋的代碼 通往我的GitHub


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM