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