8b4fad0da99f6f701d753a9f62998c585beddf8b.svn-base 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759
  1. /*!
  2. * ECharts, a javascript interactive chart library.
  3. *
  4. * Copyright (c) 2015, Baidu Inc.
  5. * All rights reserved.
  6. *
  7. * LICENSE
  8. * https://github.com/ecomfe/echarts/blob/master/LICENSE.txt
  9. */
  10. /**
  11. * echarts
  12. *
  13. * @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
  14. * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
  15. *
  16. */
  17. define(function (require) {
  18. var ecConfig = require('./config');
  19. var zrUtil = require('zrender/tool/util');
  20. var zrEvent = require('zrender/tool/event');
  21. var self = {};
  22. var _canvasSupported = require('zrender/tool/env').canvasSupported;
  23. var _idBase = allGetServerTime() - 0;
  24. var _instances = {}; // ECharts实例map索引
  25. var DOM_ATTRIBUTE_KEY = '_echarts_instance_';
  26. self.version = '2.2.7';
  27. self.dependencies = {
  28. zrender: '2.1.1'
  29. };
  30. /**
  31. * 入口方法
  32. */
  33. self.init = function (dom, theme) {
  34. var zrender = require('zrender');
  35. if ((zrender.version.replace('.', '') - 0) < (self.dependencies.zrender.replace('.', '') - 0)) {
  36. console.error(
  37. 'ZRender ' + zrender.version
  38. + ' is too old for ECharts ' + self.version
  39. + '. Current version need ZRender '
  40. + self.dependencies.zrender + '+'
  41. );
  42. }
  43. dom = dom instanceof Array ? dom[0] : dom;
  44. // dom与echarts实例映射索引
  45. var key = dom.getAttribute(DOM_ATTRIBUTE_KEY);
  46. if (!key) {
  47. key = _idBase++;
  48. dom.setAttribute(DOM_ATTRIBUTE_KEY, key);
  49. }
  50. if (_instances[key]) {
  51. // 同一个dom上多次init,自动释放已有实例
  52. _instances[key].dispose();
  53. }
  54. _instances[key] = new Echarts(dom);
  55. _instances[key].id = key;
  56. _instances[key].canvasSupported = _canvasSupported;
  57. _instances[key].setTheme(theme);
  58. return _instances[key];
  59. };
  60. /**
  61. * 通过id获得ECharts实例,id可在实例化后读取
  62. */
  63. self.getInstanceById = function (key) {
  64. return _instances[key];
  65. };
  66. /**
  67. * 消息中心
  68. */
  69. function MessageCenter() {
  70. zrEvent.Dispatcher.call(this);
  71. }
  72. zrUtil.merge(MessageCenter.prototype, zrEvent.Dispatcher.prototype, true);
  73. /**
  74. * 基于zrender实现Echarts接口层
  75. * @param {HtmlElement} dom 必要
  76. */
  77. function Echarts(dom) {
  78. // Fxxk IE11 for breaking initialization without a warrant;
  79. // Just set something to let it be!
  80. // by kener 2015-01-09
  81. dom.innerHTML = '';
  82. this._themeConfig = {}; // zrUtil.clone(ecConfig);
  83. this.dom = dom;
  84. // this._zr;
  85. // this._option; // curOption clone
  86. // this._optionRestore; // for restore;
  87. // this._island;
  88. // this._toolbox;
  89. // this._timeline;
  90. // this._refreshInside; // 内部刷新标志位
  91. this._connected = false;
  92. this._status = { // 用于图表间通信
  93. dragIn: false,
  94. dragOut: false,
  95. needRefresh: false
  96. };
  97. this._curEventType = false; // 破循环信号灯
  98. this._chartList = []; // 图表实例
  99. this._messageCenter = new MessageCenter();
  100. this._messageCenterOutSide = new MessageCenter(); // Echarts层的外部消息中心,做Echarts层的消息转发
  101. // resize方法经常被绑定到window.resize上,闭包一个this
  102. this.resize = this.resize();
  103. // 初始化::构造函数
  104. this._init();
  105. }
  106. /**
  107. * ZRender EVENT
  108. *
  109. * @inner
  110. * @const
  111. * @type {Object}
  112. */
  113. var ZR_EVENT = require('zrender/config').EVENT;
  114. /**
  115. * 要绑定监听的zrender事件列表
  116. *
  117. * @const
  118. * @inner
  119. * @type {Array}
  120. */
  121. var ZR_EVENT_LISTENS = [
  122. 'CLICK', 'DBLCLICK', 'MOUSEOVER', 'MOUSEOUT',
  123. 'DRAGSTART', 'DRAGEND', 'DRAGENTER', 'DRAGOVER', 'DRAGLEAVE', 'DROP'
  124. ];
  125. /**
  126. * 对echarts的实例中的chartList属性成员,逐个进行方法调用,遍历顺序为逆序
  127. * 由于在事件触发的默认行为处理中,多次用到相同逻辑,所以抽象了该方法
  128. * 由于所有的调用场景里,最多只有两个参数,基于性能和体积考虑,这里就不使用call或者apply了
  129. *
  130. * @inner
  131. * @param {ECharts} ecInstance ECharts实例
  132. * @param {string} methodName 要调用的方法名
  133. * @param {*} arg0 调用参数1
  134. * @param {*} arg1 调用参数2
  135. * @param {*} arg2 调用参数3
  136. */
  137. function callChartListMethodReverse(ecInstance, methodName, arg0, arg1, arg2) {
  138. var chartList = ecInstance._chartList;
  139. var len = chartList.length;
  140. while (len--) {
  141. var chart = chartList[len];
  142. if (typeof chart[methodName] === 'function') {
  143. chart[methodName](arg0, arg1, arg2);
  144. }
  145. }
  146. }
  147. Echarts.prototype = {
  148. /**
  149. * 初始化::构造函数
  150. */
  151. _init: function () {
  152. var self = this;
  153. var _zr = require('zrender').init(this.dom);
  154. this._zr = _zr;
  155. // wrap: n,e,d,t for name event data this
  156. this._messageCenter.dispatch = function(type, event, eventPackage, that) {
  157. eventPackage = eventPackage || {};
  158. eventPackage.type = type;
  159. eventPackage.event = event;
  160. self._messageCenter.dispatchWithContext(type, eventPackage, that);
  161. self._messageCenterOutSide.dispatchWithContext(type, eventPackage, that);
  162. // 如下注掉的代码,@see: https://github.com/ecomfe/echarts-discuss/issues/3
  163. // if (type != 'HOVER' && type != 'MOUSEOUT') { // 频繁事件直接抛出
  164. // setTimeout(function(){
  165. // self._messageCenterOutSide.dispatchWithContext(
  166. // type, eventPackage, that
  167. // );
  168. // },50);
  169. // }
  170. // else {
  171. // self._messageCenterOutSide.dispatchWithContext(
  172. // type, eventPackage, that
  173. // );
  174. // }
  175. };
  176. this._onevent = function(param){
  177. return self.__onevent(param);
  178. };
  179. for (var e in ecConfig.EVENT) {
  180. if (e != 'CLICK' && e != 'DBLCLICK'
  181. && e != 'HOVER' && e != 'MOUSEOUT' && e != 'MAP_ROAM'
  182. ) {
  183. this._messageCenter.bind(ecConfig.EVENT[e], this._onevent, this);
  184. }
  185. }
  186. var eventBehaviors = {};
  187. this._onzrevent = function (param) {
  188. return self[eventBehaviors[ param.type ]](param);
  189. };
  190. // 挂载关心的事件
  191. for (var i = 0, len = ZR_EVENT_LISTENS.length; i < len; i++) {
  192. var eventName = ZR_EVENT_LISTENS[i];
  193. var eventValue = ZR_EVENT[eventName];
  194. eventBehaviors[eventValue] = '_on' + eventName.toLowerCase();
  195. _zr.on(eventValue, this._onzrevent);
  196. }
  197. this.chart = {}; // 图表索引
  198. this.component = {}; // 组件索引
  199. // 内置图表
  200. // 孤岛
  201. var Island = require('./chart/island');
  202. this._island = new Island(this._themeConfig, this._messageCenter, _zr, {}, this);
  203. this.chart.island = this._island;
  204. // 内置通用组件
  205. // 工具箱
  206. var Toolbox = require('./component/toolbox');
  207. this._toolbox = new Toolbox(this._themeConfig, this._messageCenter, _zr, {}, this);
  208. this.component.toolbox = this._toolbox;
  209. var componentLibrary = require('./component');
  210. componentLibrary.define('title', require('./component/title'));
  211. componentLibrary.define('tooltip', require('./component/tooltip'));
  212. componentLibrary.define('legend', require('./component/legend'));
  213. if (_zr.getWidth() === 0 || _zr.getHeight() === 0) {
  214. console.error('Dom’s width & height should be ready before init.');
  215. }
  216. },
  217. /**
  218. * ECharts事件处理中心
  219. */
  220. __onevent: function (param){
  221. param.__echartsId = param.__echartsId || this.id;
  222. // 来自其他联动图表的事件
  223. var fromMyself = (param.__echartsId === this.id);
  224. if (!this._curEventType) {
  225. this._curEventType = param.type;
  226. }
  227. switch (param.type) {
  228. case ecConfig.EVENT.LEGEND_SELECTED :
  229. this._onlegendSelected(param);
  230. break;
  231. case ecConfig.EVENT.DATA_ZOOM :
  232. if (!fromMyself) {
  233. var dz = this.component.dataZoom;
  234. if (dz) {
  235. dz.silence(true);
  236. dz.absoluteZoom(param.zoom);
  237. dz.silence(false);
  238. }
  239. }
  240. this._ondataZoom(param);
  241. break;
  242. case ecConfig.EVENT.DATA_RANGE :
  243. fromMyself && this._ondataRange(param);
  244. break;
  245. case ecConfig.EVENT.MAGIC_TYPE_CHANGED :
  246. if (!fromMyself) {
  247. var tb = this.component.toolbox;
  248. if (tb) {
  249. tb.silence(true);
  250. tb.setMagicType(param.magicType);
  251. tb.silence(false);
  252. }
  253. }
  254. this._onmagicTypeChanged(param);
  255. break;
  256. case ecConfig.EVENT.DATA_VIEW_CHANGED :
  257. fromMyself && this._ondataViewChanged(param);
  258. break;
  259. case ecConfig.EVENT.TOOLTIP_HOVER :
  260. fromMyself && this._tooltipHover(param);
  261. break;
  262. case ecConfig.EVENT.RESTORE :
  263. this._onrestore();
  264. break;
  265. case ecConfig.EVENT.REFRESH :
  266. fromMyself && this._onrefresh(param);
  267. break;
  268. // 鼠标同步
  269. case ecConfig.EVENT.TOOLTIP_IN_GRID :
  270. case ecConfig.EVENT.TOOLTIP_OUT_GRID :
  271. if (!fromMyself) {
  272. // 只处理来自外部的鼠标同步
  273. var grid = this.component.grid;
  274. if (grid) {
  275. this._zr.trigger(
  276. 'mousemove',
  277. {
  278. connectTrigger: true,
  279. zrenderX: grid.getX() + param.x * grid.getWidth(),
  280. zrenderY: grid.getY() + param.y * grid.getHeight()
  281. }
  282. );
  283. }
  284. }
  285. else if (this._connected) {
  286. // 来自自己,并且存在多图联动,空间坐标映射修改参数分发
  287. var grid = this.component.grid;
  288. if (grid) {
  289. param.x = (param.event.zrenderX - grid.getX()) / grid.getWidth();
  290. param.y = (param.event.zrenderY - grid.getY()) / grid.getHeight();
  291. }
  292. }
  293. break;
  294. /*
  295. case ecConfig.EVENT.RESIZE :
  296. case ecConfig.EVENT.DATA_CHANGED :
  297. case ecConfig.EVENT.PIE_SELECTED :
  298. case ecConfig.EVENT.MAP_SELECTED :
  299. break;
  300. */
  301. }
  302. // 多图联动,只做自己的一级事件分发,避免级联事件循环
  303. if (this._connected && fromMyself && this._curEventType === param.type) {
  304. for (var c in this._connected) {
  305. this._connected[c].connectedEventHandler(param);
  306. }
  307. // 分发完毕后复位
  308. this._curEventType = null;
  309. }
  310. if (!fromMyself || (!this._connected && fromMyself)) { // 处理了完联动事件复位
  311. this._curEventType = null;
  312. }
  313. },
  314. /**
  315. * 点击事件,响应zrender事件,包装后分发到Echarts层
  316. */
  317. _onclick: function (param) {
  318. callChartListMethodReverse(this, 'onclick', param);
  319. if (param.target) {
  320. var ecData = this._eventPackage(param.target);
  321. if (ecData && ecData.seriesIndex != null) {
  322. this._messageCenter.dispatch(
  323. ecConfig.EVENT.CLICK,
  324. param.event,
  325. ecData,
  326. this
  327. );
  328. }
  329. }
  330. },
  331. /**
  332. * 双击事件,响应zrender事件,包装后分发到Echarts层
  333. */
  334. _ondblclick: function (param) {
  335. callChartListMethodReverse(this, 'ondblclick', param);
  336. if (param.target) {
  337. var ecData = this._eventPackage(param.target);
  338. if (ecData && ecData.seriesIndex != null) {
  339. this._messageCenter.dispatch(
  340. ecConfig.EVENT.DBLCLICK,
  341. param.event,
  342. ecData,
  343. this
  344. );
  345. }
  346. }
  347. },
  348. /**
  349. * 鼠标移入事件,响应zrender事件,包装后分发到Echarts层
  350. */
  351. _onmouseover: function (param) {
  352. if (param.target) {
  353. var ecData = this._eventPackage(param.target);
  354. if (ecData && ecData.seriesIndex != null) {
  355. this._messageCenter.dispatch(
  356. ecConfig.EVENT.HOVER,
  357. param.event,
  358. ecData,
  359. this
  360. );
  361. }
  362. }
  363. },
  364. /**
  365. * 鼠标移出事件,响应zrender事件,包装后分发到Echarts层
  366. */
  367. _onmouseout: function (param) {
  368. if (param.target) {
  369. var ecData = this._eventPackage(param.target);
  370. if (ecData && ecData.seriesIndex != null) {
  371. this._messageCenter.dispatch(
  372. ecConfig.EVENT.MOUSEOUT,
  373. param.event,
  374. ecData,
  375. this
  376. );
  377. }
  378. }
  379. },
  380. /**
  381. * dragstart回调,可计算特性实现
  382. */
  383. _ondragstart: function (param) {
  384. // 复位用于图表间通信拖拽标识
  385. this._status = {
  386. dragIn: false,
  387. dragOut: false,
  388. needRefresh: false
  389. };
  390. callChartListMethodReverse(this, 'ondragstart', param);
  391. },
  392. /**
  393. * dragging回调,可计算特性实现
  394. */
  395. _ondragenter: function (param) {
  396. callChartListMethodReverse(this, 'ondragenter', param);
  397. },
  398. /**
  399. * dragstart回调,可计算特性实现
  400. */
  401. _ondragover: function (param) {
  402. callChartListMethodReverse(this, 'ondragover', param);
  403. },
  404. /**
  405. * dragstart回调,可计算特性实现
  406. */
  407. _ondragleave: function (param) {
  408. callChartListMethodReverse(this, 'ondragleave', param);
  409. },
  410. /**
  411. * dragstart回调,可计算特性实现
  412. */
  413. _ondrop: function (param) {
  414. callChartListMethodReverse(this, 'ondrop', param, this._status);
  415. this._island.ondrop(param, this._status);
  416. },
  417. /**
  418. * dragdone回调 ,可计算特性实现
  419. */
  420. _ondragend: function (param) {
  421. callChartListMethodReverse(this, 'ondragend', param, this._status);
  422. this._timeline && this._timeline.ondragend(param, this._status);
  423. this._island.ondragend(param, this._status);
  424. // 发生过重计算
  425. if (this._status.needRefresh) {
  426. this._syncBackupData(this._option);
  427. var messageCenter = this._messageCenter;
  428. messageCenter.dispatch(
  429. ecConfig.EVENT.DATA_CHANGED,
  430. param.event,
  431. this._eventPackage(param.target),
  432. this
  433. );
  434. messageCenter.dispatch(ecConfig.EVENT.REFRESH, null, null, this);
  435. }
  436. },
  437. /**
  438. * 图例选择响应
  439. */
  440. _onlegendSelected: function (param) {
  441. // 用于图表间通信
  442. this._status.needRefresh = false;
  443. callChartListMethodReverse(this, 'onlegendSelected', param, this._status);
  444. if (this._status.needRefresh) {
  445. this._messageCenter.dispatch(ecConfig.EVENT.REFRESH, null, null, this);
  446. }
  447. },
  448. /**
  449. * 数据区域缩放响应
  450. */
  451. _ondataZoom: function (param) {
  452. // 用于图表间通信
  453. this._status.needRefresh = false;
  454. callChartListMethodReverse(this, 'ondataZoom', param, this._status);
  455. if (this._status.needRefresh) {
  456. this._messageCenter.dispatch(ecConfig.EVENT.REFRESH, null, null, this);
  457. }
  458. },
  459. /**
  460. * 值域漫游响应
  461. */
  462. _ondataRange: function (param) {
  463. this._clearEffect();
  464. // 用于图表间通信
  465. this._status.needRefresh = false;
  466. callChartListMethodReverse(this, 'ondataRange', param, this._status);
  467. // 没有相互影响,直接刷新即可
  468. if (this._status.needRefresh) {
  469. this._zr.refreshNextFrame();
  470. }
  471. },
  472. /**
  473. * 动态类型切换响应
  474. */
  475. _onmagicTypeChanged: function () {
  476. this._clearEffect();
  477. this._render(this._toolbox.getMagicOption());
  478. },
  479. /**
  480. * 数据视图修改响应
  481. */
  482. _ondataViewChanged: function (param) {
  483. this._syncBackupData(param.option);
  484. this._messageCenter.dispatch(
  485. ecConfig.EVENT.DATA_CHANGED,
  486. null,
  487. param,
  488. this
  489. );
  490. this._messageCenter.dispatch(ecConfig.EVENT.REFRESH, null, null, this);
  491. },
  492. /**
  493. * tooltip与图表间通信
  494. */
  495. _tooltipHover: function (param) {
  496. var tipShape = [];
  497. callChartListMethodReverse(this, 'ontooltipHover', param, tipShape);
  498. },
  499. /**
  500. * 还原
  501. */
  502. _onrestore: function () {
  503. this.restore();
  504. },
  505. /**
  506. * 刷新
  507. */
  508. _onrefresh: function (param) {
  509. this._refreshInside = true;
  510. this.refresh(param);
  511. this._refreshInside = false;
  512. },
  513. /**
  514. * 数据修改后的反向同步dataZoom持有的备份数据
  515. */
  516. _syncBackupData: function (curOption) {
  517. this.component.dataZoom && this.component.dataZoom.syncBackupData(curOption);
  518. },
  519. /**
  520. * 打包Echarts层的事件附件
  521. */
  522. _eventPackage: function (target) {
  523. if (target) {
  524. var ecData = require('./util/ecData');
  525. var seriesIndex = ecData.get(target, 'seriesIndex');
  526. var dataIndex = ecData.get(target, 'dataIndex');
  527. dataIndex = seriesIndex != -1 && this.component.dataZoom
  528. ? this.component.dataZoom.getRealDataIndex(
  529. seriesIndex,
  530. dataIndex
  531. )
  532. : dataIndex;
  533. return {
  534. seriesIndex: seriesIndex,
  535. seriesName: (ecData.get(target, 'series') || {}).name,
  536. dataIndex: dataIndex,
  537. data: ecData.get(target, 'data'),
  538. name: ecData.get(target, 'name'),
  539. value: ecData.get(target, 'value'),
  540. special: ecData.get(target, 'special')
  541. };
  542. }
  543. return;
  544. },
  545. _noDataCheck: function(magicOption) {
  546. var series = magicOption.series;
  547. for (var i = 0, l = series.length; i < l; i++) {
  548. if (series[i].type == ecConfig.CHART_TYPE_MAP
  549. || (series[i].data && series[i].data.length > 0)
  550. || (series[i].markPoint && series[i].markPoint.data && series[i].markPoint.data.length > 0)
  551. || (series[i].markLine && series[i].markLine.data && series[i].markLine.data.length > 0)
  552. || (series[i].nodes && series[i].nodes.length > 0)
  553. || (series[i].links && series[i].links.length > 0)
  554. || (series[i].matrix && series[i].matrix.length > 0)
  555. || (series[i].eventList && series[i].eventList.length > 0)
  556. ) {
  557. return false; // 存在任意数据则为非空数据
  558. }
  559. }
  560. var loadOption = (this._option && this._option.noDataLoadingOption)
  561. || this._themeConfig.noDataLoadingOption
  562. || ecConfig.noDataLoadingOption
  563. || {
  564. text: (this._option && this._option.noDataText)
  565. || this._themeConfig.noDataText
  566. || ecConfig.noDataText,
  567. effect: (this._option && this._option.noDataEffect)
  568. || this._themeConfig.noDataEffect
  569. || ecConfig.noDataEffect
  570. };
  571. // 空数据
  572. this.clear();
  573. this.showLoading(loadOption);
  574. return true;
  575. },
  576. /**
  577. * 图表渲染
  578. */
  579. _render: function (magicOption) {
  580. this._mergeGlobalConifg(magicOption);
  581. if (this._noDataCheck(magicOption)) {
  582. return;
  583. }
  584. var bgColor = magicOption.backgroundColor;
  585. if (bgColor) {
  586. if (!_canvasSupported
  587. && bgColor.indexOf('rgba') != -1
  588. ) {
  589. // IE6~8对RGBA的处理,filter会带来其他颜色的影响
  590. var cList = bgColor.split(',');
  591. this.dom.style.filter = 'alpha(opacity=' +
  592. cList[3].substring(0, cList[3].lastIndexOf(')')) * 100
  593. + ')';
  594. cList.length = 3;
  595. cList[0] = cList[0].replace('a', '');
  596. this.dom.style.backgroundColor = cList.join(',') + ')';
  597. }
  598. else {
  599. this.dom.style.backgroundColor = bgColor;
  600. }
  601. }
  602. this._zr.clearAnimation();
  603. this._chartList = [];
  604. var chartLibrary = require('./chart');
  605. var componentLibrary = require('./component');
  606. if (magicOption.xAxis || magicOption.yAxis) {
  607. magicOption.grid = magicOption.grid || {};
  608. magicOption.dataZoom = magicOption.dataZoom || {};
  609. }
  610. var componentList = [
  611. 'title', 'legend', 'tooltip', 'dataRange', 'roamController',
  612. 'grid', 'dataZoom', 'xAxis', 'yAxis', 'polar'
  613. ];
  614. var ComponentClass;
  615. var componentType;
  616. var component;
  617. for (var i = 0, l = componentList.length; i < l; i++) {
  618. componentType = componentList[i];
  619. component = this.component[componentType];
  620. if (magicOption[componentType]) {
  621. if (component) {
  622. component.refresh && component.refresh(magicOption);
  623. }
  624. else {
  625. ComponentClass = componentLibrary.get(
  626. /^[xy]Axis$/.test(componentType) ? 'axis' : componentType
  627. );
  628. component = new ComponentClass(
  629. this._themeConfig, this._messageCenter, this._zr,
  630. magicOption, this, componentType
  631. );
  632. this.component[componentType] = component;
  633. }
  634. this._chartList.push(component);
  635. }
  636. else if (component) {
  637. component.dispose();
  638. this.component[componentType] = null;
  639. delete this.component[componentType];
  640. }
  641. }
  642. var ChartClass;
  643. var chartType;
  644. var chart;
  645. var chartMap = {}; // 记录已经初始化的图表
  646. for (var i = 0, l = magicOption.series.length; i < l; i++) {
  647. chartType = magicOption.series[i].type;
  648. if (!chartType) {
  649. console.error('series[' + i + '] chart type has not been defined.');
  650. continue;
  651. }
  652. if (!chartMap[chartType]) {
  653. chartMap[chartType] = true;
  654. ChartClass = chartLibrary.get(chartType);
  655. if (ChartClass) {
  656. if (this.chart[chartType]) {
  657. chart = this.chart[chartType];
  658. chart.refresh(magicOption);
  659. }
  660. else {
  661. chart = new ChartClass(
  662. this._themeConfig, this._messageCenter, this._zr,
  663. magicOption, this
  664. );
  665. }
  666. this._chartList.push(chart);
  667. this.chart[chartType] = chart;
  668. }
  669. else {
  670. console.error(chartType + ' has not been required.');
  671. }
  672. }
  673. }
  674. // 已有实例但新option不带这类图表的实例释放
  675. for (chartType in this.chart) {
  676. if (chartType != ecConfig.CHART_TYPE_ISLAND && !chartMap[chartType]) {
  677. this.chart[chartType].dispose();
  678. this.chart[chartType] = null;
  679. delete this.chart[chartType];
  680. }
  681. }
  682. this.component.grid && this.component.grid.refixAxisShape(this.component);
  683. this._island.refresh(magicOption);
  684. this._toolbox.refresh(magicOption);
  685. magicOption.animation && !magicOption.renderAsImage
  686. ? this._zr.refresh()
  687. : this._zr.render();
  688. var imgId = 'IMG' + this.id;
  689. var img = document.getElementById(imgId);
  690. if (magicOption.renderAsImage && _canvasSupported) {
  691. // IE8- 不支持图片渲染形式
  692. if (img) {
  693. // 已经渲染过则更新显示
  694. img.src = this.getDataURL(magicOption.renderAsImage);
  695. }
  696. else {
  697. // 没有渲染过插入img dom
  698. img = this.getImage(magicOption.renderAsImage);
  699. img.id = imgId;
  700. img.style.position = 'absolute';
  701. img.style.left = 0;
  702. img.style.top = 0;
  703. this.dom.firstChild.appendChild(img);
  704. }
  705. this.un();
  706. this._zr.un();
  707. this._disposeChartList();
  708. this._zr.clear();
  709. }
  710. else if (img) {
  711. // 删除可能存在的img
  712. img.parentNode.removeChild(img);
  713. }
  714. img = null;
  715. this._option = magicOption;
  716. },
  717. /**
  718. * 还原
  719. */
  720. restore: function () {
  721. this._clearEffect();
  722. this._option = zrUtil.clone(this._optionRestore);
  723. this._disposeChartList();
  724. this._island.clear();
  725. this._toolbox.reset(this._option, true);
  726. this._render(this._option);
  727. },
  728. /**
  729. * 刷新
  730. * @param {Object=} param,可选参数,用于附带option,内部同步用,外部不建议带入数据修改,无法同步
  731. */
  732. refresh: function (param) {
  733. this._clearEffect();
  734. param = param || {};
  735. var magicOption = param.option;
  736. // 外部调用的refresh且有option带入
  737. if (!this._refreshInside && magicOption) {
  738. // 做简单的差异合并去同步内部持有的数据克隆,不建议带入数据
  739. // 开启数据区域缩放、拖拽重计算、数据视图可编辑模式情况下,当用户产生了数据变化后无法同步
  740. // 如有带入option存在数据变化,请重新setOption
  741. magicOption = this.getOption();
  742. zrUtil.merge(magicOption, param.option, true);
  743. zrUtil.merge(this._optionRestore, param.option, true);
  744. this._toolbox.reset(magicOption);
  745. }
  746. this._island.refresh(magicOption);
  747. this._toolbox.refresh(magicOption);
  748. // 停止动画
  749. this._zr.clearAnimation();
  750. // 先来后到,安顺序刷新各种图表,图表内部refresh优化检查magicOption,无需更新则不更新~
  751. for (var i = 0, l = this._chartList.length; i < l; i++) {
  752. this._chartList[i].refresh && this._chartList[i].refresh(magicOption);
  753. }
  754. this.component.grid && this.component.grid.refixAxisShape(this.component);
  755. this._zr.refresh();
  756. },
  757. /**
  758. * 释放图表实例
  759. */
  760. _disposeChartList: function () {
  761. this._clearEffect();
  762. // 停止动画
  763. this._zr.clearAnimation();
  764. var len = this._chartList.length;
  765. while (len--) {
  766. var chart = this._chartList[len];
  767. if (chart) {
  768. var chartType = chart.type;
  769. this.chart[chartType] && delete this.chart[chartType];
  770. this.component[chartType] && delete this.component[chartType];
  771. chart.dispose && chart.dispose();
  772. }
  773. }
  774. this._chartList = [];
  775. },
  776. /**
  777. * 非图表全局属性merge~~
  778. */
  779. _mergeGlobalConifg: function (magicOption) {
  780. var mergeList = [
  781. // 背景颜色
  782. 'backgroundColor',
  783. // 拖拽重计算相关
  784. 'calculable', 'calculableColor', 'calculableHolderColor',
  785. // 孤岛显示连接符
  786. 'nameConnector', 'valueConnector',
  787. // 动画相关
  788. 'animation', 'animationThreshold',
  789. 'animationDuration', 'animationDurationUpdate',
  790. 'animationEasing', 'addDataAnimation',
  791. // 默认标志图形类型列表
  792. 'symbolList',
  793. // 降低图表内元素拖拽敏感度,单位ms,不建议外部干预
  794. 'DRAG_ENABLE_TIME'
  795. ];
  796. var len = mergeList.length;
  797. while (len--) {
  798. var mergeItem = mergeList[len];
  799. if (magicOption[mergeItem] == null) {
  800. magicOption[mergeItem] = this._themeConfig[mergeItem] != null
  801. ? this._themeConfig[mergeItem]
  802. : ecConfig[mergeItem];
  803. }
  804. }
  805. // 数值系列的颜色列表,不传则采用内置颜色,可配数组,借用zrender实例注入,会有冲突风险,先这样
  806. var themeColor = magicOption.color;
  807. if (!(themeColor && themeColor.length)) {
  808. themeColor = this._themeConfig.color || ecConfig.color;
  809. }
  810. this._zr.getColor = function (idx) {
  811. var zrColor = require('zrender/tool/color');
  812. return zrColor.getColor(idx, themeColor);
  813. };
  814. if (!_canvasSupported) {
  815. // 不支持Canvas的强制关闭动画
  816. magicOption.animation = false;
  817. magicOption.addDataAnimation = false;
  818. }
  819. },
  820. /**
  821. * 万能接口,配置图表实例任何可配置选项,多次调用时option选项做merge处理
  822. * @param {Object} option
  823. * @param {boolean=} notMerge 多次调用时option选项是默认是合并(merge)的,
  824. * 如果不需求,可以通过notMerger参数为true阻止与上次option的合并
  825. */
  826. setOption: function (option, notMerge) {
  827. if (!option.timeline) {
  828. return this._setOption(option, notMerge);
  829. }
  830. else {
  831. return this._setTimelineOption(option);
  832. }
  833. },
  834. /**
  835. * 万能接口,配置图表实例任何可配置选项,多次调用时option选项做merge处理
  836. * @param {Object} option
  837. * @param {boolean=} notMerge 多次调用时option选项是默认是合并(merge)的,
  838. * 如果不需求,可以通过notMerger参数为true阻止与上次option的合并
  839. * @param {boolean=} 默认false。keepTimeLine 表示从timeline组件调用而来,
  840. * 表示当前行为是timeline的数据切换,保持timeline,
  841. * 反之销毁timeline。 详见Issue #1601
  842. */
  843. _setOption: function (option, notMerge, keepTimeLine) {
  844. if (!notMerge && this._option) {
  845. this._option = zrUtil.merge(
  846. this.getOption(),
  847. zrUtil.clone(option),
  848. true
  849. );
  850. }
  851. else {
  852. this._option = zrUtil.clone(option);
  853. !keepTimeLine && this._timeline && this._timeline.dispose();
  854. }
  855. this._optionRestore = zrUtil.clone(this._option);
  856. if (!this._option.series || this._option.series.length === 0) {
  857. this._zr.clear();
  858. return;
  859. }
  860. if (this.component.dataZoom // 存在dataZoom控件
  861. && (this._option.dataZoom // 并且新option也存在
  862. || (this._option.toolbox
  863. && this._option.toolbox.feature
  864. && this._option.toolbox.feature.dataZoom
  865. && this._option.toolbox.feature.dataZoom.show
  866. )
  867. )
  868. ) {
  869. // dataZoom同步数据
  870. this.component.dataZoom.syncOption(this._option);
  871. }
  872. this._toolbox.reset(this._option);
  873. this._render(this._option);
  874. return this;
  875. },
  876. /**
  877. * 返回内部持有的当前显示option克隆
  878. */
  879. getOption: function () {
  880. var magicOption = zrUtil.clone(this._option);
  881. var self = this;
  882. function restoreOption(prop) {
  883. var restoreSource = self._optionRestore[prop];
  884. if (restoreSource) {
  885. if (restoreSource instanceof Array) {
  886. var len = restoreSource.length;
  887. while (len--) {
  888. magicOption[prop][len].data = zrUtil.clone(
  889. restoreSource[len].data
  890. );
  891. }
  892. }
  893. else {
  894. magicOption[prop].data = zrUtil.clone(restoreSource.data);
  895. }
  896. }
  897. }
  898. // 横轴数据还原
  899. restoreOption('xAxis');
  900. // 纵轴数据还原
  901. restoreOption('yAxis');
  902. // 系列数据还原
  903. restoreOption('series');
  904. return magicOption;
  905. },
  906. /**
  907. * 数据设置快捷接口
  908. * @param {Array} series
  909. * @param {boolean=} notMerge 多次调用时option选项是默认是合并(merge)的,
  910. * 如果不需求,可以通过notMerger参数为true阻止与上次option的合并。
  911. */
  912. setSeries: function (series, notMerge) {
  913. if (!notMerge) {
  914. this.setOption({series: series});
  915. }
  916. else {
  917. this._option.series = series;
  918. this.setOption(this._option, notMerge);
  919. }
  920. return this;
  921. },
  922. /**
  923. * 返回内部持有的当前显示series克隆
  924. */
  925. getSeries: function () {
  926. return this.getOption().series;
  927. },
  928. /**
  929. * timelineOption接口,配置图表实例任何可配置选项
  930. * @param {Object} option
  931. */
  932. _setTimelineOption: function(option) {
  933. this._timeline && this._timeline.dispose();
  934. var Timeline = require('./component/timeline');
  935. var timeline = new Timeline(
  936. this._themeConfig, this._messageCenter, this._zr, option, this
  937. );
  938. this._timeline = timeline;
  939. this.component.timeline = this._timeline;
  940. return this;
  941. },
  942. /**
  943. * 动态数据添加
  944. * 形参为单组数据参数,多组时为数据,内容同[seriesIdx, data, isShift, additionData]
  945. * @param {number} seriesIdx 系列索引
  946. * @param {number | Object} data 增加数据
  947. * @param {boolean=} isHead 是否队头加入,默认,不指定或false时为队尾插入
  948. * @param {boolean=} dataGrow 是否增长数据队列长度,默认,不指定或false时移出目标数组对位数据
  949. * @param {string=} additionData 是否增加类目轴(饼图为图例)数据,附加操作同isHead和dataGrow
  950. */
  951. addData: function (seriesIdx, data, isHead, dataGrow, additionData) {
  952. var params = seriesIdx instanceof Array
  953. ? seriesIdx
  954. : [[seriesIdx, data, isHead, dataGrow, additionData]];
  955. //this._optionRestore 和 magicOption 都要同步
  956. var magicOption = this.getOption();
  957. var optionRestore = this._optionRestore;
  958. var self = this;
  959. for (var i = 0, l = params.length; i < l; i++) {
  960. seriesIdx = params[i][0];
  961. data = params[i][1];
  962. isHead = params[i][2];
  963. dataGrow = params[i][3];
  964. additionData = params[i][4];
  965. var seriesItem = optionRestore.series[seriesIdx];
  966. var inMethod = isHead ? 'unshift' : 'push';
  967. var outMethod = isHead ? 'pop' : 'shift';
  968. if (seriesItem) {
  969. var seriesItemData = seriesItem.data;
  970. var mSeriesItemData = magicOption.series[seriesIdx].data;
  971. seriesItemData[inMethod](data);
  972. mSeriesItemData[inMethod](data);
  973. if (!dataGrow) {
  974. seriesItemData[outMethod]();
  975. data = mSeriesItemData[outMethod]();
  976. }
  977. if (additionData != null) {
  978. var legend;
  979. var legendData;
  980. if (seriesItem.type === ecConfig.CHART_TYPE_PIE
  981. && (legend = optionRestore.legend)
  982. && (legendData = legend.data)
  983. ) {
  984. var mLegendData = magicOption.legend.data;
  985. legendData[inMethod](additionData);
  986. mLegendData[inMethod](additionData);
  987. if (!dataGrow) {
  988. var legendDataIdx = zrUtil.indexOf(legendData, data.name);
  989. legendDataIdx != -1 && legendData.splice(legendDataIdx, 1);
  990. legendDataIdx = zrUtil.indexOf(mLegendData, data.name);
  991. legendDataIdx != -1 && mLegendData.splice(legendDataIdx, 1);
  992. }
  993. }
  994. else if (optionRestore.xAxis != null && optionRestore.yAxis != null) {
  995. // x轴类目
  996. var axisData;
  997. var mAxisData;
  998. var axisIdx = seriesItem.xAxisIndex || 0;
  999. if (optionRestore.xAxis[axisIdx].type == null
  1000. || optionRestore.xAxis[axisIdx].type === 'category'
  1001. ) {
  1002. axisData = optionRestore.xAxis[axisIdx].data;
  1003. mAxisData = magicOption.xAxis[axisIdx].data;
  1004. axisData[inMethod](additionData);
  1005. mAxisData[inMethod](additionData);
  1006. if (!dataGrow) {
  1007. axisData[outMethod]();
  1008. mAxisData[outMethod]();
  1009. }
  1010. }
  1011. // y轴类目
  1012. axisIdx = seriesItem.yAxisIndex || 0;
  1013. if (optionRestore.yAxis[axisIdx].type === 'category') {
  1014. axisData = optionRestore.yAxis[axisIdx].data;
  1015. mAxisData = magicOption.yAxis[axisIdx].data;
  1016. axisData[inMethod](additionData);
  1017. mAxisData[inMethod](additionData);
  1018. if (!dataGrow) {
  1019. axisData[outMethod]();
  1020. mAxisData[outMethod]();
  1021. }
  1022. }
  1023. }
  1024. }
  1025. // 同步图表内状态,动画需要
  1026. this._option.series[seriesIdx].data = magicOption.series[seriesIdx].data;
  1027. }
  1028. }
  1029. this._zr.clearAnimation();
  1030. var chartList = this._chartList;
  1031. var chartAnimationCount = 0;
  1032. var chartAnimationDone = function () {
  1033. chartAnimationCount--;
  1034. if (chartAnimationCount === 0) {
  1035. animationDone();
  1036. }
  1037. };
  1038. for (var i = 0, l = chartList.length; i < l; i++) {
  1039. if (magicOption.addDataAnimation && chartList[i].addDataAnimation) {
  1040. chartAnimationCount++;
  1041. chartList[i].addDataAnimation(params, chartAnimationDone);
  1042. }
  1043. }
  1044. // dataZoom同步数据
  1045. this.component.dataZoom && this.component.dataZoom.syncOption(magicOption);
  1046. this._option = magicOption;
  1047. function animationDone() {
  1048. if (!self._zr) {
  1049. return; // 已经被释放
  1050. }
  1051. self._zr.clearAnimation();
  1052. for (var i = 0, l = chartList.length; i < l; i++) {
  1053. // 有addData动画就去掉过渡动画
  1054. chartList[i].motionlessOnce =
  1055. magicOption.addDataAnimation && chartList[i].addDataAnimation;
  1056. }
  1057. self._messageCenter.dispatch(
  1058. ecConfig.EVENT.REFRESH,
  1059. null,
  1060. {option: magicOption},
  1061. self
  1062. );
  1063. }
  1064. if (!magicOption.addDataAnimation) {
  1065. setTimeout(animationDone, 0);
  1066. }
  1067. return this;
  1068. },
  1069. /**
  1070. * 动态[标注 | 标线]添加
  1071. * @param {number} seriesIdx 系列索引
  1072. * @param {Object} markData [标注 | 标线]对象,支持多个
  1073. */
  1074. addMarkPoint: function (seriesIdx, markData) {
  1075. return this._addMark(seriesIdx, markData, 'markPoint');
  1076. },
  1077. addMarkLine: function (seriesIdx, markData) {
  1078. return this._addMark(seriesIdx, markData, 'markLine');
  1079. },
  1080. _addMark: function (seriesIdx, markData, markType) {
  1081. var series = this._option.series;
  1082. var seriesItem;
  1083. if (series && (seriesItem = series[seriesIdx])) {
  1084. var seriesR = this._optionRestore.series;
  1085. var seriesRItem = seriesR[seriesIdx];
  1086. var markOpt = seriesItem[markType];
  1087. var markOptR = seriesRItem[markType];
  1088. markOpt = seriesItem[markType] = markOpt || {data: []};
  1089. markOptR = seriesRItem[markType] = markOptR || {data: []};
  1090. for (var key in markData) {
  1091. if (key === 'data') {
  1092. // 数据concat
  1093. markOpt.data = markOpt.data.concat(markData.data);
  1094. markOptR.data = markOptR.data.concat(markData.data);
  1095. }
  1096. else if (typeof markData[key] != 'object' || markOpt[key] == null) {
  1097. // 简单类型或新值直接赋值
  1098. markOpt[key] = markOptR[key] = markData[key];
  1099. }
  1100. else {
  1101. // 非数据的复杂对象merge
  1102. zrUtil.merge(markOpt[key], markData[key], true);
  1103. zrUtil.merge(markOptR[key], markData[key], true);
  1104. }
  1105. }
  1106. var chart = this.chart[seriesItem.type];
  1107. chart && chart.addMark(seriesIdx, markData, markType);
  1108. }
  1109. return this;
  1110. },
  1111. /**
  1112. * 动态[标注 | 标线]删除
  1113. * @param {number} seriesIdx 系列索引
  1114. * @param {string} markName [标注 | 标线]名称
  1115. */
  1116. delMarkPoint: function (seriesIdx, markName) {
  1117. return this._delMark(seriesIdx, markName, 'markPoint');
  1118. },
  1119. delMarkLine: function (seriesIdx, markName) {
  1120. return this._delMark(seriesIdx, markName, 'markLine');
  1121. },
  1122. _delMark: function (seriesIdx, markName, markType) {
  1123. var series = this._option.series;
  1124. var seriesItem;
  1125. var mark;
  1126. var dataArray;
  1127. if (!(
  1128. series
  1129. && (seriesItem = series[seriesIdx])
  1130. && (mark = seriesItem[markType])
  1131. && (dataArray = mark.data)
  1132. )
  1133. ) {
  1134. return this;
  1135. }
  1136. markName = markName.split(' > ');
  1137. var targetIndex = -1;
  1138. for (var i = 0, l = dataArray.length; i < l; i++) {
  1139. var dataItem = dataArray[i];
  1140. if (dataItem instanceof Array) {
  1141. if (dataItem[0].name === markName[0]
  1142. && dataItem[1].name === markName[1]
  1143. ) {
  1144. targetIndex = i;
  1145. break;
  1146. }
  1147. }
  1148. else if (dataItem.name === markName[0]) {
  1149. targetIndex = i;
  1150. break;
  1151. }
  1152. }
  1153. if (targetIndex > -1) {
  1154. dataArray.splice(targetIndex, 1);
  1155. this._optionRestore.series[seriesIdx][markType].data.splice(targetIndex, 1);
  1156. var chart = this.chart[seriesItem.type];
  1157. chart && chart.delMark(seriesIdx, markName.join(' > '), markType);
  1158. }
  1159. return this;
  1160. },
  1161. /**
  1162. * 获取当前dom
  1163. */
  1164. getDom: function () {
  1165. return this.dom;
  1166. },
  1167. /**
  1168. * 获取当前zrender实例,可用于添加额为的shape和深度控制
  1169. */
  1170. getZrender: function () {
  1171. return this._zr;
  1172. },
  1173. /**
  1174. * 获取Base64图片dataURL
  1175. * @param {string} imgType 图片类型,支持png|jpeg,默认为png
  1176. * @return imgDataURL
  1177. */
  1178. getDataURL: function (imgType) {
  1179. if (!_canvasSupported) {
  1180. return '';
  1181. }
  1182. if (this._chartList.length === 0) {
  1183. // 渲染为图片
  1184. var imgId = 'IMG' + this.id;
  1185. var img = document.getElementById(imgId);
  1186. if (img) {
  1187. return img.src;
  1188. }
  1189. }
  1190. // 清除可能存在的tooltip元素
  1191. var tooltip = this.component.tooltip;
  1192. tooltip && tooltip.hideTip();
  1193. switch (imgType) {
  1194. case 'jpeg':
  1195. break;
  1196. default:
  1197. imgType = 'png';
  1198. }
  1199. var bgColor = this._option.backgroundColor;
  1200. if (bgColor && bgColor.replace(' ','') === 'rgba(0,0,0,0)') {
  1201. bgColor = '#fff';
  1202. }
  1203. return this._zr.toDataURL('image/' + imgType, bgColor);
  1204. },
  1205. /**
  1206. * 获取img
  1207. * @param {string} imgType 图片类型,支持png|jpeg,默认为png
  1208. * @return img dom
  1209. */
  1210. getImage: function (imgType) {
  1211. var title = this._optionRestore.title;
  1212. var imgDom = document.createElement('img');
  1213. imgDom.src = this.getDataURL(imgType);
  1214. imgDom.title = (title && title.text) || 'ECharts';
  1215. return imgDom;
  1216. },
  1217. /**
  1218. * 获取多图联动的Base64图片dataURL
  1219. * @param {string} imgType 图片类型,支持png|jpeg,默认为png
  1220. * @return imgDataURL
  1221. */
  1222. getConnectedDataURL: function (imgType) {
  1223. if (!this.isConnected()) {
  1224. return this.getDataURL(imgType);
  1225. }
  1226. var tempDom = this.dom;
  1227. var imgList = {
  1228. 'self': {
  1229. img: this.getDataURL(imgType),
  1230. left: tempDom.offsetLeft,
  1231. top: tempDom.offsetTop,
  1232. right: tempDom.offsetLeft + tempDom.offsetWidth,
  1233. bottom: tempDom.offsetTop + tempDom.offsetHeight
  1234. }
  1235. };
  1236. var minLeft = imgList.self.left;
  1237. var minTop = imgList.self.top;
  1238. var maxRight = imgList.self.right;
  1239. var maxBottom = imgList.self.bottom;
  1240. for (var c in this._connected) {
  1241. tempDom = this._connected[c].getDom();
  1242. imgList[c] = {
  1243. img: this._connected[c].getDataURL(imgType),
  1244. left: tempDom.offsetLeft,
  1245. top: tempDom.offsetTop,
  1246. right: tempDom.offsetLeft + tempDom.offsetWidth,
  1247. bottom: tempDom.offsetTop + tempDom.offsetHeight
  1248. };
  1249. minLeft = Math.min(minLeft, imgList[c].left);
  1250. minTop = Math.min(minTop, imgList[c].top);
  1251. maxRight = Math.max(maxRight, imgList[c].right);
  1252. maxBottom = Math.max(maxBottom, imgList[c].bottom);
  1253. }
  1254. var zrDom = document.createElement('div');
  1255. zrDom.style.position = 'absolute';
  1256. zrDom.style.left = '-4000px';
  1257. zrDom.style.width = (maxRight - minLeft) + 'px';
  1258. zrDom.style.height = (maxBottom - minTop) + 'px';
  1259. document.body.appendChild(zrDom);
  1260. var zrImg = require('zrender').init(zrDom);
  1261. var ImageShape = require('zrender/shape/Image');
  1262. for (var c in imgList) {
  1263. zrImg.addShape(new ImageShape({
  1264. style: {
  1265. x: imgList[c].left - minLeft,
  1266. y: imgList[c].top - minTop,
  1267. image: imgList[c].img
  1268. }
  1269. }));
  1270. }
  1271. zrImg.render();
  1272. var bgColor = this._option.backgroundColor;
  1273. if (bgColor && bgColor.replace(/ /g, '') === 'rgba(0,0,0,0)') {
  1274. bgColor = '#fff';
  1275. }
  1276. var image = zrImg.toDataURL('image/png', bgColor);
  1277. setTimeout(function () {
  1278. zrImg.dispose();
  1279. zrDom.parentNode.removeChild(zrDom);
  1280. zrDom = null;
  1281. }, 100);
  1282. return image;
  1283. },
  1284. /**
  1285. * 获取多图联动的img
  1286. * @param {string} imgType 图片类型,支持png|jpeg,默认为png
  1287. * @return img dom
  1288. */
  1289. getConnectedImage: function (imgType) {
  1290. var title = this._optionRestore.title;
  1291. var imgDom = document.createElement('img');
  1292. imgDom.src = this.getConnectedDataURL(imgType);
  1293. imgDom.title = (title && title.text) || 'ECharts';
  1294. return imgDom;
  1295. },
  1296. /**
  1297. * 外部接口绑定事件
  1298. * @param {Object} eventName 事件名称
  1299. * @param {Object} eventListener 事件响应函数
  1300. */
  1301. on: function (eventName, eventListener) {
  1302. this._messageCenterOutSide.bind(eventName, eventListener, this);
  1303. return this;
  1304. },
  1305. /**
  1306. * 外部接口解除事件绑定
  1307. * @param {Object} eventName 事件名称
  1308. * @param {Object} eventListener 事件响应函数
  1309. */
  1310. un: function (eventName, eventListener) {
  1311. this._messageCenterOutSide.unbind(eventName, eventListener);
  1312. return this;
  1313. },
  1314. /**
  1315. * 多图联动
  1316. * @param connectTarget{ECharts | Array <ECharts>} connectTarget 联动目标
  1317. */
  1318. connect: function (connectTarget) {
  1319. if (!connectTarget) {
  1320. return this;
  1321. }
  1322. if (!this._connected) {
  1323. this._connected = {};
  1324. }
  1325. if (connectTarget instanceof Array) {
  1326. for (var i = 0, l = connectTarget.length; i < l; i++) {
  1327. this._connected[connectTarget[i].id] = connectTarget[i];
  1328. }
  1329. }
  1330. else {
  1331. this._connected[connectTarget.id] = connectTarget;
  1332. }
  1333. return this;
  1334. },
  1335. /**
  1336. * 解除多图联动
  1337. * @param connectTarget{ECharts | Array <ECharts>} connectTarget 解除联动目标
  1338. */
  1339. disConnect: function (connectTarget) {
  1340. if (!connectTarget || !this._connected) {
  1341. return this;
  1342. }
  1343. if (connectTarget instanceof Array) {
  1344. for (var i = 0, l = connectTarget.length; i < l; i++) {
  1345. delete this._connected[connectTarget[i].id];
  1346. }
  1347. }
  1348. else {
  1349. delete this._connected[connectTarget.id];
  1350. }
  1351. for (var k in this._connected) {
  1352. return k, this; // 非空
  1353. }
  1354. // 空,转为标志位
  1355. this._connected = false;
  1356. return this;
  1357. },
  1358. /**
  1359. * 联动事件响应
  1360. */
  1361. connectedEventHandler: function (param) {
  1362. if (param.__echartsId != this.id) {
  1363. // 来自其他联动图表的事件
  1364. this._onevent(param);
  1365. }
  1366. },
  1367. /**
  1368. * 是否存在多图联动
  1369. */
  1370. isConnected: function () {
  1371. return !!this._connected;
  1372. },
  1373. /**
  1374. * 显示loading过渡
  1375. * @param {Object} loadingOption
  1376. */
  1377. showLoading: function (loadingOption) {
  1378. var effectList = {
  1379. bar: require('zrender/loadingEffect/Bar'),
  1380. bubble: require('zrender/loadingEffect/Bubble'),
  1381. dynamicLine: require('zrender/loadingEffect/DynamicLine'),
  1382. ring: require('zrender/loadingEffect/Ring'),
  1383. spin: require('zrender/loadingEffect/Spin'),
  1384. whirling: require('zrender/loadingEffect/Whirling')
  1385. };
  1386. this._toolbox.hideDataView();
  1387. loadingOption = loadingOption || {};
  1388. var textStyle = loadingOption.textStyle || {};
  1389. loadingOption.textStyle = textStyle;
  1390. var finalTextStyle = zrUtil.merge(
  1391. zrUtil.merge(
  1392. zrUtil.clone(textStyle),
  1393. this._themeConfig.textStyle
  1394. ),
  1395. ecConfig.textStyle
  1396. );
  1397. textStyle.textFont = finalTextStyle.fontStyle + ' '
  1398. + finalTextStyle.fontWeight + ' '
  1399. + finalTextStyle.fontSize + 'px '
  1400. + finalTextStyle.fontFamily;
  1401. textStyle.text = loadingOption.text
  1402. || (this._option && this._option.loadingText)
  1403. || this._themeConfig.loadingText
  1404. || ecConfig.loadingText;
  1405. if (loadingOption.x != null) {
  1406. textStyle.x = loadingOption.x;
  1407. }
  1408. if (loadingOption.y != null) {
  1409. textStyle.y = loadingOption.y;
  1410. }
  1411. loadingOption.effectOption = loadingOption.effectOption || {};
  1412. loadingOption.effectOption.textStyle = textStyle;
  1413. var Effect = loadingOption.effect;
  1414. if (typeof Effect === 'string' || Effect == null) {
  1415. Effect = effectList[
  1416. loadingOption.effect
  1417. || (this._option && this._option.loadingEffect)
  1418. || this._themeConfig.loadingEffect
  1419. || ecConfig.loadingEffect
  1420. ]
  1421. || effectList.spin;
  1422. }
  1423. this._zr.showLoading(new Effect(loadingOption.effectOption));
  1424. return this;
  1425. },
  1426. /**
  1427. * 隐藏loading过渡
  1428. */
  1429. hideLoading: function () {
  1430. this._zr.hideLoading();
  1431. return this;
  1432. },
  1433. /**
  1434. * 主题设置
  1435. */
  1436. setTheme: function (theme) {
  1437. if (theme) {
  1438. if (typeof theme === 'string') {
  1439. // 默认主题
  1440. switch (theme) {
  1441. case 'macarons':
  1442. theme = require('./theme/macarons');
  1443. break;
  1444. case 'infographic':
  1445. theme = require('./theme/infographic');
  1446. break;
  1447. default:
  1448. theme = {}; // require('./theme/default');
  1449. }
  1450. }
  1451. else {
  1452. theme = theme || {};
  1453. }
  1454. // // 复位默认配置
  1455. // // this._themeConfig会被别的对象引用持有
  1456. // // 所以不能改成this._themeConfig = {};
  1457. // for (var key in this._themeConfig) {
  1458. // delete this._themeConfig[key];
  1459. // }
  1460. // for (var key in ecConfig) {
  1461. // this._themeConfig[key] = zrUtil.clone(ecConfig[key]);
  1462. // }
  1463. // // 颜色数组随theme,不merge
  1464. // theme.color && (this._themeConfig.color = []);
  1465. // // 默认标志图形类型列表,不merge
  1466. // theme.symbolList && (this._themeConfig.symbolList = []);
  1467. // // 应用新主题
  1468. // zrUtil.merge(this._themeConfig, zrUtil.clone(theme), true);
  1469. this._themeConfig = theme;
  1470. }
  1471. if (!_canvasSupported) { // IE8-
  1472. var textStyle = this._themeConfig.textStyle;
  1473. textStyle && textStyle.fontFamily && textStyle.fontFamily2
  1474. && (textStyle.fontFamily = textStyle.fontFamily2);
  1475. textStyle = ecConfig.textStyle;
  1476. textStyle.fontFamily = textStyle.fontFamily2;
  1477. }
  1478. this._timeline && this._timeline.setTheme(true);
  1479. this._optionRestore && this.restore();
  1480. },
  1481. /**
  1482. * 视图区域大小变化更新,不默认绑定,供使用方按需调用
  1483. */
  1484. resize: function () {
  1485. var self = this;
  1486. return function(){
  1487. self._clearEffect();
  1488. self._zr.resize();
  1489. if (self._option && self._option.renderAsImage && _canvasSupported) {
  1490. // 渲染为图片重走render模式
  1491. self._render(self._option);
  1492. return self;
  1493. }
  1494. // 停止动画
  1495. self._zr.clearAnimation();
  1496. self._island.resize();
  1497. self._toolbox.resize();
  1498. self._timeline && self._timeline.resize();
  1499. // 先来后到,不能仅刷新自己,也不能在上一个循环中刷新,如坐标系数据改变会影响其他图表的大小
  1500. // 所以安顺序刷新各种图表,图表内部refresh优化无需更新则不更新~
  1501. for (var i = 0, l = self._chartList.length; i < l; i++) {
  1502. self._chartList[i].resize && self._chartList[i].resize();
  1503. }
  1504. self.component.grid && self.component.grid.refixAxisShape(self.component);
  1505. self._zr.refresh();
  1506. self._messageCenter.dispatch(ecConfig.EVENT.RESIZE, null, null, self);
  1507. return self;
  1508. };
  1509. },
  1510. _clearEffect: function() {
  1511. this._zr.modLayer(ecConfig.EFFECT_ZLEVEL, { motionBlur: false });
  1512. this._zr.painter.clearLayer(ecConfig.EFFECT_ZLEVEL);
  1513. },
  1514. /**
  1515. * 清除已渲染内容 ,clear后echarts实例可用
  1516. */
  1517. clear: function () {
  1518. this._disposeChartList();
  1519. this._zr.clear();
  1520. this._option = {};
  1521. this._optionRestore = {};
  1522. this.dom.style.backgroundColor = null;
  1523. return this;
  1524. },
  1525. /**
  1526. * 释放,dispose后echarts实例不可用
  1527. */
  1528. dispose: function () {
  1529. var key = this.dom.getAttribute(DOM_ATTRIBUTE_KEY);
  1530. key && delete _instances[key];
  1531. this._island.dispose();
  1532. this._toolbox.dispose();
  1533. this._timeline && this._timeline.dispose();
  1534. this._messageCenter.unbind();
  1535. this.clear();
  1536. this._zr.dispose();
  1537. this._zr = null;
  1538. }
  1539. };
  1540. return self;
  1541. });