zrender源码分析4--初始化Painter绘图模块2

入口2: 渲染

// zrender_demo.html
zr.render();

// zrender.js
/**
 * 渲染
 * 
 * @param {Function} callback  渲染结束后回调函数
 * todo:增加缓动函数
 */
ZRender.prototype.render = function (callback) {
	this.painter.render(callback);
	return this;
};

然后我们看看Painter是如何渲染的。(这边的回调是undefined)

1. 先关闭正在显示的数据加载提示

// Painter.js
/**
 * 首次绘图,创建各种dom和context
 * 
 * @param {Function=} callback 绘画结束后的回调函数
 */
Painter.prototype.render = function (callback) {
	if (this.isLoading()) {
		this.hideLoading();
	}

	//......
	return this;
};

2. 检查_maxZlevel是否变大,如是则同步创建需要的Canvas。这次并不需要更新。

this._syncMaxZlevelCanvase();
/**
 * 检查_maxZlevel是否变大,如是则同步创建需要的Canvas
 * 
 * @private
 */
Painter.prototype._syncMaxZlevelCanvase = function () {
	var curMaxZlevel = this.storage.getMaxZlevel();
	if (this._maxZlevel < curMaxZlevel) {
		//实体
		for (var i = this._maxZlevel + 1; i <= curMaxZlevel; i++) {
			var canvasElem = createDom(i, 'canvas', this);
			this._domList[i] = canvasElem;
			this._domRoot.insertBefore(canvasElem, this._domList.hover);
			if (vmlCanvasManager) {
				vmlCanvasManager.initElement(canvasElem);
			}

			var canvasCtx = canvasElem.getContext('2d');
			this._ctxList[i] = canvasCtx;
			if (devicePixelRatio != 1) { 
				canvasCtx.scale(devicePixelRatio, devicePixelRatio);
			}
		}
		this._maxZlevel = curMaxZlevel;
	}
};

3. 依然是好习惯,先清空已有内容。这边的clearLayer() API比较复杂,晚点再细究吧。

//清空已有内容,render默认为首次渲染
this.clear();
/**
 * 清除hover层外所有内容
 */
Painter.prototype.clear = function () {
	for (var k in this._ctxList) {
		if (k == 'hover') {
			continue;
		}

		this.clearLayer(k);
	}

	return this;
};

this._ctxList的值如下,这边只需要清空非高亮画布

QQ截图20140926145246

4. 升序遍历,shape上的zlevel指定绘画图层的z轴层叠

//升序遍历,shape上的zlevel指定绘画图层的z轴层叠
this.storage.iterShape(
	this._brush({ all : true }),
	{ normal: 'up' }
);
/**
 * 遍历迭代器
 * 
 * @param {Function} fun 迭代回调函数,return true终止迭代
 * @param {Object=} option 迭代参数,缺省为仅降序遍历常规形状
 *     hover : true 是否迭代高亮层数据
 *     normal : 'down' | 'up' | 'free' 是否迭代常规数据,迭代时是否指定及z轴顺序
 */
Storage.prototype.iterShape = function (fun, option) {
	// ..... 
	// 设置option默认值,默认降序遍历
	if (option.hover) {
		//高亮层数据遍历
		for (var i = 0, l = this._hoverElements.length; i < l; i++) {
			if (fun(this._hoverElements[i])) {
				return this;
			}
		}
	}

	var zlist;
	var len;
	if (typeof option.normal != 'undefined') {
		//z轴遍历: 'down' | 'up' | 'free'
		switch (option.normal) {
			case 'down':
				// 降序遍历,高层优先
				//......
				break;
			case 'up':
				//升序遍历,底层优先
				for (var i = 0, l = this._zElements.length; i < l; i++) {
					zlist = this._zElements[i];
					if (zlist) {
						len = zlist.length;
						for (var k = 0; k < len; k++) {
							if (fun(zlist[k])) {
								return this;
							}
						}
					}
				}
				break;
			// case 'free':
			default:
				//无序遍历
				for (var i in this._elements) {
					if (fun(this._elements[i])) {
						return this;
					}
				}
				break;
		}
	}

	return this;
};  

还记得之前初始化Painter时提到的_zElements不,当时说的就是根据zlevel来组织画布,这边就用到了。状态如下:

QQ截图20140926150044

遍历中,会对circle进行刷画图像

QQ截图20140926150510

function(shape) {
	if ((changedZlevel.all || changedZlevel[shape.zlevel])
		&& !shape.invisible
	) {
		var ctx = ctxList[shape.zlevel];
		if (ctx) {
			if (!shape.onbrush //没有onbrush
				//有onbrush并且调用执行返回false或undefined则继续粉刷
				|| (shape.onbrush && !shape.onbrush(ctx, false))
			) {
				if (config.catchBrushException) {
					try {
						shape.brush(ctx, false, updatePainter);
					}
					catch(error) {
						log(
							error,
							'brush error of ' + shape.type,
							shape
						);
					}
				}
				else {
					shape.brush(ctx, false, updatePainter);
				}
			}
		}
		else {
			log(
				'can not find the specific zlevel canvas!'
			);
		}
	}
};   

其中shape.brush()暂时不细究。等下一轮吧。

5. update到最新则清空标志位。Storage中只是清空了_changedZlevel。

// update到最新则清空标志位
this.storage.clearChangedZlevel();
// Storage.js
Storage.prototype.clearChangedZlevel = function () {
	this._changedZlevel = {};
	return this;
};

6. callback为undefined,所以下面的不执行。

/**
 * 首次绘图,创建各种dom和context
 * 
 * @param {Function=} callback 绘画结束后的回调函数
 */
Painter.prototype.render = function (callback) {
	// .......
	// 这部分代码刚才都分析过
	
	if (typeof callback == 'function') {
		callback();
	}

	return this;
};

Painter的初步分析到此为止。接下来分析先Handler,再细究Painter中跳过的部分。

原文地址:https://www.cnblogs.com/leftthen/p/3994971.html