• 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等未完待续。

  • 相关阅读:
    Spring Cloud Ribbon实现客户端负载均衡
    Spring Boot 初步小结
    日志配置
    外部属性文件的使用
    运行jar
    类型安全的配置文件
    java动态代理中的invoke方法是如何被自动调用的(转)
    数据库为什么要用B+树结构--MySQL索引结构的实现(转)
    Java transient关键字使用小记(转)
    面试题思考:Java 8 / Java 7 为我们提供了什么新功能
  • 原文地址:https://www.cnblogs.com/leftthen/p/3993436.html
Copyright © 2020-2023  润新知