1.echarts是什么?

关键字:data visualization,canvas,chart

Echarts是基于轻量级的canvas类库,纯javaScript实现,MVC封装,数据驱动,一款直观、生动,可交互,可个性化定制的数据图表。

 

2.为什么Echarts基于canvas类库?

svg与canvas是两个可以选择的类库之一,其中svg的交互性更好,性能较弱,不适用于移动端,在绘制数万个点时会崩溃;而canvas的渲染速度和性能更好,echarts在canvas上构建一层MVC层使得它可以像svg一样交互。

 

3.为什么说Echarts是基于轻量级的类库?

因为Echarts是纯javaScript实现,所以它是一个轻量级的产品,侵入性较小,依赖的东西少,也就是说在换掉框架时对项目影响比较小。

 

4.什么是数据驱动?

所谓数据驱动是指你只需做的是定义图形数据,就可以实现绘图。

 

5.Echarts的特点有哪些?

三个特点,重要性和优先级依次递减。

设计效果必须直观、生动;

能够交互;

可个性化定制.

 

6.为什么说Echarts是MVC封装?

 

javascript和echarts的参考文献 echarts论文_Storage

 

Echarts总体结构是基于MVC架构的,各部分的主要作用是:

Storage(M):模型层,实现图形数据的增删改查(CURD)管理。

Painter(V):视图层,实现canvas元素的生命周期管理,即视图渲染、更新控制、绘图。

Handler(C):控制层,事件交互处理,实现完整的dom事件模拟封装。

从下面的代码片段可知,Storage是一个类似数据的仓库,提供各种数据的读、写、改、删等操作。Painter持有了Storage对象,也就是说结构图中视图层与模型层存在R(read)关系,即Painter需要读取Storage中的数据进行绘图。Handler持有了Storage对象和Painter对象,也就是结构图中控制层与模型层存在CURD关系,即Handler通过访问Storage对象提供的数据增删改查操作实现事件交互处理所需的数据部分;而结构图中控制层与视图层存在call关系,即Handler通过访问Painter对象提供的视图操作实现事件交互处理的视图部分。

Storage :
    /**
     * 内容仓库 (M)
     * @alias module:zrender/Storage
     * @constructor
     */
    var Storage = function () {
        this._roots = [];
 
        this._displayList = [];
 
        this._displayListLen = 0;
    };
Painter :
 /**
     * @alias module:zrender/Painter
     * @constructor
     * @param {HTMLElement} root 绘图容器
     * @param {module:zrender/Storage} storage
     * @param {Object} opts
     */
    var Painter = function (root, storage, opts) {
        // In node environment using node-canvas
        var singleCanvas = !root.nodeName // In node ?
            || root.nodeName.toUpperCase() === 'CANVAS';
 
        this._opts = opts = util.extend({}, opts || {});
 
        /**
         * @type {number}
         */
        this.dpr = opts.devicePixelRatio || config.devicePixelRatio;
        /**
         * @type {boolean}
         * @private
         */
        this._singleCanvas = singleCanvas;
        /**
         * 绘图容器
         * @type {HTMLElement}
         */
        this.root = root;
 
        var rootStyle = root.style;
 
        if (rootStyle) {
            rootStyle['-webkit-tap-highlight-color'] = 'transparent';
            rootStyle['-webkit-user-select'] =
            rootStyle['user-select'] =
            rootStyle['-webkit-touch-callout'] = 'none';
 
            root.innerHTML = '';
        }
 
        /**
         * @type {module:zrender/Storage}
         */
        this.storage = storage;
 
        /**
         * @type {Array.<number>}
         * @private
         */
        var zlevelList = this._zlevelList = [];
 
        /**
         * @type {Object.<string, module:zrender/Layer>}
         * @private
         */
        var layers = this._layers = {};
 
        /**
         * @type {Object.<string, Object>}
         * @type {private}
         */
        this._layerConfig = {};
 
        if (!singleCanvas) {
            this._width = this._getSize(0);
            this._height = this._getSize(1);
 
            var domRoot = this._domRoot = createRoot(
                this._width, this._height
            );
            root.appendChild(domRoot);
        }
        else {
            if (opts.width != null) {
                root.width = opts.width;
            }
            if (opts.height != null) {
                root.height = opts.height;
            }
            // Use canvas width and height directly
            var width = root.width;
            var height = root.height;
            this._width = width;
            this._height = height;
 
            // Create layer if only one given canvas
            // Device pixel ratio is fixed to 1 because given canvas has its specified width and height
            var mainLayer = new Layer(root, this, 1);
            mainLayer.initContext();
            // FIXME Use canvas width and height
            // mainLayer.resize(width, height);
            layers[0] = mainLayer;
            zlevelList.push(0);
 
            this._domRoot = root;
        }
 
        // Layers for progressive rendering
        this._progressiveLayers = [];
 
        /**
         * @type {module:zrender/Layer}
         * @private
         */
        this._hoverlayer;
 
        this._hoverElements = [];
    };
Handler :
    /**
     * @alias module:zrender/Handler
     * @constructor
     * @extends module:zrender/mixin/Eventful
     * @param {module:zrender/Storage} storage Storage instance.
     * @param {module:zrender/Painter} painter Painter instance.
     * @param {module:zrender/dom/HandlerProxy} proxy HandlerProxy instance.
     * @param {HTMLElement} painterRoot painter.root (not painter.getViewportRoot()).
     */
    var Handler = function(storage, painter, proxy, painterRoot) {
        Eventful.call(this);
 
        this.storage = storage;
 
        this.painter = painter;
 
        this.painterRoot = painterRoot;
 
        proxy = proxy || new EmptyProxy();
 
        /**
         * Proxy of event. can be Dom, WebGLSurface, etc.
         */
        this.proxy = proxy;
 
        // Attach handler
        proxy.handler = this;
 
        /**
         * {target, topTarget}
         * @private
         * @type {Object}
         */
        this._hovered = {};
 
        /**
         * @private
         * @type {Date}
         */
        this._lastTouchMoment;
 
        /**
         * @private
         * @type {number}
         */
        this._lastX;
 
        /**
         * @private
         * @type {number}
         */
        this._lastY;
 
 
        Draggable.call(this);
 
        util.each(handlerNames, function (name) {
            proxy.on && proxy.on(name, this[name], this);
        }, this);
    };