text: /*!
   * ECharts, a javascript interactive chart library.
   *  
   * Copyright (c) 2014, Baidu Inc.
   * All rights reserved.
   * 
   * LICENSE
   * https://github.com/ecomfe/echarts/blob/master/LICENSE.txt
   */
  
  /**
   * echarts
   *
   * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。
   * @author Kener (@Kener-林峰, linzhifeng@baidu.com)
   *
   */
  define(function (require) {
      var ecConfig = require('./config');
      var zrUtil = require('zrender/tool/util');
      var zrEvent = require('zrender/tool/event');
      
      var self = {};
      
      var _canvasSupported = require('zrender/tool/env').canvasSupported;
      var _idBase = new Date() - 0;
      var _instances = {};    // ECharts实例map索引
      var DOM_ATTRIBUTE_KEY = '_echarts_instance_';
      
      self.version = '2.0.2';
      self.dependencies = {
          zrender : '2.0.2'
      };
      /**
       * 入口方法 
       */
      self.init = function (dom, theme) {
          var zrender = require('zrender');
          if (((zrender.version || '1.0.3').replace('.', '') - 0)
              < (self.dependencies.zrender.replace('.', '') - 0)
          ) {
              console.error(
                  'ZRender ' + (zrender.version || '1.0.3-') 
                  + ' is too old for ECharts ' + self.version 
                  + '. Current version need ZRender ' 
                  + self.dependencies.zrender + '+'
              );
          }
              
          dom = dom instanceof Array ? dom[0] : dom;
  
          // dom与echarts实例映射索引
          var key = dom.getAttribute(DOM_ATTRIBUTE_KEY);
          if (!key) {
              key = _idBase++;
              dom.setAttribute(DOM_ATTRIBUTE_KEY, key);
          }
  
          if (_instances[key]) {
              // 同一个dom上多次init，自动释放已有实例
              _instances[key].dispose();
          }
          _instances[key] = new Echarts(dom);
          _instances[key].id = key;
          _instances[key].setTheme(theme);
          
          return  _instances[key];
      };
      
      /**
       * 通过id获得ECharts实例，id可在实例化后读取 
       */
      self.getInstanceById = function (key) {
          return _instances[key];
      };
  
      /**
       * 消息中心
       */
      function MessageCenter() {
          zrEvent.Dispatcher.call(this);
      }
      zrUtil.merge(MessageCenter.prototype, zrEvent.Dispatcher.prototype, true);
  
      /**
       * 基于zrender实现Echarts接口层
       * @param {HtmlElement} dom 必要
       */
      function Echarts(dom) {
          this._themeConfig = zrUtil.clone(ecConfig);
  
          this.dom = dom;
          // this._zr;
          // this._option;                    // curOption clone
          // this._optionRestore;             // for restore;
          // this._island;
          // this._toolbox;
          // this._timeline;
          // this._refreshInside;             // 内部刷新标志位
          
          this._connected = false;
          this._status = {                    // 用于图表间通信
              dragIn : false,
              dragOut : false,
              needRefresh : false
          };
          this._curEventType = false;         // 破循环信号灯
          this._chartList = [];               // 图表实例
  
          this._messageCenter = new MessageCenter();
  
          this._messageCenterOutSide = new MessageCenter();    // Echarts层的外部消息中心，做Echarts层的消息转发
          
          // resize方法经常被绑定到window.resize上，闭包一个this
          this.resize = this.resize();
          
          // 初始化::构造函数
          this._init();
      }
      
      /**
       * ZRender EVENT
       * 
       * @inner
       * @const
       * @type {Object}
       */
      var ZR_EVENT = require('zrender/config').EVENT;
  
      /**
       * 要绑定监听的zrender事件列表
       * 
       * @const
       * @inner
       * @type {Array}
       */
      var ZR_EVENT_LISTENS = [
          'CLICK', 'DBLCLICK', 'MOUSEOVER', 
          'DRAGSTART', 'DRAGEND', 'DRAGENTER', 'DRAGOVER', 'DRAGLEAVE', 'DROP'
      ];
  
      /**
       * 对echarts的实例中的chartList属性成员，逐个进行方法调用，遍历顺序为逆序
       * 由于在事件触发的默认行为处理中，多次用到相同逻辑，所以抽象了该方法
       * 由于所有的调用场景里，最多只有两个参数，基于性能和体积考虑，这里就不使用call或者apply了
       * 
       * @inner
       * @param {ECharts} ecInstance ECharts实例
       * @param {string} methodName 要调用的方法名
       * @param {*} arg0 调用参数1
       * @param {*} arg1 调用参数2
       * @param {*} arg2 调用参数3
       */
      function callChartListMethodReverse(ecInstance, methodName, arg0, arg1, arg2) {
          var chartList = ecInstance._chartList;
          var len = chartList.length;
  
          while (len--) {
              var chart = chartList[len];
              if (typeof chart[methodName] === 'function') {
                  chart[methodName](arg0, arg1, arg2);
              }
          }
      }
  
      Echarts.prototype = {
          /**
           * 初始化::构造函数
           */ 
          _init : function () {
              var self = this;
              var _zr = require('zrender').init(this.dom);
              this._zr = _zr;
  
              // wrap: n,e,d,t for name event data this
              this._messageCenter.dispatch = function(type, event, eventPackage, that) {
                  eventPackage = eventPackage || {};
                  eventPackage.type = type;
                  eventPackage.event = event;
  
                  self._messageCenter.dispatchWithContext(type, eventPackage, that);
                  if (type != 'HOVER') {
                      setTimeout(function(){
                          self._messageCenterOutSide.dispatchWithContext(
                              type, eventPackage, that
                          );
                      },50);
                  }
                  else {
                      self._messageCenterOutSide.dispatchWithContext(
                          type, eventPackage, that
                      );
                  }
              };
              
              this._onevent = function(param){
                  return self.__onevent(param);
              };
              for (var e in ecConfig.EVENT) {
                  if (e != 'CLICK' && e != 'DBLCLICK' && e != 'HOVER' && e != 'MAP_ROAM') {
                      this._messageCenter.bind(ecConfig.EVENT[e], this._onevent, this);
                  }
              }
  
  
              var eventBehaviors = {};
              this._onzrevent = function (param) {
                  return self[eventBehaviors[ param.type ]](param);
              };
  
              // 挂载关心的事件
              for (var i = 0, len = ZR_EVENT_LISTENS.length; i < len; i++) {
                  var eventName = ZR_EVENT_LISTENS[i];
                  var eventValue = ZR_EVENT[eventName];
                  eventBehaviors[eventValue] = '_on' + eventName.toLowerCase();
                  _zr.on(eventValue, this._onzrevent);
              }
  
              this.chart = {};            // 图表索引
              this.component = {};        // 组件索引
              
              // 内置图表
              // 孤岛
              var Island = require('./chart/island');
              this._island = new Island(this._themeConfig, this._messageCenter, _zr, {}, this);
              this.chart.island = this._island;
              
              // 内置通用组件
              // 工具箱
              var Toolbox = require('./component/toolbox');
              this._toolbox = new Toolbox(this._themeConfig, this._messageCenter, _zr, {}, this);
              this.component.toolbox = this._toolbox;
              
              var componentLibrary = require('./component');
              componentLibrary.define('title', require('./component/title'));
              componentLibrary.define('tooltip', require('./component/tooltip'));
              componentLibrary.define('legend', require('./component/legend'));
          },
  
          /**
           * ECharts事件处理中心 
           */
          __onevent : function (param){
              param.__echartsId = param.__echartsId || this.id;
  
              // 来自其他联动图表的事件
              var fromMyself = (param.__echartsId == this.id);
              
              if (!this._curEventType) {
                  this._curEventType = param.type;
              }
              
              switch (param.type) {
                  case ecConfig.EVENT.LEGEND_SELECTED :
                      this._onlegendSelected(param);
                      break;
                  case ecConfig.EVENT.DATA_ZOOM :
                      if (!fromMyself) {
                          var dz = this.component.dataZoom;
                          if (dz) {
                              dz.silence(true);
                              dz.absoluteZoom(param.zoom);
                              dz.silence(false);
                          }
                      }
                      this._ondataZoom(param);
                      break;        
                  case ecConfig.EVENT.DATA_RANGE :
                      fromMyself && this._ondataRange(param);
                      break;        
                  case ecConfig.EVENT.MAGIC_TYPE_CHANGED :
                      if (!fromMyself) {
                          var tb = this.component.toolbox;
                          if (tb) {
                              tb.silence(true);
                              tb.setMagicType(param.magicType);
                              tb.silence(false);
                          }
                      }
                      this._onmagicTypeChanged(param);
                      break;        
                  case ecConfig.EVENT.DATA_VIEW_CHANGED :
                      fromMyself && this._ondataViewChanged(param);
                      break;        
                  case ecConfig.EVENT.TOOLTIP_HOVER :
                      fromMyself && this._tooltipHover(param);
                      break;        
                  case ecConfig.EVENT.RESTORE :
                      this._onrestore();
                      break;        
                  case ecConfig.EVENT.REFRESH :
                      fromMyself && this._onrefresh(param);
                      break;
                  // 鼠标同步
                  case ecConfig.EVENT.TOOLTIP_IN_GRID :
                  case ecConfig.EVENT.TOOLTIP_OUT_GRID :
                      if (!fromMyself) {
                          // 只处理来自外部的鼠标同步
                          var grid = this.component.grid;
                          if (grid) {
                              this._zr.trigger(
                                  'mousemove',
                                  {
                                      connectTrigger : true,
                                      zrenderX : grid.getX() + param.x * grid.getWidth(),
                                      zrenderY : grid.getY() + param.y * grid.getHeight()
                                  }
                              );
                          }
                      } 
                      else if (this._connected) {
                          // 来自自己，并且存在多图联动，空间坐标映射修改参数分发
                          var grid = this.component.grid;
                          if (grid) {
                              param.x = (param.event.zrenderX - grid.getX()) / grid.getWidth();
                              param.y = (param.event.zrenderY - grid.getY()) / grid.getHeight();
                          }
                      }
                      break;
                  /*
                  case ecConfig.EVENT.RESIZE :
                  case ecConfig.EVENT.DATA_CHANGED :
                  case ecConfig.EVENT.PIE_SELECTED :
                  case ecConfig.EVENT.MAP_SELECTED :
                      break;
                  */
              }
              
              // 多图联动，只做自己的一级事件分发，避免级联事件循环
              if (this._connected && fromMyself && this._curEventType == param.type) { 
                  for (var c in this._connected) {
                      this._connected[c].connectedEventHandler(param);
                  }
                  // 分发完毕后复位
                  this._curEventType = null;
              }
              
              if (!fromMyself || (!this._connected && fromMyself)) {  // 处理了完联动事件复位
                  this._curEventType = null;
              }
          },
  
          /**
           * 点击事件，响应zrender事件，包装后分发到Echarts层
           */
          _onclick : function (param) {
              callChartListMethodReverse(this, 'onclick', param);
  
              if (param.target) {
                  var ecData = this._eventPackage(param.target);
                  if (ecData && ecData.seriesIndex != null) {
                      this._messageCenter.dispatch(
                          ecConfig.EVENT.CLICK,
                          param.event,
                          ecData,
                          this
                      );
                  }
              }
          },
          
          /**
           * 双击事件，响应zrender事件，包装后分发到Echarts层
           */
          _ondblclick : function (param) {
              callChartListMethodReverse(this, 'ondblclick', param);
  
              if (param.target) {
                  var ecData = this._eventPackage(param.target);
                  if (ecData && ecData.seriesIndex != null) {
                      this._messageCenter.dispatch(
                          ecConfig.EVENT.DBLCLICK,
                          param.event,
                          ecData,
                          this
                      );
                  }
              }
          },
  
           /**
            * 鼠标移入事件，响应zrender事件，包装后分发到Echarts层
            */
          _onmouseover : function (param) {
              if (param.target) {
                  var ecData = this._eventPackage(param.target);
                  if (ecData && ecData.seriesIndex != null) {
                      this._messageCenter.dispatch(
                          ecConfig.EVENT.HOVER,
                          param.event,
                          ecData,
                          this
                      );
                  }
              }
          },
  
          /**
           * dragstart回调，可计算特性实现
           */
          _ondragstart : function (param) {
              // 复位用于图表间通信拖拽标识
              this._status = {
                  dragIn : false,
                  dragOut : false,
                  needRefresh : false
              };
  
              callChartListMethodReverse(this, 'ondragstart', param);
          },
  
          /**
           * dragging回调，可计算特性实现
           */
          _ondragenter : function (param) {
              callChartListMethodReverse(this, 'ondragenter', param);
          },
  
          /**
           * dragstart回调，可计算特性实现
           */
          _ondragover : function (param) {
              callChartListMethodReverse(this, 'ondragover', param);
          },
          
          /**
           * dragstart回调，可计算特性实现
           */
          _ondragleave : function (param) {
              callChartListMethodReverse(this, 'ondragleave', param);
          },
  
          /**
           * dragstart回调，可计算特性实现
           */
          _ondrop : function (param) {
              callChartListMethodReverse(this, 'ondrop', param, this._status);
              this._island.ondrop(param, this._status);
          },
  
          /**
           * dragdone回调 ，可计算特性实现
           */
          _ondragend : function (param) {
              callChartListMethodReverse(this, 'ondragend', param, this._status);
  
              this._timeline && this._timeline.ondragend(param, this._status);
              this._island.ondragend(param, this._status);
  
              // 发生过重计算
              if (this._status.needRefresh) {
                  this._syncBackupData(this._option);
  
                  var messageCenter = this._messageCenter;
                  messageCenter.dispatch(
                      ecConfig.EVENT.DATA_CHANGED,
                      param.event,
                      this._eventPackage(param.target),
                      this
                  );
                  messageCenter.dispatch(ecConfig.EVENT.REFRESH, null, null, this);
              }
          },
  
          /**
           * 图例选择响应
           */
          _onlegendSelected : function (param) {
              // 用于图表间通信
              this._status.needRefresh = false;
              callChartListMethodReverse(this, 'onlegendSelected', param, this._status);
  
              if (this._status.needRefresh) {
                  this._messageCenter.dispatch(ecConfig.EVENT.REFRESH, null, null, this);
              }
          },
  
          /**
           * 数据区域缩放响应 
           */
          _ondataZoom : function (param) {
              // 用于图表间通信
              this._status.needRefresh = false;
              callChartListMethodReverse(this, 'ondataZoom', param, this._status);
  
              if (this._status.needRefresh) {
                  this._messageCenter.dispatch(ecConfig.EVENT.REFRESH, null, null, this);
              }
          },
  
          /**
           * 值域漫游响应 
           */
          _ondataRange : function (param) {
              this._clearEffect();
              // 用于图表间通信
              this._status.needRefresh = false;
              callChartListMethodReverse(this, 'ondataRange', param, this._status);
              
              // 没有相互影响，直接刷新即可
              if (this._status.needRefresh) {
                  this._zr.refresh();
              }
          },
  
          /**
           * 动态类型切换响应 
           */
          _onmagicTypeChanged : function () {
              this._clearEffect();
              this._render(this._toolbox.getMagicOption());
          },
  
          /**
           * 数据视图修改响应 
           */
          _ondataViewChanged : function (param) {
              this._syncBackupData(param.option);
              this._messageCenter.dispatch(
                  ecConfig.EVENT.DATA_CHANGED,
                  null,
                  param,
                  this
              );
              this._messageCenter.dispatch(ecConfig.EVENT.REFRESH, null, null, this);
          },
          
          /**
           * tooltip与图表间通信 
           */
          _tooltipHover : function (param) {
              var tipShape = [];
              callChartListMethodReverse(this, 'ontooltipHover', param, tipShape);
          },
  
          /**
           * 还原 
           */
          _onrestore : function () {
              this.restore();
          },
  
          /**
           * 刷新 
           */
          _onrefresh : function (param) {
              this._refreshInside = true;
              this.refresh(param);
              this._refreshInside = false;
          },
          
          /**
           * 数据修改后的反向同步dataZoom持有的备份数据 
           */
          _syncBackupData : function (curOption) {
              this.component.dataZoom && this.component.dataZoom.syncBackupData(curOption);
          },
  
          /**
           * 打包Echarts层的事件附件
           */
          _eventPackage : function (target) {
              if (target) {
                  var ecData = require('./util/ecData');
                  
                  var seriesIndex = ecData.get(target, 'seriesIndex');
                  var dataIndex = ecData.get(target, 'dataIndex');
                  
                  dataIndex = seriesIndex != -1 && this.component.dataZoom
                              ? this.component.dataZoom.getRealDataIndex(
                                  seriesIndex,
                                  dataIndex
                                )
                              : dataIndex;
                  return {
                      seriesIndex : seriesIndex,
                      dataIndex : dataIndex,
                      data : ecData.get(target, 'data'),
                      name : ecData.get(target, 'name'),
                      value : ecData.get(target, 'value'),
                      special : ecData.get(target, 'special')
                  };
              }
              return;
          },
  
          /**
           * 图表渲染 
           */
          _render : function (magicOption) {
              this._mergeGlobalConifg(magicOption);
  
              var bgColor = magicOption.backgroundColor;
              if (bgColor) {
                  if (!_canvasSupported 
                      && bgColor.indexOf('rgba') != -1
                  ) {
                      // IE6~8对RGBA的处理，filter会带来其他颜色的影响
                      var cList = bgColor.split(',');
                      this.dom.style.filter = 'alpha(opacity=' +
                          cList[3].substring(0, cList[3].lastIndexOf(')')) * 100
                          + ')';
                      cList.length = 3;
                      cList[0] = cList[0].replace('a', '');
                      this.dom.style.backgroundColor = cList.join(',') + ')';
                  }
                  else {
                      this.dom.style.backgroundColor = bgColor;
                  }
              }
              
              this._zr.clearAnimation();
              this._chartList = [];
  
              var chartLibrary = require('./chart');
              var componentLibrary = require('./component');
              
              if (magicOption.xAxis || magicOption.yAxis) {
                  magicOption.grid = magicOption.grid || {};
                  magicOption.dataZoom = magicOption.dataZoom || {};
              }
              
              var componentList = [
                  'title', 'legend', 'tooltip', 'dataRange',
                  'grid', 'dataZoom', 'xAxis', 'yAxis', 'polar'
              ];
              
              var ComponentClass;
              var componentType;
              var component;
              for (var i = 0, l = componentList.length; i < l; i++) {
                  componentType = componentList[i];
                  component = this.component[componentType];
  
                  if (magicOption[componentType]) {
                      if (component) {
                          component.refresh && component.refresh(magicOption);
                      }
                      else {
                          ComponentClass = componentLibrary.get(
                              /^[xy]Axis$/.test(componentType) ? 'axis' : componentType
                          );
                          component = new ComponentClass(
                              this._themeConfig, this._messageCenter, this._zr,
                              magicOption, this, componentType
                          );
                          this.component[componentType] = component;
                      }
                      this._chartList.push(component);
                  }
                  else if (component) {
                      component.dispose();
                      this.component[componentType] = null;
                      delete this.component[componentType];
                  }
              }
  
              var ChartClass;
              var chartType;
              var chart;
              var chartMap = {};      // 记录已经初始化的图表
              for (var i = 0, l = magicOption.series.length; i < l; i++) {
                  chartType = magicOption.series[i].type;
                  if (!chartType) {
                      console.error('series[' + i + '] chart type has not been defined.');
                      continue;
                  }
  
                  if (!chartMap[chartType]) {
                      chartMap[chartType] = true;
                      ChartClass = chartLibrary.get(chartType);
                      if (ChartClass) {
                          if (this.chart[chartType]) {
                              chart = this.chart[chartType];
                              chart.refresh(magicOption);
                          }
                          else {
                              chart = new ChartClass(
                                  this._themeConfig, this._messageCenter, this._zr,
                                  magicOption, this
                              );
                          }
                          this._chartList.push(chart);
                          this.chart[chartType] = chart;
                      }
                      else {
                          console.error(chartType + ' has not been required.');
                      }
                  }
              }
              
              // 已有实例但新option不带这类图表的实例释放
              for (chartType in this.chart) {
                  if (chartType != ecConfig.CHART_TYPE_ISLAND  && !chartMap[chartType]) {
                      this.chart[chartType].dispose();
                      this.chart[chartType] = null;
                      delete this.chart[chartType];
                  }
              }
              
              this.component.grid && this.component.grid.refixAxisShape(this.component);
  
              this._island.refresh(magicOption);
              this._toolbox.refresh(magicOption);
              
              magicOption.animation && !magicOption.renderAsImage
                  ? this._zr.refresh()
                  : this._zr.render();
              
              var imgId = 'IMG' + this.id;
              var img = document.getElementById(imgId);
              if (magicOption.renderAsImage && _canvasSupported) {
                  // IE8- 不支持图片渲染形式
                  if (img) {
                      // 已经渲染过则更新显示
                      img.src = this.getDataURL(magicOption.renderAsImage);
                  }
                  else {
                      // 没有渲染过插入img dom
                      img = this.getImage(magicOption.renderAsImage);
                      img.id = imgId;
                      img.style.position = 'absolute';
                      img.style.left = 0;
                      img.style.top = 0;
                      this.dom.firstChild.appendChild(img);
                  }
                  this.un();
                  this._zr.un();
                  this._disposeChartList();
                  this._zr.clear();
              }
              else if (img) {
                  // 删除可能存在的img
                  img.parentNode.removeChild(img);
              }
              img = null;
              
              this._option = magicOption;
          },
  
          /**
           * 还原 
           */
          restore : function () {
              this._clearEffect();
              this._option = zrUtil.clone(this._optionRestore);
              this._disposeChartList();
              this._island.clear();
              this._toolbox.reset(this._option, true);
              this._render(this._option);
          },
  
          /**
           * 刷新 
           * @param {Object=} param，可选参数，用于附带option，内部同步用，外部不建议带入数据修改，无法同步 
           */
          refresh : function (param) {
              this._clearEffect();
              param = param || {};
              var magicOption = param.option;
              
              // 外部调用的refresh且有option带入
              if (!this._refreshInside && magicOption) {
                  // 做简单的差异合并去同步内部持有的数据克隆，不建议带入数据
                  // 开启数据区域缩放、拖拽重计算、数据视图可编辑模式情况下，当用户产生了数据变化后无法同步
                  // 如有带入option存在数据变化，请重新setOption
                  magicOption = this.getOption();
                  zrUtil.merge(magicOption, param.option, true);
                  zrUtil.merge(this._optionRestore, param.option, true);
                  this._toolbox.reset(magicOption);
              }
              
              this._island.refresh(magicOption);
              this._toolbox.refresh(magicOption);
              
              // 停止动画
              this._zr.clearAnimation();
              // 先来后到，安顺序刷新各种图表，图表内部refresh优化检查magicOption，无需更新则不更新~
              for (var i = 0, l = this._chartList.length; i < l; i++) {
                  this._chartList[i].refresh && this._chartList[i].refresh(magicOption);
              }
              this.component.grid && this.component.grid.refixAxisShape(this.component);
              this._zr.refresh();
          },
  
          /**
           * 释放图表实例
           */
          _disposeChartList : function () {
              this._clearEffect();
  
              // 停止动画
              this._zr.clearAnimation();
  
              var len = this._chartList.length;
              while (len--) {
                  var chart = this._chartList[len];
  
                  if (chart) {
                      var chartType = chart.type;
                      this.chart[chartType] && delete this.chart[chartType];
                      this.component[chartType] && delete this.component[chartType];
                      chart.dispose && chart.dispose();
                  }
              }
  
              this._chartList = [];
          },
  
          /**
           * 非图表全局属性merge~~ 
           */
          _mergeGlobalConifg : function (magicOption) {
              var mergeList = [
                  // 背景颜色
                  'backgroundColor',
                  
                  // 拖拽重计算相关
                  'calculable', 'calculableColor', 'calculableHolderColor',
                  
                  // 孤岛显示连接符
                  'nameConnector', 'valueConnector',
                  
                  // 动画相关
                  'animation', 'animationThreshold', 'animationDuration',
                  'animationEasing', 'addDataAnimation',
                  
                  // 默认标志图形类型列表
                  'symbolList',
                  
                  // 降低图表内元素拖拽敏感度，单位ms，不建议外部干预
                  'DRAG_ENABLE_TIME'
              ];
  
              var len = mergeList.length;
              while (len--) {
                  var mergeItem = mergeList[len];
                  if (magicOption[mergeItem] == null) {
                      magicOption[mergeItem] = this._themeConfig[mergeItem];
                  }
              }
              
              // 数值系列的颜色列表，不传则采用内置颜色，可配数组，借用zrender实例注入，会有冲突风险，先这样
              var themeColor = magicOption.color;
              if (!(themeColor && themeColor.length)) {
                  themeColor = this._themeConfig.color;
              }
  
              this._zr.getColor = function (idx) {
                  var zrColor = require('zrender/tool/color');
                  return zrColor.getColor(idx, themeColor);
              };
          },
          
          /**
           * 万能接口，配置图表实例任何可配置选项，多次调用时option选项做merge处理
           * @param {Object} option
           * @param {boolean=} notMerge 多次调用时option选项是默认是合并（merge）的，
           *                   如果不需求，可以通过notMerger参数为true阻止与上次option的合并
           */
          setOption : function (option, notMerge) {
              if (!option.timeline) {
                  return this._setOption(option, notMerge);
              }
              else {
                  return this._setTimelineOption(option);
              }
          },
          
          /**
           * 万能接口，配置图表实例任何可配置选项，多次调用时option选项做merge处理
           * @param {Object} option
           * @param {boolean=} notMerge 多次调用时option选项是默认是合并（merge）的，
           *                   如果不需求，可以通过notMerger参数为true阻止与上次option的合并
           */
          _setOption : function (option, notMerge) {
              if (!notMerge && this._option) {
                  this._option = zrUtil.merge(
                      this.getOption(),
                      zrUtil.clone(option),
                      true
                  );
              }
              else {
                  this._option = zrUtil.clone(option);
              }
  
              this._optionRestore = zrUtil.clone(this._option);
              
              if (!this._option.series || this._option.series.length === 0) {
                  this._zr.clear();
                  return;
              }
  
              if (this.component.dataZoom                         // 存在dataZoom控件
                  && (this._option.dataZoom                       // 并且新option也存在
                      || (this._option.toolbox
                          && this._option.toolbox.feature
                          && this._option.toolbox.feature.dataZoom
                          && this._option.toolbox.feature.dataZoom.show
                      )
                  )
              ) {
                  // dataZoom同步数据
                  this.component.dataZoom.syncOption(this._option);
              }
              this._toolbox.reset(this._option);
              this._render(this._option);
              return this;
          },
  
          /**
           * 返回内部持有的当前显示option克隆 
           */
          getOption : function () {
              var magicOption = zrUtil.clone(this._option);
              
              var self = this;
              function restoreOption(prop) {
                  var restoreSource = self._optionRestore[prop];
  
                  if (restoreSource) {
                      if (restoreSource instanceof Array) {
                          var len = restoreSource.length;
                          while (len--) {
                              magicOption[prop][len].data = zrUtil.clone(
                                  restoreSource[len].data
                              );
                          }
                      }
                      else {
                          magicOption[prop].data = zrUtil.clone(restoreSource.data);
                      }
                  }
              }
  
              // 横轴数据还原
              restoreOption('xAxis');
              
              // 纵轴数据还原
              restoreOption('yAxis');
              
              // 系列数据还原
              restoreOption('series');
              
              return magicOption;
          },
  
          /**
           * 数据设置快捷接口
           * @param {Array} series
           * @param {boolean=} notMerge 多次调用时option选项是默认是合并（merge）的，
           *                   如果不需求，可以通过notMerger参数为true阻止与上次option的合并。
           */
          setSeries : function (series, notMerge) {
              if (!notMerge) {
                  this.setOption({series: series});
              }
              else {
                  this._option.series = series;
                  this.setOption(this._option, notMerge);
              }
              return this;
          },
  
          /**
           * 返回内部持有的当前显示series克隆 
           */
          getSeries : function () {
              return this.getOption().series;
          },
          
          /**
           * timelineOption接口，配置图表实例任何可配置选项
           * @param {Object} option
           */
          _setTimelineOption : function(option) {
              this._timeline && this._timeline.dispose();
              var Timeline = require('./component/timeline');
              var timeline = new Timeline(
                  this._themeConfig, this._messageCenter, this._zr, option, this
              );
              this._timeline = timeline;
              this.component.timeline = this._timeline;
              
              return this;
          },
          
          /**
           * 动态数据添加
           * 形参为单组数据参数，多组时为数据，内容同[seriesIdx, data, isShift, additionData]
           * @param {number} seriesIdx 系列索引
           * @param {number | Object} data 增加数据
           * @param {boolean=} isHead 是否队头加入，默认，不指定或false时为队尾插入
           * @param {boolean=} dataGrow 是否增长数据队列长度，默认，不指定或false时移出目标数组对位数据
           * @param {string=} additionData 是否增加类目轴(饼图为图例)数据，附加操作同isHead和dataGrow
           */
          addData : function (seriesIdx, data, isHead, dataGrow, additionData) {
              var params = seriesIdx instanceof Array
                  ? seriesIdx
                  : [[seriesIdx, data, isHead, dataGrow, additionData]];
  
              //this._optionRestore 和 magicOption 都要同步
              var magicOption = this.getOption();
              var optionRestore = this._optionRestore;
              for (var i = 0, l = params.length; i < l; i++) {
                  seriesIdx = params[i][0];
                  data = params[i][1];
                  isHead = params[i][2];
                  dataGrow = params[i][3];
                  additionData = params[i][4];
  
                  
                  var seriesItem = optionRestore.series[seriesIdx];
                  var inMethod = isHead ? 'unshift' : 'push';
                  var outMethod = isHead ? 'pop' : 'shift';
                  if (seriesItem) {
                      var seriesItemData = seriesItem.data;
                      var mSeriesItemData = magicOption.series[seriesIdx].data;
  
                      seriesItemData[inMethod](data);
                      mSeriesItemData[inMethod](data);
                      if (!dataGrow) {
                          seriesItemData[outMethod]();
                          data = mSeriesItemData[outMethod]();
                      }
                      
                      
                      if (additionData != null) {
                          var legend;
                          var legendData;
  
                          if (seriesItem.type == ecConfig.CHART_TYPE_PIE
                              && (legend = optionRestore.legend) 
                              && (legendData = legend.data)
                          ) {
                              var mLegendData = magicOption.legend.data;
                              legendData[inMethod](additionData);
                              mLegendData[inMethod](additionData);
  
                              if (!dataGrow) {
                                  var legendDataIdx = zrUtil.indexOf(legendData, data.name);
                                  legendDataIdx != -1 && legendData.splice(legendDataIdx, 1);
                                  
                                  legendDataIdx = zrUtil.indexOf(mLegendData, data.name);
                                  legendDataIdx != -1 && mLegendData.splice(legendDataIdx, 1);
                              }
                          }
                          else if (optionRestore.xAxis != null && optionRestore.yAxis != null) {
                              // x轴类目
                              var axisData;
                              var mAxisData;
                              var axisIdx = seriesItem.xAxisIndex || 0;
  
                              if (typeof optionRestore.xAxis[axisIdx].type == 'undefined'
                                  || optionRestore.xAxis[axisIdx].type == 'category'
                              ) {
                                  axisData = optionRestore.xAxis[axisIdx].data;
                                  mAxisData = magicOption.xAxis[axisIdx].data;
  
                                  axisData[inMethod](additionData);
                                  mAxisData[inMethod](additionData);
                                  if (!dataGrow) {
                                      axisData[outMethod]();
                                      mAxisData[outMethod]();
                                  }
                              }
                              
                              // y轴类目
                              axisIdx = seriesItem.yAxisIndex || 0;
                              if (optionRestore.yAxis[axisIdx].type == 'category') {
                                  axisData = optionRestore.yAxis[axisIdx].data;
                                  mAxisData = magicOption.yAxis[axisIdx].data;
  
                                  axisData[inMethod](additionData);
                                  mAxisData[inMethod](additionData);
                                  if (!dataGrow) {
                                      axisData[outMethod]();
                                      mAxisData[outMethod]();
                                  }
                              }
                          }
                      }
  
                      // 同步图表内状态，动画需要
                      this._option.series[seriesIdx].data = magicOption.series[seriesIdx].data;
                  }
              }
              
              this._zr.clearAnimation();
              var chartList = this._chartList;
              for (var i = 0, l = chartList.length; i < l; i++) {
                  if (magicOption.addDataAnimation && chartList[i].addDataAnimation) {
                      chartList[i].addDataAnimation(params);
                  }
              }
  
              // dataZoom同步数据
              this.component.dataZoom && this.component.dataZoom.syncOption(magicOption);
              
              this._option = magicOption;
              var self = this;
              setTimeout(function (){
                  if (!self._zr) {
                      return; // 已经被释放
                  }
                  self._zr.clearAnimation();
                  for (var i = 0, l = chartList.length; i < l; i++) {
                      // 有addData动画就去掉过渡动画
                      chartList[i].motionlessOnce = 
                          magicOption.addDataAnimation && chartList[i].addDataAnimation;
                  }
                  self._messageCenter.dispatch(
                      ecConfig.EVENT.REFRESH,
                      null,
                      {option: magicOption},
                      self
                  );
              }, magicOption.addDataAnimation ? 500 : 0);
              return this;
          },
  
          /**
           * 动态[标注 | 标线]添加
           * @param {number} seriesIdx 系列索引
           * @param {Object} markData [标注 | 标线]对象，支持多个
           */
          addMarkPoint : function (seriesIdx, markData) {
              return this._addMark(seriesIdx, markData, 'markPoint');
          },
          
          addMarkLine : function (seriesIdx, markData) {
              return this._addMark(seriesIdx, markData, 'markLine');
          },
          
          _addMark : function (seriesIdx, markData, markType) {
              var series = this._option.series;
              var seriesItem;
  
              if (series && (seriesItem = series[seriesIdx])) {
                  var seriesR = this._optionRestore.series;
                  var seriesRItem = seriesR[seriesIdx];
                  var markOpt = seriesItem[markType];
                  var markOptR = seriesRItem[markType];
  
                  markOpt = seriesItem[markType] = markOpt || {data: []};
                  markOptR = seriesRItem[markType] = markOptR || {data: []};
  
                  for (var key in markData) {
                      if (key == 'data') {
                          // 数据concat
                          markOpt.data = markOpt.data.concat(markData.data);
                          markOptR.data = markOptR.data.concat(markData.data);
                      }
                      else if (typeof markData[key] != 'object'
                            || typeof markOpt[key] == 'undefined'
                      ) {
                          // 简单类型或新值直接赋值
                          markOpt[key] = markOptR[key] = markData[key];
                      }
                      else {
                          // 非数据的复杂对象merge
                          zrUtil.merge(markOpt[key], markData[key], true);
                          zrUtil.merge(markOptR[key], markData[key], true);
                      }
                  }
                  
                  var chart = this.chart[seriesItem.type];
                  chart && chart.addMark(seriesIdx, markData, markType);
              }
  
              return this;
          },
          
          /**
           * 动态[标注 | 标线]删除
           * @param {number} seriesIdx 系列索引
           * @param {string} markName [标注 | 标线]名称
           */
          delMarkPoint : function (seriesIdx, markName) {
              return this._delMark(seriesIdx, markName, 'markPoint');
          },
          
          delMarkLine : function (seriesIdx, markName) {
              return this._delMark(seriesIdx, markName, 'markLine');
          },
          
          _delMark : function (seriesIdx, markName, markType) {
              var series = this._option.series;
              var seriesItem;
              var mark;
              var dataArray;
  
              if (!(
                      series 
                      && (seriesItem = series[seriesIdx]) 
                      && (mark = seriesItem[markType])
                      && (dataArray = mark.data)
                  )
              ) {
                  return this;
              }
  
              markName = markName.split(' > ');
              var targetIndex = -1;
              
              for (var i = 0, l = dataArray.length; i < l; i++) {
                  var dataItem = dataArray[i];
                  if (dataItem instanceof Array) {
                      if (dataItem[0].name == markName[0]
                          && dataItem[1].name == markName[1]
                      ) {
                          targetIndex = i;
                          break;
                      }
                  }
                  else if (dataItem.name == markName[0]) {
                      targetIndex = i;
                      break;
                  }
              }
              
              if (targetIndex > -1) {
                  dataArray.splice(targetIndex, 1);
                  this._optionRestore.series[seriesIdx][markType].data.splice(targetIndex, 1);
  
                  var chart = this.chart[seriesItem.type];
                  chart && chart.delMark(seriesIdx, markName.join(' > '), markType);
              }
              
              return this;
          },
          
          /**
           * 获取当前dom 
           */
          getDom : function () {
              return this.dom;
          },
          
          /**
           * 获取当前zrender实例，可用于添加额为的shape和深度控制 
           */
          getZrender : function () {
              return this._zr;
          },
  
          /**
           * 获取Base64图片dataURL
           * @param {string} imgType 图片类型，支持png|jpeg，默认为png
           * @return imgDataURL
           */
          getDataURL : function (imgType) {
              if (!_canvasSupported) {
                  return '';
              }
  
              if (this._chartList.length === 0) {
                  // 渲染为图片
                  var imgId = 'IMG' + this.id;
                  var img = document.getElementById(imgId);
                  if (img) {
                      return img.src;
                  }
              }
  
              // 清除可能存在的tooltip元素
              var tooltip = this.component.tooltip;
              tooltip && tooltip.hideTip();
                  
              switch (imgType) {
                  case 'jpeg':
                      break;
                  default:
                      imgType = 'png';
              }
  
              var bgColor = this._option.backgroundColor;
              if (bgColor && bgColor.replace(' ','') == 'rgba(0,0,0,0)') {
                  bgColor = '#fff';
              }
  
              return this._zr.toDataURL('image/' + imgType, bgColor); 
          },
  
          /**
           * 获取img
           * @param {string} imgType 图片类型，支持png|jpeg，默认为png
           * @return img dom
           */
          getImage : function (imgType) {
              var title = this._optionRestore.title;
              var imgDom = document.createElement('img');
              imgDom.src = this.getDataURL(imgType);
              imgDom.title = (title && title.text) || 'ECharts';
              return imgDom;
          },
          
          /**
           * 获取多图联动的Base64图片dataURL
           * @param {string} imgType 图片类型，支持png|jpeg，默认为png
           * @return imgDataURL
           */
          getConnectedDataURL : function (imgType) {
              if (!this.isConnected()) {
                  return this.getDataURL(imgType);
              }
              
              var tempDom = this.dom;
              var imgList = {
                  'self' : {
                      img : this.getDataURL(imgType),
                      left : tempDom.offsetLeft,
                      top : tempDom.offsetTop,
                      right : tempDom.offsetLeft + tempDom.offsetWidth,
                      bottom : tempDom.offsetTop + tempDom.offsetHeight
                  }
              };
  
              var minLeft = imgList.self.left;
              var minTop = imgList.self.top;
              var maxRight = imgList.self.right;
              var maxBottom = imgList.self.bottom;
  
              for (var c in this._connected) {
                  tempDom = this._connected[c].getDom();
                  imgList[c] = {
                      img : this._connected[c].getDataURL(imgType),
                      left : tempDom.offsetLeft,
                      top : tempDom.offsetTop,
                      right : tempDom.offsetLeft + tempDom.offsetWidth,
                      bottom : tempDom.offsetTop + tempDom.offsetHeight
                  };
  
                  minLeft = Math.min(minLeft, imgList[c].left);
                  minTop = Math.min(minTop, imgList[c].top);
                  maxRight = Math.max(maxRight, imgList[c].right);
                  maxBottom = Math.max(maxBottom, imgList[c].bottom);
              }
              
              var zrDom = document.createElement('div');
              zrDom.style.position = 'absolute';
              zrDom.style.left = '-4000px';
              zrDom.style.width = (maxRight - minLeft) + 'px';
              zrDom.style.height = (maxBottom - minTop) + 'px';
              document.body.appendChild(zrDom);
              
              var zrImg = require('zrender').init(zrDom);
              
              var ImageShape = require('zrender/shape/Image');
              for (var c in imgList) {
                  zrImg.addShape(new ImageShape({
                      style : {
                          x : imgList[c].left - minLeft,
                          y : imgList[c].top - minTop,
                          image : imgList[c].img
                      }
                  }));
              }
              
              zrImg.render();
              var bgColor = this._option.backgroundColor;
              if (bgColor && bgColor.replace(/ /g, '') == 'rgba(0,0,0,0)') {
                  bgColor = '#fff';
              }
              
              var image = zrImg.toDataURL('image/png', bgColor);
              
              setTimeout(function () {
                  zrImg.dispose();
                  zrDom.parentNode.removeChild(zrDom);
                  zrDom = null;
              }, 100);
              
              return image;
          },
          
          /**
           * 获取多图联动的img
           * @param {string} imgType 图片类型，支持png|jpeg，默认为png
           * @return img dom
           */
          getConnectedImage : function (imgType) {
              var title = this._optionRestore.title;
              var imgDom = document.createElement('img');
              imgDom.src = this.getConnectedDataURL(imgType);
              imgDom.title = (title && title.text) || 'ECharts';
              return imgDom;
          },
  
          /**
           * 外部接口绑定事件
           * @param {Object} eventName 事件名称
           * @param {Object} eventListener 事件响应函数
           */
          on : function (eventName, eventListener) {
              this._messageCenterOutSide.bind(eventName, eventListener, this);
              return this;
          },
  
          /**
           * 外部接口解除事件绑定
           * @param {Object} eventName 事件名称
           * @param {Object} eventListener 事件响应函数
           */
          un : function (eventName, eventListener) {
              this._messageCenterOutSide.unbind(eventName, eventListener);
              return this;
          },
          
          /**
           * 多图联动 
           * @param connectTarget{ECharts | Array <ECharts>} connectTarget 联动目标
           */
          connect : function (connectTarget) {
              if (!connectTarget) {
                  return this;
              }
              
              if (!this._connected) {
                  this._connected = {};
              }
              
              if (connectTarget instanceof Array) {
                  for (var i = 0, l = connectTarget.length; i < l; i++) {
                      this._connected[connectTarget[i].id] = connectTarget[i];
                  }
              }
              else {
                  this._connected[connectTarget.id] = connectTarget;
              }
              
              return this;
          },
          
          /**
           * 解除多图联动 
           * @param connectTarget{ECharts | Array <ECharts>} connectTarget 解除联动目标
           */
          disConnect : function (connectTarget) {
              if (!connectTarget || !this._connected) {
                  return this;
              }
              
              if (connectTarget instanceof Array) {
                  for (var i = 0, l = connectTarget.length; i < l; i++) {
                      delete this._connected[connectTarget[i].id];
                  }
              }
              else {
                  delete this._connected[connectTarget.id];
              }
              
              for (var k in this._connected) {
                  return k, this; // 非空
              }
              
              // 空，转为标志位
              this._connected = false;
              return this;
          },
          
          /**
           * 联动事件响应 
           */
          connectedEventHandler : function (param) {
              if (param.__echartsId != this.id) {
                  // 来自其他联动图表的事件
                  this._onevent(param);
              }
          },
          
          /**
           * 是否存在多图联动 
           */
          isConnected : function () {
              return !!this._connected;
          },
          
          /**
           * 显示loading过渡 
           * @param {Object} loadingOption
           */
          showLoading : function (loadingOption) {
              var effectList = {
                  bar : require('zrender/loadingEffect/Bar'),
                  bubble : require('zrender/loadingEffect/Bubble'),
                  dynamicLine : require('zrender/loadingEffect/DynamicLine'),
                  ring : require('zrender/loadingEffect/Ring'),
                  spin : require('zrender/loadingEffect/Spin'),
                  whirling : require('zrender/loadingEffect/Whirling')
              };
              this._toolbox.hideDataView();
  
              loadingOption = loadingOption || {};
  
              var textStyle = loadingOption.textStyle || {};
              loadingOption.textStyle = textStyle;
  
              var finalTextStyle = zrUtil.merge(
                  zrUtil.clone(textStyle),
                  this._themeConfig.textStyle
              );
              textStyle.textFont = finalTextStyle.fontStyle + ' '
                                   + finalTextStyle.fontWeight + ' '
                                   + finalTextStyle.fontSize + 'px '
                                   + finalTextStyle.fontFamily;
  
              textStyle.text = loadingOption.text || this._themeConfig.loadingText;
  
              if (loadingOption.x != null) {
                  textStyle.x = loadingOption.x;
              }
              if (loadingOption.y != null) {
                  textStyle.y = loadingOption.y;
              }
              
              loadingOption.effectOption = loadingOption.effectOption || {};
              loadingOption.effectOption.textStyle = textStyle;
              
              var Effect = loadingOption.effect;
              if (typeof Effect == 'string' || Effect == null) {
                  Effect =  effectList[loadingOption.effect || 'spin'];
              }
              this._zr.showLoading(new Effect(loadingOption.effectOption));
              return this;
          },
  
          /**
           * 隐藏loading过渡 
           */
          hideLoading : function () {
              this._zr.hideLoading();
              return this;
          },
          
          /**
           * 主题设置 
           */
          setTheme : function (theme) {
              if (theme) {
                 if (typeof theme === 'string') {
                      // 默认主题
                      switch (theme) {
                          // case 'themename':
                          //     theme = require('./theme/themename');
                          default:
                              theme = require('./theme/default');
                      }
                  }
                  else {
                      theme = theme || {};
                  }
                  
                  // 复位默认配置
                  // this._themeConfig会被别的对象引用持有
                  // 所以不能改成this._themeConfig = {};
                  for (var key in this._themeConfig) {
                      delete this._themeConfig[key];
                  }
                  for (var key in ecConfig) {
                      this._themeConfig[key] = zrUtil.clone(ecConfig[key]);
                  }
                  
                  // 颜色数组随theme，不merge
                  theme.color && (this._themeConfig.color = []);
                  
                  // 默认标志图形类型列表，不merge
                  theme.symbolList && (this._themeConfig.symbolList = []);
                  
                  // 应用新主题
                  zrUtil.merge(this._themeConfig, zrUtil.clone(theme), true);
              }
              
              if (!_canvasSupported) {   // IE8-
                  this._themeConfig.textStyle.fontFamily = this._themeConfig.textStyle.fontFamily2;
              }
              
              this._timeline && this._timeline.setTheme(true);
              this._optionRestore && this.restore();
          },
  
          /**
           * 视图区域大小变化更新，不默认绑定，供使用方按需调用 
           */
          resize : function () {
              var self = this;
              return function(){
                  self._clearEffect();
                  self._zr.resize();
                  if (self._option && self._option.renderAsImage && _canvasSupported) {
                      // 渲染为图片重走render模式
                      self._render(self._option);
                      return self;
                  }
                  // 停止动画
                  self._zr.clearAnimation();
                  self._island.resize();
                  self._toolbox.resize();
                  self._timeline && self._timeline.resize();
                  // 先来后到，不能仅刷新自己，也不能在上一个循环中刷新，如坐标系数据改变会影响其他图表的大小
                  // 所以安顺序刷新各种图表，图表内部refresh优化无需更新则不更新~
                  for (var i = 0, l = self._chartList.length; i < l; i++) {
                      self._chartList[i].resize && self._chartList[i].resize();
                  }
                  self.component.grid && self.component.grid.refixAxisShape(self.component);
                  self._zr.refresh();
                  self._messageCenter.dispatch(ecConfig.EVENT.RESIZE, null, null, self);
                  return self;
              };
          },
          
          _clearEffect : function() {
              this._zr.modLayer(ecConfig.EFFECT_ZLEVEL, {motionBlur : false});
              this._zr.painter.clearLayer(ecConfig.EFFECT_ZLEVEL);
          },
          
          /**
           * 清除已渲染内容 ，clear后echarts实例可用
           */
          clear : function () {
              this._disposeChartList();
              this._zr.clear();
              this._option = {};
              this._optionRestore = {};
              return this;
          },
  
          /**
           * 释放，dispose后echarts实例不可用
           */
          dispose : function () {
              var key = this.dom.getAttribute(DOM_ATTRIBUTE_KEY);
              key && delete _instances[key];
          
              this._island.dispose();
              this._toolbox.dispose();
              this._timeline && this._timeline.dispose();
              this._messageCenter.unbind();
              this.clear();
              this._zr.dispose();
              this._zr = null;
          }
      };
  
      return self;
  });