标签:style blog http color io os 使用 ar for
上一篇说到:ZRender源码分析2:Storage(Model层),这次咱看来看看Painter-View层
Painter这个类主要负责MVC中的V(View)层,负责将Storage中的shape对象绘制到canvas中,包括了:更新、渲染、变化大小、导出、修改等操作。
Painter这个类还是很明显的构造函数,然后把方法赋值到Painter.prototype上,无新奇之处,下面为示例代码。只有在Painter.js末尾有一个内部的createDom函数,
很明显,传入id,type(tagName),painter(用来确定宽高)来创建一个新的dom元素,
并且这个dom元素的宽高与painter的相同,tagname为type,绝对定位,拥有一个自定义属性key为ata-zr-dom-id,value为id。
function Painter(root,stroage) {
this.root = xxxx;
}
Painter.prototype.render = function () {};
Painter.prototype.refresh = function () {};
Painter.prototype.update = function () {};
Painter.prototype.clear = function () {};
.....
/**
* 创建dom
*
* @inner
* @param {string} id dom id 待用
* @param {string} type dom type,such as canvas, div etc.
* @param {Painter} painter painter instance
*/
function createDom(id, type, painter) {
var newDom = document.createElement(type);
var width = painter._width;
var height = painter._height;
// 没append呢,请原谅我这样写,清晰~
newDom.style.position = ‘absolute‘;
newDom.style.left = 0;
newDom.style.top = 0;
newDom.style.width = width + ‘px‘;
newDom.style.height = height + ‘px‘;
newDom.setAttribute(‘width‘, width * devicePixelRatio);
newDom.setAttribute(‘height‘, height * devicePixelRatio);
// id不作为索引用,避免可能造成的重名,定义为私有属性
newDom.setAttribute(‘data-zr-dom-id‘, id);
return newDom;
}
/**
* 绘图类 (V)
*
* @param {HTMLElement} root 绘图区域
* @param {storage} storage Storage实例
*/
function Painter(root, storage) {
this.root = root;
this.storage = storage;
root.innerHTML = ‘‘;
this._width = this._getWidth(); // 宽,缓存记录
this._height = this._getHeight(); // 高,缓存记录
var domRoot = document.createElement(‘div‘);
this._domRoot = domRoot;
//domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬
domRoot.style.position = ‘relative‘;
domRoot.style.overflow = ‘hidden‘;
domRoot.style.width = this._width + ‘px‘;
domRoot.style.height = this._height + ‘px‘;
root.appendChild(domRoot);
this._domList = {}; //canvas dom元素
this._ctxList = {}; //canvas 2D context对象,与domList对应
this._domListBack = {};
this._ctxListBack = {};
this._zLevelConfig = {}; // 每个zLevel 的配置,@config clearColor
this._maxZlevel = storage.getMaxZlevel(); //最大zlevel,缓存记录
// this._loadingTimer
this._loadingEffect = new BaseLoadingEffect({});
this.shapeToImage = this._createShapeToImageProcessor();
// 创建各层canvas
// 背景
this._domList.bg = createDom(‘bg‘, ‘div‘, this);
domRoot.appendChild(this._domList.bg);
var canvasElem;
var canvasCtx;
/**
* 每一个level,就是一个canvas
*
* DOM结构
* root
* ->domRoot
* ->canvas level1
* ->canvas level2
* ->canvas level3
* ->canvas hover_level
*
* _domList保存所有的DOM引用
* {
* 1:CanvasHTMLElement
* 2:CanvasHTMLElement
* 3:CanvasHTMLElement
* hover:CanvasHTMLElement
* }
*
* ctxList保存所有的canvas.getContext(‘2d‘)引用
* {
* 1:CanvasContext
* 2:CanvasContext
* 3:CanvasContext
* hover:CanvasContext
* }
*/
// 实体
for (var i = 0; i <= this._maxZlevel; i++) {
canvasElem = createDom(i, ‘canvas‘, this);
domRoot.appendChild(canvasElem);
this._domList[i] = canvasElem;
vmlCanvasManager && vmlCanvasManager.initElement(canvasElem); // excanvas method
this._ctxList[i] = canvasCtx = canvasElem.getContext(‘2d‘);
if (devicePixelRatio != 1) {
canvasCtx.scale(devicePixelRatio, devicePixelRatio);
}
}
// 高亮
canvasElem = createDom(‘hover‘, ‘canvas‘, this);
canvasElem.id = ‘_zrender_hover_‘;
domRoot.appendChild(canvasElem);
this._domList.hover = canvasElem;
vmlCanvasManager && vmlCanvasManager.initElement(canvasElem); // excanvas method
this._domList.hover.onselectstart = returnFalse;
this._ctxList.hover = canvasCtx = canvasElem.getContext(‘2d‘);
if (devicePixelRatio != 1) { //处理视网膜
canvasCtx.scale(devicePixelRatio, devicePixelRatio);
}
}
Painter.prototype._getWidth = function() {
var root = this.root;
var stl = root.currentStyle
|| document.defaultView.getComputedStyle(root);
return ((root.clientWidth || parseInt(stl.width, 10))
- parseInt(stl.paddingLeft, 10) // 请原谅我这比较粗暴
- parseInt(stl.paddingRight, 10)).toFixed(0) - 0;
/**
* 这里用实际的width减去了左右的padding
* 为什么不考虑将这两个方法就行重载?
*/
};
Painter.prototype._getHeight = function () {
var root = this.root;
var stl = root.currentStyle
|| document.defaultView.getComputedStyle(root);
return ((root.clientHeight || parseInt(stl.height, 10))
- parseInt(stl.paddingTop, 10) // 请原谅我这比较粗暴
- parseInt(stl.paddingBottom, 10)).toFixed(0) - 0;
};
//////////////以下为zrender.js中代码////////////////////
/**
* 将常规shape转成image shape
*/
ZRender.prototype.shapeToImage = function(e, width, height) {
var id = guid();
return this.painter.shapeToImage(id, e, width, height);
};
//////////////以下为Painter.js中代码////////////////////
Painter.prototype._createShapeToImageProcessor = function () {
if (vmlCanvasManager) {
return doNothing;
}
var painter = this;
var canvas = document.createElement(‘canvas‘);
var ctx = canvas.getContext(‘2d‘);
var devicePixelRatio = window.devicePixelRatio || 1;
return function (id, e, width, height) {
return painter._shapeToImage(
id, e, width, height,
canvas, ctx, devicePixelRatio
);
};
};
Painter.prototype._shapeToImage = function (
id, shape, width, height,
canvas, ctx, devicePixelRatio
) {
canvas.style.width = width + ‘px‘;
canvas.style.height = height + ‘px‘;
canvas.setAttribute(‘width‘, width * devicePixelRatio);
canvas.setAttribute(‘height‘, height * devicePixelRatio);
ctx.clearRect(0, 0, width * devicePixelRatio, height * devicePixelRatio);
var shapeTransform = {
position : shape.position,
rotation : shape.rotation,
scale : shape.scale
};
shape.position = [0, 0, 0];
shape.rotation = 0;
shape.scale = [1, 1];
if (shape) {
shape.brush(ctx, false);
}
var ImageShape = require( ‘./shape/Image‘ );
var imgShape = new ImageShape({
id : id,
style : {
x : 0,
y : 0,
// TODO 直接使用canvas而不是通过base64
image : canvas.toDataURL()
}
});
if (shapeTransform.position != null) {
imgShape.position = shape.position = shapeTransform.position;
}
if (shapeTransform.rotation != null) {
imgShape.rotation = shape.rotation = shapeTransform.rotation;
}
if (shapeTransform.scale != null) {
imgShape.scale = shape.scale = shapeTransform.scale;
}
return imgShape;
};
/**
* 构造类继承关系
*
* @param {Function} clazz 源类
* @param {Function} baseClazz 基类
*/
function inherits(clazz, baseClazz) {
var clazzPrototype = clazz.prototype;
function F() {}
F.prototype = baseClazz.prototype;
clazz.prototype = new F();
for (var prop in clazzPrototype) {
clazz.prototype[prop] = clazzPrototype[prop];
}
clazz.constructor = clazz;
}
因为接下来的讲解之中,在loadingEffect和Shape对象中,都会有JS继承的出现,zrender/tool/util.js中有一个inherits的方法,实现了完美继承。 有兴趣的同学们可以看看下面两个,我就不详细的说了。
因为Painter的内容牵扯较多,关于Shape对象不详细说道说道又无法进行,说以下篇咱们看看Shape到底是怎么组织的,等下下篇,再从来Painter类
标签:style blog http color io os 使用 ar for
原文地址:http://www.cnblogs.com/hhstuhacker/p/zrender-source-painter-part1.html