接上次分析到初始化ZRender的源码,这次关注绘图模块Painter的初始化
入口1:new Painter(dom, this.storage);
// zrender.js /** * 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(); }
初始化Painter时,传入绘图区域dom、内容仓库实例storage。
并立即备份
// Painter.js /** * 绘图类 (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(); // 高,缓存记录
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; };
新建DIV,设置默认属性并拼接
var domRoot = document.createElement('div'); this._domRoot = domRoot; 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
通过storage获取最大的zlevel
this._maxZlevel = storage.getMaxZlevel(); //最大zlevel,缓存记录
初始化图形加载效果
this._loadingEffect = new BaseLoadingEffect({});
// loadingEffect/Base.js /** * @constructor * * @param {Object} options 选项 * @param {color} options.backgroundColor 背景颜色 * @param {Object} options.textStyle 文字样式,同shape/text.style * @param {number=} options.progress 进度参数,部分特效有用 * @param {Object=} options.effect 特效参数,部分特效有用 * * textStyle:{ * textFont: 'normal 20px Arial' || {textFont}, //文本字体 * color: {color} * } * } */ function Base(options) { this.setOptions(options); } Base.prototype.setOptions = function (options) { this.options = options || {}; };
图形另存为图片方法。很高端的样子,晚点再看吧
this.shapeToImage = this._createShapeToImageProcessor(); 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 ); }; };
准备工作做完了,开始创建各层canvas
首先创建背景
this._domList.bg = createDom('bg', 'div', this); domRoot.appendChild(this._domList.bg);
来看看创建dom元素的createDom吧,高宽取决于父容器
/** * 创建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; }
循环创建各层canvas,vmlCanvasManager是啥,得晚点细究,这边一直为false
var canvasElem; var canvasCtx; // 实体 for (var i = 0; i <= this._maxZlevel; i++) { canvasElem = createDom(i, 'canvas', this); domRoot.appendChild(canvasElem); this._domList[i] = canvasElem; vmlCanvasManager && vmlCanvasManager.initElement(canvasElem); this._ctxList[i] = canvasCtx = canvasElem.getContext('2d'); if (devicePixelRatio != 1) { canvasCtx.scale(devicePixelRatio, devicePixelRatio); } }
创建用于高亮的canva
canvasElem = createDom('hover', 'canvas', this); canvasElem.id = '_zrender_hover_'; domRoot.appendChild(canvasElem); this._domList.hover = canvasElem; vmlCanvasManager && vmlCanvasManager.initElement(canvasElem); this._domList.hover.onselectstart = returnFalse; this._ctxList.hover = canvasCtx = canvasElem.getContext('2d'); if (devicePixelRatio != 1) { canvasCtx.scale(devicePixelRatio, devicePixelRatio); }
我们来看看创建好的Painter实例
未完,待续