/*! | |
* ECharts, a javascript interactive chart library. | |
* | |
* Copyright (c) 2015, Baidu Inc. | |
* All rights reserved. | |
* | |
* LICENSE | |
* https://github.com/ecomfe/echarts/blob/master/LICENSE.txt | |
*/ | |
/** | |
* echarts | |
* | |
* @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。 | |
* @author Kener (@Kener-林峰, kener.linfeng@gmail.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.2.7'; | |
self.dependencies = { | |
zrender: '2.1.1' | |
}; | |
/** | |
* 入口方法 | |
*/ | |
self.init = function (dom, theme) { | |
var zrender = require('zrender'); | |
if ((zrender.version.replace('.', '') - 0) < (self.dependencies.zrender.replace('.', '') - 0)) { | |
console.error( | |
'ZRender ' + zrender.version | |
+ ' 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].canvasSupported = _canvasSupported; | |
_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) { | |
// Fxxk IE11 for breaking initialization without a warrant; | |
// Just set something to let it be! | |
// by kener 2015-01-09 | |
dom.innerHTML = ''; | |
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', 'MOUSEOUT', | |
'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); | |
self._messageCenterOutSide.dispatchWithContext(type, eventPackage, that); | |
// 如下注掉的代码,@see: https://github.com/ecomfe/echarts-discuss/issues/3 | |
// if (type != 'HOVER' && type != 'MOUSEOUT') { // 频繁事件直接抛出 | |
// 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 != 'MOUSEOUT' && 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')); | |
if (_zr.getWidth() === 0 || _zr.getHeight() === 0) { | |
console.error('Dom’s width & height should be ready before init.'); | |
} | |
}, | |
/** | |
* 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 | |
); | |
} | |
} | |
}, | |
/** | |
* 鼠标移出事件,响应zrender事件,包装后分发到Echarts层 | |
*/ | |
_onmouseout: function (param) { | |
if (param.target) { | |
var ecData = this._eventPackage(param.target); | |
if (ecData && ecData.seriesIndex != null) { | |
this._messageCenter.dispatch( | |
ecConfig.EVENT.MOUSEOUT, | |
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.refreshNextFrame(); | |
} | |
}, | |
/** | |
* 动态类型切换响应 | |
*/ | |
_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, | |
seriesName: (ecData.get(target, 'series') || {}).name, | |
dataIndex: dataIndex, | |
data: ecData.get(target, 'data'), | |
name: ecData.get(target, 'name'), | |
value: ecData.get(target, 'value'), | |
special: ecData.get(target, 'special') | |
}; | |
} | |
return; | |
}, | |
_noDataCheck: function(magicOption) { | |
var series = magicOption.series; | |
for (var i = 0, l = series.length; i < l; i++) { | |
if (series[i].type == ecConfig.CHART_TYPE_MAP | |
|| (series[i].data && series[i].data.length > 0) | |
|| (series[i].markPoint && series[i].markPoint.data && series[i].markPoint.data.length > 0) | |
|| (series[i].markLine && series[i].markLine.data && series[i].markLine.data.length > 0) | |
|| (series[i].nodes && series[i].nodes.length > 0) | |
|| (series[i].links && series[i].links.length > 0) | |
|| (series[i].matrix && series[i].matrix.length > 0) | |
|| (series[i].eventList && series[i].eventList.length > 0) | |
) { | |
return false; // 存在任意数据则为非空数据 | |
} | |
} | |
var loadOption = (this._option && this._option.noDataLoadingOption) | |
|| this._themeConfig.noDataLoadingOption | |
|| ecConfig.noDataLoadingOption | |
|| { | |
text: (this._option && this._option.noDataText) | |
|| this._themeConfig.noDataText | |
|| ecConfig.noDataText, | |
effect: (this._option && this._option.noDataEffect) | |
|| this._themeConfig.noDataEffect | |
|| ecConfig.noDataEffect | |
}; | |
// 空数据 | |
this.clear(); | |
this.showLoading(loadOption); | |
return true; | |
}, | |
/** | |
* 图表渲染 | |
*/ | |
_render: function (magicOption) { | |
this._mergeGlobalConifg(magicOption); | |
if (this._noDataCheck(magicOption)) { | |
return; | |
} | |
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', 'roamController', | |
'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', 'animationDurationUpdate', | |
'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] != null | |
? this._themeConfig[mergeItem] | |
: ecConfig[mergeItem]; | |
} | |
} | |
// 数值系列的颜色列表,不传则采用内置颜色,可配数组,借用zrender实例注入,会有冲突风险,先这样 | |
var themeColor = magicOption.color; | |
if (!(themeColor && themeColor.length)) { | |
themeColor = this._themeConfig.color || ecConfig.color; | |
} | |
this._zr.getColor = function (idx) { | |
var zrColor = require('zrender/tool/color'); | |
return zrColor.getColor(idx, themeColor); | |
}; | |
if (!_canvasSupported) { | |
// 不支持Canvas的强制关闭动画 | |
magicOption.animation = false; | |
magicOption.addDataAnimation = false; | |
} | |
}, | |
/** | |
* 万能接口,配置图表实例任何可配置选项,多次调用时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的合并 | |
* @param {boolean=} 默认false。keepTimeLine 表示从timeline组件调用而来, | |
* 表示当前行为是timeline的数据切换,保持timeline, | |
* 反之销毁timeline。 详见Issue #1601 | |
*/ | |
_setOption: function (option, notMerge, keepTimeLine) { | |
if (!notMerge && this._option) { | |
this._option = zrUtil.merge( | |
this.getOption(), | |
zrUtil.clone(option), | |
true | |
); | |
} | |
else { | |
this._option = zrUtil.clone(option); | |
!keepTimeLine && this._timeline && this._timeline.dispose(); | |
} | |
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; | |
var self = this; | |
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 (optionRestore.xAxis[axisIdx].type == null | |
|| 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; | |
var chartAnimationCount = 0; | |
var chartAnimationDone = function () { | |
chartAnimationCount--; | |
if (chartAnimationCount === 0) { | |
animationDone(); | |
} | |
}; | |
for (var i = 0, l = chartList.length; i < l; i++) { | |
if (magicOption.addDataAnimation && chartList[i].addDataAnimation) { | |
chartAnimationCount++; | |
chartList[i].addDataAnimation(params, chartAnimationDone); | |
} | |
} | |
// dataZoom同步数据 | |
this.component.dataZoom && this.component.dataZoom.syncOption(magicOption); | |
this._option = magicOption; | |
function animationDone() { | |
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 | |
); | |
} | |
if (!magicOption.addDataAnimation) { | |
setTimeout(animationDone, 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' || markOpt[key] == null) { | |
// 简单类型或新值直接赋值 | |
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.merge( | |
zrUtil.clone(textStyle), | |
this._themeConfig.textStyle | |
), | |
ecConfig.textStyle | |
); | |
textStyle.textFont = finalTextStyle.fontStyle + ' ' | |
+ finalTextStyle.fontWeight + ' ' | |
+ finalTextStyle.fontSize + 'px ' | |
+ finalTextStyle.fontFamily; | |
textStyle.text = loadingOption.text | |
|| (this._option && this._option.loadingText) | |
|| this._themeConfig.loadingText | |
|| ecConfig.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 | |
|| (this._option && this._option.loadingEffect) | |
|| this._themeConfig.loadingEffect | |
|| ecConfig.loadingEffect | |
] | |
|| effectList.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 'macarons': | |
theme = require('./theme/macarons'); | |
break; | |
case 'infographic': | |
theme = require('./theme/infographic'); | |
break; | |
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); | |
this._themeConfig = theme; | |
} | |
if (!_canvasSupported) { // IE8- | |
var textStyle = this._themeConfig.textStyle; | |
textStyle && textStyle.fontFamily && textStyle.fontFamily2 | |
&& (textStyle.fontFamily = textStyle.fontFamily2); | |
textStyle = ecConfig.textStyle; | |
textStyle.fontFamily = 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 = {}; | |
this.dom.style.backgroundColor = null; | |
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; | |
}); |