zrender源码分析--初探如何画一个圆

今天是想看看使用zrender框架如何去,画一个圆,再加“circle”的文字在圆心。

然后开始代码:

如何部署代码,让zrender跑起来这边就不说了,官方例子就有写,地址是:https://github.com/ecomfe/zrender

准备工作如下:

dom中新建一个容器用于绘图:

QQ截图20140928151708

然后直接写代码就可以了。

调用zrender的init接口初始化

// zrender_demo.html
var zr = zrender.init(document.getElementById('main'));

进入init方法,发现做2件事情:A、初始化ZRender;B、将其存入ZRender实例map索引

/**
 * 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;
};

其中guid()是zrender统一的ID生成机制,通过esl加载,然后按需调用:

// zrender.js
var guid = require('./tool/guid');
guid();

// tool/guid.js
/**
 * zrender: 生成唯一id
 *
 * @author errorrik (errorrik@gmail.com)
 */

define(
    function() {
        var idStart = 0x0907;

        return function () {
            return 'zrender__' + (idStart++);
        };
    }
);

进入ZRender接口类,这边体现官网提到的“MVC核心封装实现图形仓库、视图渲染和交互控制”

  • Stroage(M) : shape数据CURD管理

  • Painter(V) : canvas元素生命周期管理,视图渲染,绘画,更新控制

  • Handler(C) : 事件交互处理,实现完整dom事件模拟封装

/**
 * 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、Painter、Handler、animation的初始化暂时不细究跳过

好习惯是每次绘图前,都清空画布

// zrender_demo.html
zr.clear();

zrender执行清空时,清空storage后,再执行painter的clear()方法

// zrender.js
/**
 * 清除当前ZRender下所有类图的数据和显示,clear后MVC和已绑定事件均还存在在,ZRender可用
 */
ZRender.prototype.clear = function () {
	this.storage.del();
	this.painter.clear();
	return this;
};

同样暂不细究storage、painter的清除机制

接下来开始绘图,添加一个圆形

// zrender_demo.html
var color = require('zrender/tool/color');
var colorIdx = 0;
var width = Math.ceil(zr.getWidth());    // 视图宽度
var height = Math.ceil(zr.getHeight());    // 视图高度

F11查看getWidth(),调用painter的方法。getHeight类似实现

// zrender.js
/**
 * 获取视图宽度
 */
ZRender.prototype.getWidth = function() {
	return this.painter.getWidth();
};
// zrender_demo.html
var circle = new CircleShape({
	style : {
		x : 100,
		y : 100,
		r : 50,
		brushType : 'both',
		color : 'rgba(220, 20, 60, 0.8)',          // rgba supported
		strokeColor : color.getColor(colorIdx++),  // getColor from default palette
		lineWidth : 5,
		text :'circle',
		textPosition :'inside'
	},
	hoverable : true,   // default true
	draggable : true,   // default false
	clickable : true,   // default false

	// 可自带任何有效自定义属性
	_name : 'Hello~',
	onclick: function(params){
		alert(params.target._name);
	},

	// 响应事件并动态修改图形元素
	onmousewheel: function(params){
		var eventTool = require('zrender/tool/event');
		var delta = eventTool.getDelta(params.event);
		var r = params.target.style.r;
		r += (delta > 0 ? 1 : -1) * 10;
		if (r < 10) {
			r = 10;
		};
		zr.modShape(params.target.id, {style: {r: r}})
		zr.refresh();
		eventTool.stop(params.event);
	}
});

初始化圆Circle,直接调用基类

// shape/circle.js
function Circle(options) {
 Base.call(this, options);
}

base中先对各属性进行默认值初始化,而后使用传入值覆盖

// shape/base.js
function Base( options ) {
	this.id = options.id || guid();
	this.zlevel = 0;
	this.draggable = false;
	this.clickable = false;
	this.hoverable = true;
	this.position = [0, 0];
	this.rotation = [0, 0, 0];
	this.scale = [1, 1, 0, 0];

	for ( var key in options ) {
		this[ key ] = options[ key ];
	}

	this.style = this.style || {};
}

往storage中添加图形形状

// zrender_demo.html
zr.addShape(circle);
// zrender.js
/**
 * 添加图形形状
 * 
 * @param {Object} shape 形状对象,可用属性全集,详见各shape
 */
ZRender.prototype.addShape = function (shape) {
	this.storage.add(shape);
	return this;
};

执行绘图

// zrender_demo.html
zr.render();

zrender直接调用painter接口渲染

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

Storage、 Painter、handler等未完待续。

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