echarts.js 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879
  1. // Enable DEV mode when using source code without build. which has no __DEV__ variable
  2. // In build process 'typeof __DEV__' will be replace with 'boolean'
  3. // So this code will be removed or disabled anyway after built.
  4. if (typeof __DEV__ === 'undefined') {
  5. // In browser
  6. if (typeof window !== 'undefined') {
  7. window.__DEV__ = true;
  8. }
  9. // In node
  10. else if (typeof global !== 'undefined') {
  11. global.__DEV__ = true;
  12. }
  13. }
  14. /*!
  15. * ECharts, a javascript interactive chart library.
  16. *
  17. * Copyright (c) 2015, Baidu Inc.
  18. * All rights reserved.
  19. *
  20. * LICENSE
  21. * https://github.com/ecomfe/echarts/blob/master/LICENSE.txt
  22. */
  23. /**
  24. * @module echarts
  25. */
  26. define(function (require) {
  27. var env = require('zrender/core/env');
  28. var GlobalModel = require('./model/Global');
  29. var ExtensionAPI = require('./ExtensionAPI');
  30. var CoordinateSystemManager = require('./CoordinateSystem');
  31. var OptionManager = require('./model/OptionManager');
  32. var ComponentModel = require('./model/Component');
  33. var SeriesModel = require('./model/Series');
  34. var ComponentView = require('./view/Component');
  35. var ChartView = require('./view/Chart');
  36. var graphic = require('./util/graphic');
  37. var modelUtil = require('./util/model');
  38. var throttle = require('./util/throttle');
  39. var zrender = require('zrender');
  40. var zrUtil = require('zrender/core/util');
  41. var colorTool = require('zrender/tool/color');
  42. var Eventful = require('zrender/mixin/Eventful');
  43. var timsort = require('zrender/core/timsort');
  44. var each = zrUtil.each;
  45. var parseClassType = ComponentModel.parseClassType;
  46. var PRIORITY_PROCESSOR_FILTER = 1000;
  47. var PRIORITY_PROCESSOR_STATISTIC = 5000;
  48. var PRIORITY_VISUAL_LAYOUT = 1000;
  49. var PRIORITY_VISUAL_GLOBAL = 2000;
  50. var PRIORITY_VISUAL_CHART = 3000;
  51. var PRIORITY_VISUAL_COMPONENT = 4000;
  52. // FIXME
  53. // necessary?
  54. var PRIORITY_VISUAL_BRUSH = 5000;
  55. // Main process have three entries: `setOption`, `dispatchAction` and `resize`,
  56. // where they must not be invoked nestedly, except the only case: invoke
  57. // dispatchAction with updateMethod "none" in main process.
  58. // This flag is used to carry out this rule.
  59. // All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]).
  60. var IN_MAIN_PROCESS = '__flagInMainProcess';
  61. var HAS_GRADIENT_OR_PATTERN_BG = '__hasGradientOrPatternBg';
  62. var OPTION_UPDATED = '__optionUpdated';
  63. var ACTION_REG = /^[a-zA-Z0-9_]+$/;
  64. function createRegisterEventWithLowercaseName(method) {
  65. return function (eventName, handler, context) {
  66. // Event name is all lowercase
  67. eventName = eventName && eventName.toLowerCase();
  68. Eventful.prototype[method].call(this, eventName, handler, context);
  69. };
  70. }
  71. /**
  72. * @module echarts~MessageCenter
  73. */
  74. function MessageCenter() {
  75. Eventful.call(this);
  76. }
  77. MessageCenter.prototype.on = createRegisterEventWithLowercaseName('on');
  78. MessageCenter.prototype.off = createRegisterEventWithLowercaseName('off');
  79. MessageCenter.prototype.one = createRegisterEventWithLowercaseName('one');
  80. zrUtil.mixin(MessageCenter, Eventful);
  81. /**
  82. * @module echarts~ECharts
  83. */
  84. function ECharts (dom, theme, opts) {
  85. opts = opts || {};
  86. // Get theme by name
  87. if (typeof theme === 'string') {
  88. theme = themeStorage[theme];
  89. }
  90. /**
  91. * @type {string}
  92. */
  93. this.id;
  94. /**
  95. * Group id
  96. * @type {string}
  97. */
  98. this.group;
  99. /**
  100. * @type {HTMLDomElement}
  101. * @private
  102. */
  103. this._dom = dom;
  104. /**
  105. * @type {module:zrender/ZRender}
  106. * @private
  107. */
  108. var zr = this._zr = zrender.init(dom, {
  109. renderer: opts.renderer || 'canvas',
  110. devicePixelRatio: opts.devicePixelRatio,
  111. width: opts.width,
  112. height: opts.height
  113. });
  114. /**
  115. * Expect 60 pfs.
  116. * @type {Function}
  117. * @private
  118. */
  119. this._throttledZrFlush = throttle.throttle(zrUtil.bind(zr.flush, zr), 17);
  120. /**
  121. * @type {Object}
  122. * @private
  123. */
  124. this._theme = zrUtil.clone(theme);
  125. /**
  126. * @type {Array.<module:echarts/view/Chart>}
  127. * @private
  128. */
  129. this._chartsViews = [];
  130. /**
  131. * @type {Object.<string, module:echarts/view/Chart>}
  132. * @private
  133. */
  134. this._chartsMap = {};
  135. /**
  136. * @type {Array.<module:echarts/view/Component>}
  137. * @private
  138. */
  139. this._componentsViews = [];
  140. /**
  141. * @type {Object.<string, module:echarts/view/Component>}
  142. * @private
  143. */
  144. this._componentsMap = {};
  145. /**
  146. * @type {module:echarts/ExtensionAPI}
  147. * @private
  148. */
  149. this._api = new ExtensionAPI(this);
  150. /**
  151. * @type {module:echarts/CoordinateSystem}
  152. * @private
  153. */
  154. this._coordSysMgr = new CoordinateSystemManager();
  155. Eventful.call(this);
  156. /**
  157. * @type {module:echarts~MessageCenter}
  158. * @private
  159. */
  160. this._messageCenter = new MessageCenter();
  161. // Init mouse events
  162. this._initEvents();
  163. // In case some people write `window.onresize = chart.resize`
  164. this.resize = zrUtil.bind(this.resize, this);
  165. // Can't dispatch action during rendering procedure
  166. this._pendingActions = [];
  167. // Sort on demand
  168. function prioritySortFunc(a, b) {
  169. return a.prio - b.prio;
  170. }
  171. timsort(visualFuncs, prioritySortFunc);
  172. timsort(dataProcessorFuncs, prioritySortFunc);
  173. zr.animation.on('frame', this._onframe, this);
  174. }
  175. var echartsProto = ECharts.prototype;
  176. echartsProto._onframe = function () {
  177. // Lazy update
  178. if (this[OPTION_UPDATED]) {
  179. var silent = this[OPTION_UPDATED].silent;
  180. this[IN_MAIN_PROCESS] = true;
  181. updateMethods.prepareAndUpdate.call(this);
  182. this[IN_MAIN_PROCESS] = false;
  183. this[OPTION_UPDATED] = false;
  184. flushPendingActions.call(this, silent);
  185. triggerUpdatedEvent.call(this, silent);
  186. }
  187. };
  188. /**
  189. * @return {HTMLDomElement}
  190. */
  191. echartsProto.getDom = function () {
  192. return this._dom;
  193. };
  194. /**
  195. * @return {module:zrender~ZRender}
  196. */
  197. echartsProto.getZr = function () {
  198. return this._zr;
  199. };
  200. /**
  201. * Usage:
  202. * chart.setOption(option, notMerge, lazyUpdate);
  203. * chart.setOption(option, {
  204. * notMerge: ...,
  205. * lazyUpdate: ...,
  206. * silent: ...
  207. * });
  208. *
  209. * @param {Object} option
  210. * @param {Object|boolean} [opts] opts or notMerge.
  211. * @param {boolean} [opts.notMerge=false]
  212. * @param {boolean} [opts.lazyUpdate=false] Useful when setOption frequently.
  213. */
  214. echartsProto.setOption = function (option, notMerge, lazyUpdate) {
  215. if (__DEV__) {
  216. zrUtil.assert(!this[IN_MAIN_PROCESS], '`setOption` should not be called during main process.');
  217. }
  218. var silent;
  219. if (zrUtil.isObject(notMerge)) {
  220. lazyUpdate = notMerge.lazyUpdate;
  221. silent = notMerge.silent;
  222. notMerge = notMerge.notMerge;
  223. }
  224. this[IN_MAIN_PROCESS] = true;
  225. if (!this._model || notMerge) {
  226. var optionManager = new OptionManager(this._api);
  227. var theme = this._theme;
  228. var ecModel = this._model = new GlobalModel(null, null, theme, optionManager);
  229. ecModel.init(null, null, theme, optionManager);
  230. }
  231. // FIXME
  232. // ugly
  233. this.__lastOnlyGraphic = !!(option && option.graphic);
  234. zrUtil.each(option, function (o, mainType) {
  235. mainType !== 'graphic' && (this.__lastOnlyGraphic = false);
  236. }, this);
  237. this._model.setOption(option, optionPreprocessorFuncs);
  238. if (lazyUpdate) {
  239. this[OPTION_UPDATED] = {silent: silent};
  240. this[IN_MAIN_PROCESS] = false;
  241. }
  242. else {
  243. updateMethods.prepareAndUpdate.call(this);
  244. // Ensure zr refresh sychronously, and then pixel in canvas can be
  245. // fetched after `setOption`.
  246. this._zr.flush();
  247. this[OPTION_UPDATED] = false;
  248. this[IN_MAIN_PROCESS] = false;
  249. flushPendingActions.call(this, silent);
  250. triggerUpdatedEvent.call(this, silent);
  251. }
  252. };
  253. /**
  254. * @DEPRECATED
  255. */
  256. echartsProto.setTheme = function () {
  257. console.log('ECharts#setTheme() is DEPRECATED in ECharts 3.0');
  258. };
  259. /**
  260. * @return {module:echarts/model/Global}
  261. */
  262. echartsProto.getModel = function () {
  263. return this._model;
  264. };
  265. /**
  266. * @return {Object}
  267. */
  268. echartsProto.getOption = function () {
  269. return this._model && this._model.getOption();
  270. };
  271. /**
  272. * @return {number}
  273. */
  274. echartsProto.getWidth = function () {
  275. return this._zr.getWidth();
  276. };
  277. /**
  278. * @return {number}
  279. */
  280. echartsProto.getHeight = function () {
  281. return this._zr.getHeight();
  282. };
  283. /**
  284. * Get canvas which has all thing rendered
  285. * @param {Object} opts
  286. * @param {string} [opts.backgroundColor]
  287. */
  288. echartsProto.getRenderedCanvas = function (opts) {
  289. if (!env.canvasSupported) {
  290. return;
  291. }
  292. opts = opts || {};
  293. opts.pixelRatio = opts.pixelRatio || 1;
  294. opts.backgroundColor = opts.backgroundColor
  295. || this._model.get('backgroundColor');
  296. var zr = this._zr;
  297. var list = zr.storage.getDisplayList();
  298. // Stop animations
  299. zrUtil.each(list, function (el) {
  300. el.stopAnimation(true);
  301. });
  302. return zr.painter.getRenderedCanvas(opts);
  303. };
  304. /**
  305. * @return {string}
  306. * @param {Object} opts
  307. * @param {string} [opts.type='png']
  308. * @param {string} [opts.pixelRatio=1]
  309. * @param {string} [opts.backgroundColor]
  310. * @param {string} [opts.excludeComponents]
  311. */
  312. echartsProto.getDataURL = function (opts) {
  313. opts = opts || {};
  314. var excludeComponents = opts.excludeComponents;
  315. var ecModel = this._model;
  316. var excludesComponentViews = [];
  317. var self = this;
  318. each(excludeComponents, function (componentType) {
  319. ecModel.eachComponent({
  320. mainType: componentType
  321. }, function (component) {
  322. var view = self._componentsMap[component.__viewId];
  323. if (!view.group.ignore) {
  324. excludesComponentViews.push(view);
  325. view.group.ignore = true;
  326. }
  327. });
  328. });
  329. var url = this.getRenderedCanvas(opts).toDataURL(
  330. 'image/' + (opts && opts.type || 'png')
  331. );
  332. each(excludesComponentViews, function (view) {
  333. view.group.ignore = false;
  334. });
  335. return url;
  336. };
  337. /**
  338. * @return {string}
  339. * @param {Object} opts
  340. * @param {string} [opts.type='png']
  341. * @param {string} [opts.pixelRatio=1]
  342. * @param {string} [opts.backgroundColor]
  343. */
  344. echartsProto.getConnectedDataURL = function (opts) {
  345. if (!env.canvasSupported) {
  346. return;
  347. }
  348. var groupId = this.group;
  349. var mathMin = Math.min;
  350. var mathMax = Math.max;
  351. var MAX_NUMBER = Infinity;
  352. if (connectedGroups[groupId]) {
  353. var left = MAX_NUMBER;
  354. var top = MAX_NUMBER;
  355. var right = -MAX_NUMBER;
  356. var bottom = -MAX_NUMBER;
  357. var canvasList = [];
  358. var dpr = (opts && opts.pixelRatio) || 1;
  359. zrUtil.each(instances, function (chart, id) {
  360. if (chart.group === groupId) {
  361. var canvas = chart.getRenderedCanvas(
  362. zrUtil.clone(opts)
  363. );
  364. var boundingRect = chart.getDom().getBoundingClientRect();
  365. left = mathMin(boundingRect.left, left);
  366. top = mathMin(boundingRect.top, top);
  367. right = mathMax(boundingRect.right, right);
  368. bottom = mathMax(boundingRect.bottom, bottom);
  369. canvasList.push({
  370. dom: canvas,
  371. left: boundingRect.left,
  372. top: boundingRect.top
  373. });
  374. }
  375. });
  376. left *= dpr;
  377. top *= dpr;
  378. right *= dpr;
  379. bottom *= dpr;
  380. var width = right - left;
  381. var height = bottom - top;
  382. var targetCanvas = zrUtil.createCanvas();
  383. targetCanvas.width = width;
  384. targetCanvas.height = height;
  385. var zr = zrender.init(targetCanvas);
  386. each(canvasList, function (item) {
  387. var img = new graphic.Image({
  388. style: {
  389. x: item.left * dpr - left,
  390. y: item.top * dpr - top,
  391. image: item.dom
  392. }
  393. });
  394. zr.add(img);
  395. });
  396. zr.refreshImmediately();
  397. return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png'));
  398. }
  399. else {
  400. return this.getDataURL(opts);
  401. }
  402. };
  403. /**
  404. * Convert from logical coordinate system to pixel coordinate system.
  405. * See CoordinateSystem#convertToPixel.
  406. * @param {string|Object} finder
  407. * If string, e.g., 'geo', means {geoIndex: 0}.
  408. * If Object, could contain some of these properties below:
  409. * {
  410. * seriesIndex / seriesId / seriesName,
  411. * geoIndex / geoId, geoName,
  412. * bmapIndex / bmapId / bmapName,
  413. * xAxisIndex / xAxisId / xAxisName,
  414. * yAxisIndex / yAxisId / yAxisName,
  415. * gridIndex / gridId / gridName,
  416. * ... (can be extended)
  417. * }
  418. * @param {Array|number} value
  419. * @return {Array|number} result
  420. */
  421. echartsProto.convertToPixel = zrUtil.curry(doConvertPixel, 'convertToPixel');
  422. /**
  423. * Convert from pixel coordinate system to logical coordinate system.
  424. * See CoordinateSystem#convertFromPixel.
  425. * @param {string|Object} finder
  426. * If string, e.g., 'geo', means {geoIndex: 0}.
  427. * If Object, could contain some of these properties below:
  428. * {
  429. * seriesIndex / seriesId / seriesName,
  430. * geoIndex / geoId / geoName,
  431. * bmapIndex / bmapId / bmapName,
  432. * xAxisIndex / xAxisId / xAxisName,
  433. * yAxisIndex / yAxisId / yAxisName
  434. * gridIndex / gridId / gridName,
  435. * ... (can be extended)
  436. * }
  437. * @param {Array|number} value
  438. * @return {Array|number} result
  439. */
  440. echartsProto.convertFromPixel = zrUtil.curry(doConvertPixel, 'convertFromPixel');
  441. function doConvertPixel(methodName, finder, value) {
  442. var ecModel = this._model;
  443. var coordSysList = this._coordSysMgr.getCoordinateSystems();
  444. var result;
  445. finder = modelUtil.parseFinder(ecModel, finder);
  446. for (var i = 0; i < coordSysList.length; i++) {
  447. var coordSys = coordSysList[i];
  448. if (coordSys[methodName]
  449. && (result = coordSys[methodName](ecModel, finder, value)) != null
  450. ) {
  451. return result;
  452. }
  453. }
  454. if (__DEV__) {
  455. console.warn(
  456. 'No coordinate system that supports ' + methodName + ' found by the given finder.'
  457. );
  458. }
  459. }
  460. /**
  461. * Is the specified coordinate systems or components contain the given pixel point.
  462. * @param {string|Object} finder
  463. * If string, e.g., 'geo', means {geoIndex: 0}.
  464. * If Object, could contain some of these properties below:
  465. * {
  466. * seriesIndex / seriesId / seriesName,
  467. * geoIndex / geoId / geoName,
  468. * bmapIndex / bmapId / bmapName,
  469. * xAxisIndex / xAxisId / xAxisName,
  470. * yAxisIndex / yAxisId / yAxisName
  471. * gridIndex / gridId / gridName,
  472. * ... (can be extended)
  473. * }
  474. * @param {Array|number} value
  475. * @return {boolean} result
  476. */
  477. echartsProto.containPixel = function (finder, value) {
  478. var ecModel = this._model;
  479. var result;
  480. finder = modelUtil.parseFinder(ecModel, finder);
  481. zrUtil.each(finder, function (models, key) {
  482. key.indexOf('Models') >= 0 && zrUtil.each(models, function (model) {
  483. var coordSys = model.coordinateSystem;
  484. if (coordSys && coordSys.containPoint) {
  485. result |= !!coordSys.containPoint(value);
  486. }
  487. else if (key === 'seriesModels') {
  488. var view = this._chartsMap[model.__viewId];
  489. if (view && view.containPoint) {
  490. result |= view.containPoint(value, model);
  491. }
  492. else {
  493. if (__DEV__) {
  494. console.warn(key + ': ' + (view
  495. ? 'The found component do not support containPoint.'
  496. : 'No view mapping to the found component.'
  497. ));
  498. }
  499. }
  500. }
  501. else {
  502. if (__DEV__) {
  503. console.warn(key + ': containPoint is not supported');
  504. }
  505. }
  506. }, this);
  507. }, this);
  508. return !!result;
  509. };
  510. /**
  511. * Get visual from series or data.
  512. * @param {string|Object} finder
  513. * If string, e.g., 'series', means {seriesIndex: 0}.
  514. * If Object, could contain some of these properties below:
  515. * {
  516. * seriesIndex / seriesId / seriesName,
  517. * dataIndex / dataIndexInside
  518. * }
  519. * If dataIndex is not specified, series visual will be fetched,
  520. * but not data item visual.
  521. * If all of seriesIndex, seriesId, seriesName are not specified,
  522. * visual will be fetched from first series.
  523. * @param {string} visualType 'color', 'symbol', 'symbolSize'
  524. */
  525. echartsProto.getVisual = function (finder, visualType) {
  526. var ecModel = this._model;
  527. finder = modelUtil.parseFinder(ecModel, finder, {defaultMainType: 'series'});
  528. var seriesModel = finder.seriesModel;
  529. if (__DEV__) {
  530. if (!seriesModel) {
  531. console.warn('There is no specified seires model');
  532. }
  533. }
  534. var data = seriesModel.getData();
  535. var dataIndexInside = finder.hasOwnProperty('dataIndexInside')
  536. ? finder.dataIndexInside
  537. : finder.hasOwnProperty('dataIndex')
  538. ? data.indexOfRawIndex(finder.dataIndex)
  539. : null;
  540. return dataIndexInside != null
  541. ? data.getItemVisual(dataIndexInside, visualType)
  542. : data.getVisual(visualType);
  543. };
  544. var updateMethods = {
  545. /**
  546. * @param {Object} payload
  547. * @private
  548. */
  549. update: function (payload) {
  550. // console.time && console.time('update');
  551. var ecModel = this._model;
  552. var api = this._api;
  553. var coordSysMgr = this._coordSysMgr;
  554. var zr = this._zr;
  555. // update before setOption
  556. if (!ecModel) {
  557. return;
  558. }
  559. // Fixme First time update ?
  560. ecModel.restoreData();
  561. // TODO
  562. // Save total ecModel here for undo/redo (after restoring data and before processing data).
  563. // Undo (restoration of total ecModel) can be carried out in 'action' or outside API call.
  564. // Create new coordinate system each update
  565. // In LineView may save the old coordinate system and use it to get the orignal point
  566. coordSysMgr.create(this._model, this._api);
  567. processData.call(this, ecModel, api);
  568. stackSeriesData.call(this, ecModel);
  569. coordSysMgr.update(ecModel, api);
  570. doVisualEncoding.call(this, ecModel, payload);
  571. doRender.call(this, ecModel, payload);
  572. // Set background
  573. var backgroundColor = ecModel.get('backgroundColor') || 'transparent';
  574. var painter = zr.painter;
  575. // TODO all use clearColor ?
  576. if (painter.isSingleCanvas && painter.isSingleCanvas()) {
  577. zr.configLayer(0, {
  578. clearColor: backgroundColor
  579. });
  580. }
  581. else {
  582. // In IE8
  583. if (!env.canvasSupported) {
  584. var colorArr = colorTool.parse(backgroundColor);
  585. backgroundColor = colorTool.stringify(colorArr, 'rgb');
  586. if (colorArr[3] === 0) {
  587. backgroundColor = 'transparent';
  588. }
  589. }
  590. if (backgroundColor.colorStops || backgroundColor.image) {
  591. // Gradient background
  592. // FIXME Fixed layer?
  593. zr.configLayer(0, {
  594. clearColor: backgroundColor
  595. });
  596. this[HAS_GRADIENT_OR_PATTERN_BG] = true;
  597. this._dom.style.background = 'transparent';
  598. }
  599. else {
  600. if (this[HAS_GRADIENT_OR_PATTERN_BG]) {
  601. zr.configLayer(0, {
  602. clearColor: null
  603. });
  604. }
  605. this[HAS_GRADIENT_OR_PATTERN_BG] = false;
  606. this._dom.style.background = backgroundColor;
  607. }
  608. }
  609. // console.time && console.timeEnd('update');
  610. },
  611. /**
  612. * @param {Object} payload
  613. * @private
  614. */
  615. updateView: function (payload) {
  616. var ecModel = this._model;
  617. // update before setOption
  618. if (!ecModel) {
  619. return;
  620. }
  621. ecModel.eachSeries(function (seriesModel) {
  622. seriesModel.getData().clearAllVisual();
  623. });
  624. doVisualEncoding.call(this, ecModel, payload);
  625. invokeUpdateMethod.call(this, 'updateView', ecModel, payload);
  626. },
  627. /**
  628. * @param {Object} payload
  629. * @private
  630. */
  631. updateVisual: function (payload) {
  632. var ecModel = this._model;
  633. // update before setOption
  634. if (!ecModel) {
  635. return;
  636. }
  637. ecModel.eachSeries(function (seriesModel) {
  638. seriesModel.getData().clearAllVisual();
  639. });
  640. doVisualEncoding.call(this, ecModel, payload, true);
  641. invokeUpdateMethod.call(this, 'updateVisual', ecModel, payload);
  642. },
  643. /**
  644. * @param {Object} payload
  645. * @private
  646. */
  647. updateLayout: function (payload) {
  648. var ecModel = this._model;
  649. // update before setOption
  650. if (!ecModel) {
  651. return;
  652. }
  653. doLayout.call(this, ecModel, payload);
  654. invokeUpdateMethod.call(this, 'updateLayout', ecModel, payload);
  655. },
  656. /**
  657. * @param {Object} payload
  658. * @private
  659. */
  660. prepareAndUpdate: function (payload) {
  661. var ecModel = this._model;
  662. prepareView.call(this, 'component', ecModel);
  663. prepareView.call(this, 'chart', ecModel);
  664. // FIXME
  665. // ugly
  666. if (this.__lastOnlyGraphic) {
  667. each(this._componentsViews, function (componentView) {
  668. var componentModel = componentView.__model;
  669. if (componentModel && componentModel.mainType === 'graphic') {
  670. componentView.render(componentModel, ecModel, this._api, payload);
  671. updateZ(componentModel, componentView);
  672. }
  673. }, this);
  674. this.__lastOnlyGraphic = false;
  675. }
  676. else {
  677. updateMethods.update.call(this, payload);
  678. }
  679. }
  680. };
  681. /**
  682. * @private
  683. */
  684. function updateDirectly(ecIns, method, payload, mainType, subType) {
  685. var ecModel = ecIns._model;
  686. var query = {};
  687. query[mainType + 'Id'] = payload[mainType + 'Id'];
  688. query[mainType + 'Index'] = payload[mainType + 'Index'];
  689. query[mainType + 'Name'] = payload[mainType + 'Name'];
  690. var condition = {mainType: mainType, query: query};
  691. subType && (condition.subType = subType); // subType may be '' by parseClassType;
  692. // If dispatchAction before setOption, do nothing.
  693. ecModel && ecModel.eachComponent(condition, function (model, index) {
  694. var view = ecIns[
  695. mainType === 'series' ? '_chartsMap' : '_componentsMap'
  696. ][model.__viewId];
  697. if (view && view.__alive) {
  698. view[method](model, ecModel, ecIns._api, payload);
  699. }
  700. }, ecIns);
  701. }
  702. /**
  703. * Resize the chart
  704. * @param {Object} opts
  705. * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)
  706. * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)
  707. * @param {boolean} [opts.silent=false]
  708. */
  709. echartsProto.resize = function (opts) {
  710. if (__DEV__) {
  711. zrUtil.assert(!this[IN_MAIN_PROCESS], '`resize` should not be called during main process.');
  712. }
  713. this[IN_MAIN_PROCESS] = true;
  714. this._zr.resize(opts);
  715. var optionChanged = this._model && this._model.resetOption('media');
  716. var updateMethod = optionChanged ? 'prepareAndUpdate' : 'update';
  717. updateMethods[updateMethod].call(this);
  718. // Resize loading effect
  719. this._loadingFX && this._loadingFX.resize();
  720. this[IN_MAIN_PROCESS] = false;
  721. var silent = opts && opts.silent;
  722. flushPendingActions.call(this, silent);
  723. triggerUpdatedEvent.call(this, silent);
  724. };
  725. /**
  726. * Show loading effect
  727. * @param {string} [name='default']
  728. * @param {Object} [cfg]
  729. */
  730. echartsProto.showLoading = function (name, cfg) {
  731. if (zrUtil.isObject(name)) {
  732. cfg = name;
  733. name = '';
  734. }
  735. name = name || 'default';
  736. this.hideLoading();
  737. if (!loadingEffects[name]) {
  738. if (__DEV__) {
  739. console.warn('Loading effects ' + name + ' not exists.');
  740. }
  741. return;
  742. }
  743. var el = loadingEffects[name](this._api, cfg);
  744. var zr = this._zr;
  745. this._loadingFX = el;
  746. zr.add(el);
  747. };
  748. /**
  749. * Hide loading effect
  750. */
  751. echartsProto.hideLoading = function () {
  752. this._loadingFX && this._zr.remove(this._loadingFX);
  753. this._loadingFX = null;
  754. };
  755. /**
  756. * @param {Object} eventObj
  757. * @return {Object}
  758. */
  759. echartsProto.makeActionFromEvent = function (eventObj) {
  760. var payload = zrUtil.extend({}, eventObj);
  761. payload.type = eventActionMap[eventObj.type];
  762. return payload;
  763. };
  764. /**
  765. * @pubilc
  766. * @param {Object} payload
  767. * @param {string} [payload.type] Action type
  768. * @param {Object|boolean} [opt] If pass boolean, means opt.silent
  769. * @param {boolean} [opt.silent=false] Whether trigger events.
  770. * @param {boolean} [opt.flush=undefined]
  771. * true: Flush immediately, and then pixel in canvas can be fetched
  772. * immediately. Caution: it might affect performance.
  773. * false: Not not flush.
  774. * undefined: Auto decide whether perform flush.
  775. */
  776. echartsProto.dispatchAction = function (payload, opt) {
  777. if (!zrUtil.isObject(opt)) {
  778. opt = {silent: !!opt};
  779. }
  780. if (!actions[payload.type]) {
  781. return;
  782. }
  783. // if (__DEV__) {
  784. // zrUtil.assert(
  785. // !this[IN_MAIN_PROCESS],
  786. // '`dispatchAction` should not be called during main process.'
  787. // + 'unless updateMathod is "none".'
  788. // );
  789. // }
  790. // May dispatchAction in rendering procedure
  791. if (this[IN_MAIN_PROCESS]) {
  792. this._pendingActions.push(payload);
  793. return;
  794. }
  795. doDispatchAction.call(this, payload, opt.silent);
  796. if (opt.flush) {
  797. this._zr.flush(true);
  798. }
  799. else if (opt.flush !== false && env.browser.weChat) {
  800. // In WeChat embeded browser, `requestAnimationFrame` and `setInterval`
  801. // hang when sliding page (on touch event), which cause that zr does not
  802. // refresh util user interaction finished, which is not expected.
  803. // But `dispatchAction` may be called too frequently when pan on touch
  804. // screen, which impacts performance if do not throttle them.
  805. this._throttledZrFlush();
  806. }
  807. flushPendingActions.call(this, opt.silent);
  808. triggerUpdatedEvent.call(this, opt.silent);
  809. };
  810. function doDispatchAction(payload, silent) {
  811. var payloadType = payload.type;
  812. var actionWrap = actions[payloadType];
  813. var actionInfo = actionWrap.actionInfo;
  814. var cptType = (actionInfo.update || 'update').split(':');
  815. var updateMethod = cptType.pop();
  816. cptType = cptType[0] && parseClassType(cptType[0]);
  817. this[IN_MAIN_PROCESS] = true;
  818. var payloads = [payload];
  819. var batched = false;
  820. // Batch action
  821. if (payload.batch) {
  822. batched = true;
  823. payloads = zrUtil.map(payload.batch, function (item) {
  824. item = zrUtil.defaults(zrUtil.extend({}, item), payload);
  825. item.batch = null;
  826. return item;
  827. });
  828. }
  829. var eventObjBatch = [];
  830. var eventObj;
  831. var isHighDown = payloadType === 'highlight' || payloadType === 'downplay';
  832. for (var i = 0; i < payloads.length; i++) {
  833. var batchItem = payloads[i];
  834. // Action can specify the event by return it.
  835. eventObj = actionWrap.action(batchItem, this._model);
  836. // Emit event outside
  837. eventObj = eventObj || zrUtil.extend({}, batchItem);
  838. // Convert type to eventType
  839. eventObj.type = actionInfo.event || eventObj.type;
  840. eventObjBatch.push(eventObj);
  841. // light update does not perform data process, layout and visual.
  842. if (isHighDown) {
  843. // method, payload, mainType, subType
  844. updateDirectly(this, updateMethod, batchItem, 'series');
  845. }
  846. else if (cptType) {
  847. updateDirectly(this, updateMethod, batchItem, cptType.main, cptType.sub);
  848. }
  849. }
  850. if (updateMethod !== 'none' && !isHighDown && !cptType) {
  851. // Still dirty
  852. if (this[OPTION_UPDATED]) {
  853. // FIXME Pass payload ?
  854. updateMethods.prepareAndUpdate.call(this, payload);
  855. this[OPTION_UPDATED] = false;
  856. }
  857. else {
  858. updateMethods[updateMethod].call(this, payload);
  859. }
  860. }
  861. // Follow the rule of action batch
  862. if (batched) {
  863. eventObj = {
  864. type: actionInfo.event || payloadType,
  865. batch: eventObjBatch
  866. };
  867. }
  868. else {
  869. eventObj = eventObjBatch[0];
  870. }
  871. this[IN_MAIN_PROCESS] = false;
  872. !silent && this._messageCenter.trigger(eventObj.type, eventObj);
  873. }
  874. function flushPendingActions(silent) {
  875. var pendingActions = this._pendingActions;
  876. while (pendingActions.length) {
  877. var payload = pendingActions.shift();
  878. doDispatchAction.call(this, payload, silent);
  879. }
  880. }
  881. function triggerUpdatedEvent(silent) {
  882. !silent && this.trigger('updated');
  883. }
  884. /**
  885. * Register event
  886. * @method
  887. */
  888. echartsProto.on = createRegisterEventWithLowercaseName('on');
  889. echartsProto.off = createRegisterEventWithLowercaseName('off');
  890. echartsProto.one = createRegisterEventWithLowercaseName('one');
  891. /**
  892. * @param {string} methodName
  893. * @private
  894. */
  895. function invokeUpdateMethod(methodName, ecModel, payload) {
  896. var api = this._api;
  897. // Update all components
  898. each(this._componentsViews, function (component) {
  899. var componentModel = component.__model;
  900. component[methodName](componentModel, ecModel, api, payload);
  901. updateZ(componentModel, component);
  902. }, this);
  903. // Upate all charts
  904. ecModel.eachSeries(function (seriesModel, idx) {
  905. var chart = this._chartsMap[seriesModel.__viewId];
  906. chart[methodName](seriesModel, ecModel, api, payload);
  907. updateZ(seriesModel, chart);
  908. updateProgressiveAndBlend(seriesModel, chart);
  909. }, this);
  910. // If use hover layer
  911. updateHoverLayerStatus(this._zr, ecModel);
  912. }
  913. /**
  914. * Prepare view instances of charts and components
  915. * @param {module:echarts/model/Global} ecModel
  916. * @private
  917. */
  918. function prepareView(type, ecModel) {
  919. var isComponent = type === 'component';
  920. var viewList = isComponent ? this._componentsViews : this._chartsViews;
  921. var viewMap = isComponent ? this._componentsMap : this._chartsMap;
  922. var zr = this._zr;
  923. for (var i = 0; i < viewList.length; i++) {
  924. viewList[i].__alive = false;
  925. }
  926. ecModel[isComponent ? 'eachComponent' : 'eachSeries'](function (componentType, model) {
  927. if (isComponent) {
  928. if (componentType === 'series') {
  929. return;
  930. }
  931. }
  932. else {
  933. model = componentType;
  934. }
  935. // Consider: id same and type changed.
  936. var viewId = model.id + '_' + model.type;
  937. var view = viewMap[viewId];
  938. if (!view) {
  939. var classType = parseClassType(model.type);
  940. var Clazz = isComponent
  941. ? ComponentView.getClass(classType.main, classType.sub)
  942. : ChartView.getClass(classType.sub);
  943. if (Clazz) {
  944. view = new Clazz();
  945. view.init(ecModel, this._api);
  946. viewMap[viewId] = view;
  947. viewList.push(view);
  948. zr.add(view.group);
  949. }
  950. else {
  951. // Error
  952. return;
  953. }
  954. }
  955. model.__viewId = viewId;
  956. view.__alive = true;
  957. view.__id = viewId;
  958. view.__model = model;
  959. }, this);
  960. for (var i = 0; i < viewList.length;) {
  961. var view = viewList[i];
  962. if (!view.__alive) {
  963. zr.remove(view.group);
  964. view.dispose(ecModel, this._api);
  965. viewList.splice(i, 1);
  966. delete viewMap[view.__id];
  967. }
  968. else {
  969. i++;
  970. }
  971. }
  972. }
  973. /**
  974. * Processor data in each series
  975. *
  976. * @param {module:echarts/model/Global} ecModel
  977. * @private
  978. */
  979. function processData(ecModel, api) {
  980. each(dataProcessorFuncs, function (process) {
  981. process.func(ecModel, api);
  982. });
  983. }
  984. /**
  985. * @private
  986. */
  987. function stackSeriesData(ecModel) {
  988. var stackedDataMap = {};
  989. ecModel.eachSeries(function (series) {
  990. var stack = series.get('stack');
  991. var data = series.getData();
  992. if (stack && data.type === 'list') {
  993. var previousStack = stackedDataMap[stack];
  994. if (previousStack) {
  995. data.stackedOn = previousStack;
  996. }
  997. stackedDataMap[stack] = data;
  998. }
  999. });
  1000. }
  1001. /**
  1002. * Layout before each chart render there series, special visual encoding stage
  1003. *
  1004. * @param {module:echarts/model/Global} ecModel
  1005. * @private
  1006. */
  1007. function doLayout(ecModel, payload) {
  1008. var api = this._api;
  1009. each(visualFuncs, function (visual) {
  1010. if (visual.isLayout) {
  1011. visual.func(ecModel, api, payload);
  1012. }
  1013. });
  1014. }
  1015. /**
  1016. * Encode visual infomation from data after data processing
  1017. *
  1018. * @param {module:echarts/model/Global} ecModel
  1019. * @param {object} layout
  1020. * @param {boolean} [excludesLayout]
  1021. * @private
  1022. */
  1023. function doVisualEncoding(ecModel, payload, excludesLayout) {
  1024. var api = this._api;
  1025. ecModel.clearColorPalette();
  1026. ecModel.eachSeries(function (seriesModel) {
  1027. seriesModel.clearColorPalette();
  1028. });
  1029. each(visualFuncs, function (visual) {
  1030. (!excludesLayout || !visual.isLayout)
  1031. && visual.func(ecModel, api, payload);
  1032. });
  1033. }
  1034. /**
  1035. * Render each chart and component
  1036. * @private
  1037. */
  1038. function doRender(ecModel, payload) {
  1039. var api = this._api;
  1040. // Render all components
  1041. each(this._componentsViews, function (componentView) {
  1042. var componentModel = componentView.__model;
  1043. componentView.render(componentModel, ecModel, api, payload);
  1044. updateZ(componentModel, componentView);
  1045. }, this);
  1046. each(this._chartsViews, function (chart) {
  1047. chart.__alive = false;
  1048. }, this);
  1049. // Render all charts
  1050. ecModel.eachSeries(function (seriesModel, idx) {
  1051. var chartView = this._chartsMap[seriesModel.__viewId];
  1052. chartView.__alive = true;
  1053. chartView.render(seriesModel, ecModel, api, payload);
  1054. chartView.group.silent = !!seriesModel.get('silent');
  1055. updateZ(seriesModel, chartView);
  1056. updateProgressiveAndBlend(seriesModel, chartView);
  1057. }, this);
  1058. // If use hover layer
  1059. updateHoverLayerStatus(this._zr, ecModel);
  1060. // Remove groups of unrendered charts
  1061. each(this._chartsViews, function (chart) {
  1062. if (!chart.__alive) {
  1063. chart.remove(ecModel, api);
  1064. }
  1065. }, this);
  1066. }
  1067. var MOUSE_EVENT_NAMES = [
  1068. 'click', 'dblclick', 'mouseover', 'mouseout', 'mousemove',
  1069. 'mousedown', 'mouseup', 'globalout', 'contextmenu'
  1070. ];
  1071. /**
  1072. * @private
  1073. */
  1074. echartsProto._initEvents = function () {
  1075. each(MOUSE_EVENT_NAMES, function (eveName) {
  1076. this._zr.on(eveName, function (e) {
  1077. var ecModel = this.getModel();
  1078. var el = e.target;
  1079. var params;
  1080. // no e.target when 'globalout'.
  1081. if (eveName === 'globalout') {
  1082. params = {};
  1083. }
  1084. else if (el && el.dataIndex != null) {
  1085. var dataModel = el.dataModel || ecModel.getSeriesByIndex(el.seriesIndex);
  1086. params = dataModel && dataModel.getDataParams(el.dataIndex, el.dataType) || {};
  1087. }
  1088. // If element has custom eventData of components
  1089. else if (el && el.eventData) {
  1090. params = zrUtil.extend({}, el.eventData);
  1091. }
  1092. if (params) {
  1093. params.event = e;
  1094. params.type = eveName;
  1095. this.trigger(eveName, params);
  1096. }
  1097. }, this);
  1098. }, this);
  1099. each(eventActionMap, function (actionType, eventType) {
  1100. this._messageCenter.on(eventType, function (event) {
  1101. this.trigger(eventType, event);
  1102. }, this);
  1103. }, this);
  1104. };
  1105. /**
  1106. * @return {boolean}
  1107. */
  1108. echartsProto.isDisposed = function () {
  1109. return this._disposed;
  1110. };
  1111. /**
  1112. * Clear
  1113. */
  1114. echartsProto.clear = function () {
  1115. this.setOption({ series: [] }, true);
  1116. };
  1117. /**
  1118. * Dispose instance
  1119. */
  1120. echartsProto.dispose = function () {
  1121. if (this._disposed) {
  1122. if (__DEV__) {
  1123. console.warn('Instance ' + this.id + ' has been disposed');
  1124. }
  1125. return;
  1126. }
  1127. this._disposed = true;
  1128. var api = this._api;
  1129. var ecModel = this._model;
  1130. each(this._componentsViews, function (component) {
  1131. component.dispose(ecModel, api);
  1132. });
  1133. each(this._chartsViews, function (chart) {
  1134. chart.dispose(ecModel, api);
  1135. });
  1136. // Dispose after all views disposed
  1137. this._zr.dispose();
  1138. delete instances[this.id];
  1139. };
  1140. zrUtil.mixin(ECharts, Eventful);
  1141. function updateHoverLayerStatus(zr, ecModel) {
  1142. var storage = zr.storage;
  1143. var elCount = 0;
  1144. storage.traverse(function (el) {
  1145. if (!el.isGroup) {
  1146. elCount++;
  1147. }
  1148. });
  1149. if (elCount > ecModel.get('hoverLayerThreshold') && !env.node) {
  1150. storage.traverse(function (el) {
  1151. if (!el.isGroup) {
  1152. el.useHoverLayer = true;
  1153. }
  1154. });
  1155. }
  1156. }
  1157. /**
  1158. * Update chart progressive and blend.
  1159. * @param {module:echarts/model/Series|module:echarts/model/Component} model
  1160. * @param {module:echarts/view/Component|module:echarts/view/Chart} view
  1161. */
  1162. function updateProgressiveAndBlend(seriesModel, chartView) {
  1163. // Progressive configuration
  1164. var elCount = 0;
  1165. chartView.group.traverse(function (el) {
  1166. if (el.type !== 'group' && !el.ignore) {
  1167. elCount++;
  1168. }
  1169. });
  1170. var frameDrawNum = +seriesModel.get('progressive');
  1171. var needProgressive = elCount > seriesModel.get('progressiveThreshold') && frameDrawNum && !env.node;
  1172. if (needProgressive) {
  1173. chartView.group.traverse(function (el) {
  1174. // FIXME marker and other components
  1175. if (!el.isGroup) {
  1176. el.progressive = needProgressive ?
  1177. Math.floor(elCount++ / frameDrawNum) : -1;
  1178. if (needProgressive) {
  1179. el.stopAnimation(true);
  1180. }
  1181. }
  1182. });
  1183. }
  1184. // Blend configration
  1185. var blendMode = seriesModel.get('blendMode') || null;
  1186. if (__DEV__) {
  1187. if (!env.canvasSupported && blendMode && blendMode !== 'source-over') {
  1188. console.warn('Only canvas support blendMode');
  1189. }
  1190. }
  1191. chartView.group.traverse(function (el) {
  1192. // FIXME marker and other components
  1193. if (!el.isGroup) {
  1194. el.setStyle('blend', blendMode);
  1195. }
  1196. });
  1197. }
  1198. /**
  1199. * @param {module:echarts/model/Series|module:echarts/model/Component} model
  1200. * @param {module:echarts/view/Component|module:echarts/view/Chart} view
  1201. */
  1202. function updateZ(model, view) {
  1203. var z = model.get('z');
  1204. var zlevel = model.get('zlevel');
  1205. // Set z and zlevel
  1206. view.group.traverse(function (el) {
  1207. if (el.type !== 'group') {
  1208. z != null && (el.z = z);
  1209. zlevel != null && (el.zlevel = zlevel);
  1210. }
  1211. });
  1212. }
  1213. /**
  1214. * @type {Array.<Function>}
  1215. * @inner
  1216. */
  1217. var actions = [];
  1218. /**
  1219. * Map eventType to actionType
  1220. * @type {Object}
  1221. */
  1222. var eventActionMap = {};
  1223. /**
  1224. * Data processor functions of each stage
  1225. * @type {Array.<Object.<string, Function>>}
  1226. * @inner
  1227. */
  1228. var dataProcessorFuncs = [];
  1229. /**
  1230. * @type {Array.<Function>}
  1231. * @inner
  1232. */
  1233. var optionPreprocessorFuncs = [];
  1234. /**
  1235. * Visual encoding functions of each stage
  1236. * @type {Array.<Object.<string, Function>>}
  1237. * @inner
  1238. */
  1239. var visualFuncs = [];
  1240. /**
  1241. * Theme storage
  1242. * @type {Object.<key, Object>}
  1243. */
  1244. var themeStorage = {};
  1245. /**
  1246. * Loading effects
  1247. */
  1248. var loadingEffects = {};
  1249. var instances = {};
  1250. var connectedGroups = {};
  1251. var idBase = new Date() - 0;
  1252. var groupIdBase = new Date() - 0;
  1253. var DOM_ATTRIBUTE_KEY = '_echarts_instance_';
  1254. /**
  1255. * @alias module:echarts
  1256. */
  1257. var echarts = {
  1258. /**
  1259. * @type {number}
  1260. */
  1261. version: '3.4.0',
  1262. dependencies: {
  1263. zrender: '3.3.0'
  1264. }
  1265. };
  1266. function enableConnect(chart) {
  1267. var STATUS_PENDING = 0;
  1268. var STATUS_UPDATING = 1;
  1269. var STATUS_UPDATED = 2;
  1270. var STATUS_KEY = '__connectUpdateStatus';
  1271. function updateConnectedChartsStatus(charts, status) {
  1272. for (var i = 0; i < charts.length; i++) {
  1273. var otherChart = charts[i];
  1274. otherChart[STATUS_KEY] = status;
  1275. }
  1276. }
  1277. zrUtil.each(eventActionMap, function (actionType, eventType) {
  1278. chart._messageCenter.on(eventType, function (event) {
  1279. if (connectedGroups[chart.group] && chart[STATUS_KEY] !== STATUS_PENDING) {
  1280. var action = chart.makeActionFromEvent(event);
  1281. var otherCharts = [];
  1282. zrUtil.each(instances, function (otherChart) {
  1283. if (otherChart !== chart && otherChart.group === chart.group) {
  1284. otherCharts.push(otherChart);
  1285. }
  1286. });
  1287. updateConnectedChartsStatus(otherCharts, STATUS_PENDING);
  1288. each(otherCharts, function (otherChart) {
  1289. if (otherChart[STATUS_KEY] !== STATUS_UPDATING) {
  1290. otherChart.dispatchAction(action);
  1291. }
  1292. });
  1293. updateConnectedChartsStatus(otherCharts, STATUS_UPDATED);
  1294. }
  1295. });
  1296. });
  1297. }
  1298. /**
  1299. * @param {HTMLDomElement} dom
  1300. * @param {Object} [theme]
  1301. * @param {Object} opts
  1302. * @param {number} [opts.devicePixelRatio] Use window.devicePixelRatio by default
  1303. * @param {string} [opts.renderer] Currently only 'canvas' is supported.
  1304. * @param {number} [opts.width] Use clientWidth of the input `dom` by default.
  1305. * Can be 'auto' (the same as null/undefined)
  1306. * @param {number} [opts.height] Use clientHeight of the input `dom` by default.
  1307. * Can be 'auto' (the same as null/undefined)
  1308. */
  1309. echarts.init = function (dom, theme, opts) {
  1310. if (__DEV__) {
  1311. // Check version
  1312. if ((zrender.version.replace('.', '') - 0) < (echarts.dependencies.zrender.replace('.', '') - 0)) {
  1313. throw new Error(
  1314. 'ZRender ' + zrender.version
  1315. + ' is too old for ECharts ' + echarts.version
  1316. + '. Current version need ZRender '
  1317. + echarts.dependencies.zrender + '+'
  1318. );
  1319. }
  1320. if (!dom) {
  1321. throw new Error('Initialize failed: invalid dom.');
  1322. }
  1323. if (zrUtil.isDom(dom) && dom.nodeName.toUpperCase() !== 'CANVAS' && (!dom.clientWidth || !dom.clientHeight)) {
  1324. console.warn('Can\'t get dom width or height');
  1325. }
  1326. }
  1327. var chart = new ECharts(dom, theme, opts);
  1328. chart.id = 'ec_' + idBase++;
  1329. instances[chart.id] = chart;
  1330. dom.setAttribute &&
  1331. dom.setAttribute(DOM_ATTRIBUTE_KEY, chart.id);
  1332. enableConnect(chart);
  1333. return chart;
  1334. };
  1335. /**
  1336. * @return {string|Array.<module:echarts~ECharts>} groupId
  1337. */
  1338. echarts.connect = function (groupId) {
  1339. // Is array of charts
  1340. if (zrUtil.isArray(groupId)) {
  1341. var charts = groupId;
  1342. groupId = null;
  1343. // If any chart has group
  1344. zrUtil.each(charts, function (chart) {
  1345. if (chart.group != null) {
  1346. groupId = chart.group;
  1347. }
  1348. });
  1349. groupId = groupId || ('g_' + groupIdBase++);
  1350. zrUtil.each(charts, function (chart) {
  1351. chart.group = groupId;
  1352. });
  1353. }
  1354. connectedGroups[groupId] = true;
  1355. return groupId;
  1356. };
  1357. /**
  1358. * @return {string} groupId
  1359. */
  1360. echarts.disConnect = function (groupId) {
  1361. connectedGroups[groupId] = false;
  1362. };
  1363. /**
  1364. * Dispose a chart instance
  1365. * @param {module:echarts~ECharts|HTMLDomElement|string} chart
  1366. */
  1367. echarts.dispose = function (chart) {
  1368. if (zrUtil.isDom(chart)) {
  1369. chart = echarts.getInstanceByDom(chart);
  1370. }
  1371. else if (typeof chart === 'string') {
  1372. chart = instances[chart];
  1373. }
  1374. if ((chart instanceof ECharts) && !chart.isDisposed()) {
  1375. chart.dispose();
  1376. }
  1377. };
  1378. /**
  1379. * @param {HTMLDomElement} dom
  1380. * @return {echarts~ECharts}
  1381. */
  1382. echarts.getInstanceByDom = function (dom) {
  1383. var key = dom.getAttribute(DOM_ATTRIBUTE_KEY);
  1384. return instances[key];
  1385. };
  1386. /**
  1387. * @param {string} key
  1388. * @return {echarts~ECharts}
  1389. */
  1390. echarts.getInstanceById = function (key) {
  1391. return instances[key];
  1392. };
  1393. /**
  1394. * Register theme
  1395. */
  1396. echarts.registerTheme = function (name, theme) {
  1397. themeStorage[name] = theme;
  1398. };
  1399. /**
  1400. * Register option preprocessor
  1401. * @param {Function} preprocessorFunc
  1402. */
  1403. echarts.registerPreprocessor = function (preprocessorFunc) {
  1404. optionPreprocessorFuncs.push(preprocessorFunc);
  1405. };
  1406. /**
  1407. * @param {number} [priority=1000]
  1408. * @param {Function} processorFunc
  1409. */
  1410. echarts.registerProcessor = function (priority, processorFunc) {
  1411. if (typeof priority === 'function') {
  1412. processorFunc = priority;
  1413. priority = PRIORITY_PROCESSOR_FILTER;
  1414. }
  1415. if (__DEV__) {
  1416. if (isNaN(priority)) {
  1417. throw new Error('Unkown processor priority');
  1418. }
  1419. }
  1420. dataProcessorFuncs.push({
  1421. prio: priority,
  1422. func: processorFunc
  1423. });
  1424. };
  1425. /**
  1426. * Usage:
  1427. * registerAction('someAction', 'someEvent', function () { ... });
  1428. * registerAction('someAction', function () { ... });
  1429. * registerAction(
  1430. * {type: 'someAction', event: 'someEvent', update: 'updateView'},
  1431. * function () { ... }
  1432. * );
  1433. *
  1434. * @param {(string|Object)} actionInfo
  1435. * @param {string} actionInfo.type
  1436. * @param {string} [actionInfo.event]
  1437. * @param {string} [actionInfo.update]
  1438. * @param {string} [eventName]
  1439. * @param {Function} action
  1440. */
  1441. echarts.registerAction = function (actionInfo, eventName, action) {
  1442. if (typeof eventName === 'function') {
  1443. action = eventName;
  1444. eventName = '';
  1445. }
  1446. var actionType = zrUtil.isObject(actionInfo)
  1447. ? actionInfo.type
  1448. : ([actionInfo, actionInfo = {
  1449. event: eventName
  1450. }][0]);
  1451. // Event name is all lowercase
  1452. actionInfo.event = (actionInfo.event || actionType).toLowerCase();
  1453. eventName = actionInfo.event;
  1454. // Validate action type and event name.
  1455. zrUtil.assert(ACTION_REG.test(actionType) && ACTION_REG.test(eventName));
  1456. if (!actions[actionType]) {
  1457. actions[actionType] = {action: action, actionInfo: actionInfo};
  1458. }
  1459. eventActionMap[eventName] = actionType;
  1460. };
  1461. /**
  1462. * @param {string} type
  1463. * @param {*} CoordinateSystem
  1464. */
  1465. echarts.registerCoordinateSystem = function (type, CoordinateSystem) {
  1466. CoordinateSystemManager.register(type, CoordinateSystem);
  1467. };
  1468. /**
  1469. * Layout is a special stage of visual encoding
  1470. * Most visual encoding like color are common for different chart
  1471. * But each chart has it's own layout algorithm
  1472. *
  1473. * @param {number} [priority=1000]
  1474. * @param {Function} layoutFunc
  1475. */
  1476. echarts.registerLayout = function (priority, layoutFunc) {
  1477. if (typeof priority === 'function') {
  1478. layoutFunc = priority;
  1479. priority = PRIORITY_VISUAL_LAYOUT;
  1480. }
  1481. if (__DEV__) {
  1482. if (isNaN(priority)) {
  1483. throw new Error('Unkown layout priority');
  1484. }
  1485. }
  1486. visualFuncs.push({
  1487. prio: priority,
  1488. func: layoutFunc,
  1489. isLayout: true
  1490. });
  1491. };
  1492. /**
  1493. * @param {number} [priority=3000]
  1494. * @param {Function} visualFunc
  1495. */
  1496. echarts.registerVisual = function (priority, visualFunc) {
  1497. if (typeof priority === 'function') {
  1498. visualFunc = priority;
  1499. priority = PRIORITY_VISUAL_CHART;
  1500. }
  1501. if (__DEV__) {
  1502. if (isNaN(priority)) {
  1503. throw new Error('Unkown visual priority');
  1504. }
  1505. }
  1506. visualFuncs.push({
  1507. prio: priority,
  1508. func: visualFunc
  1509. });
  1510. };
  1511. /**
  1512. * @param {string} name
  1513. */
  1514. echarts.registerLoading = function (name, loadingFx) {
  1515. loadingEffects[name] = loadingFx;
  1516. };
  1517. /**
  1518. * @param {Object} opts
  1519. * @param {string} [superClass]
  1520. */
  1521. echarts.extendComponentModel = function (opts/*, superClass*/) {
  1522. // var Clazz = ComponentModel;
  1523. // if (superClass) {
  1524. // var classType = parseClassType(superClass);
  1525. // Clazz = ComponentModel.getClass(classType.main, classType.sub, true);
  1526. // }
  1527. return ComponentModel.extend(opts);
  1528. };
  1529. /**
  1530. * @param {Object} opts
  1531. * @param {string} [superClass]
  1532. */
  1533. echarts.extendComponentView = function (opts/*, superClass*/) {
  1534. // var Clazz = ComponentView;
  1535. // if (superClass) {
  1536. // var classType = parseClassType(superClass);
  1537. // Clazz = ComponentView.getClass(classType.main, classType.sub, true);
  1538. // }
  1539. return ComponentView.extend(opts);
  1540. };
  1541. /**
  1542. * @param {Object} opts
  1543. * @param {string} [superClass]
  1544. */
  1545. echarts.extendSeriesModel = function (opts/*, superClass*/) {
  1546. // var Clazz = SeriesModel;
  1547. // if (superClass) {
  1548. // superClass = 'series.' + superClass.replace('series.', '');
  1549. // var classType = parseClassType(superClass);
  1550. // Clazz = ComponentModel.getClass(classType.main, classType.sub, true);
  1551. // }
  1552. return SeriesModel.extend(opts);
  1553. };
  1554. /**
  1555. * @param {Object} opts
  1556. * @param {string} [superClass]
  1557. */
  1558. echarts.extendChartView = function (opts/*, superClass*/) {
  1559. // var Clazz = ChartView;
  1560. // if (superClass) {
  1561. // superClass = superClass.replace('series.', '');
  1562. // var classType = parseClassType(superClass);
  1563. // Clazz = ChartView.getClass(classType.main, true);
  1564. // }
  1565. return ChartView.extend(opts);
  1566. };
  1567. /**
  1568. * ZRender need a canvas context to do measureText.
  1569. * But in node environment canvas may be created by node-canvas.
  1570. * So we need to specify how to create a canvas instead of using document.createElement('canvas')
  1571. *
  1572. * Be careful of using it in the browser.
  1573. *
  1574. * @param {Function} creator
  1575. * @example
  1576. * var Canvas = require('canvas');
  1577. * var echarts = require('echarts');
  1578. * echarts.setCanvasCreator(function () {
  1579. * // Small size is enough.
  1580. * return new Canvas(32, 32);
  1581. * });
  1582. */
  1583. echarts.setCanvasCreator = function (creator) {
  1584. zrUtil.createCanvas = creator;
  1585. };
  1586. echarts.registerVisual(PRIORITY_VISUAL_GLOBAL, require('./visual/seriesColor'));
  1587. echarts.registerPreprocessor(require('./preprocessor/backwardCompat'));
  1588. echarts.registerLoading('default', require('./loading/default'));
  1589. // Default action
  1590. echarts.registerAction({
  1591. type: 'highlight',
  1592. event: 'highlight',
  1593. update: 'highlight'
  1594. }, zrUtil.noop);
  1595. echarts.registerAction({
  1596. type: 'downplay',
  1597. event: 'downplay',
  1598. update: 'downplay'
  1599. }, zrUtil.noop);
  1600. // --------
  1601. // Exports
  1602. // --------
  1603. //
  1604. echarts.List = require('./data/List');
  1605. echarts.Model = require('./model/Model');
  1606. echarts.graphic = require('./util/graphic');
  1607. echarts.number = require('./util/number');
  1608. echarts.format = require('./util/format');
  1609. echarts.throttle = throttle.throttle;
  1610. echarts.matrix = require('zrender/core/matrix');
  1611. echarts.vector = require('zrender/core/vector');
  1612. echarts.color = require('zrender/tool/color');
  1613. echarts.util = {};
  1614. each([
  1615. 'map', 'each', 'filter', 'indexOf', 'inherits', 'reduce', 'filter',
  1616. 'bind', 'curry', 'isArray', 'isString', 'isObject', 'isFunction',
  1617. 'extend', 'defaults', 'clone'
  1618. ],
  1619. function (name) {
  1620. echarts.util[name] = zrUtil[name];
  1621. }
  1622. );
  1623. // PRIORITY
  1624. echarts.PRIORITY = {
  1625. PROCESSOR: {
  1626. FILTER: PRIORITY_PROCESSOR_FILTER,
  1627. STATISTIC: PRIORITY_PROCESSOR_STATISTIC
  1628. },
  1629. VISUAL: {
  1630. LAYOUT: PRIORITY_VISUAL_LAYOUT,
  1631. GLOBAL: PRIORITY_VISUAL_GLOBAL,
  1632. CHART: PRIORITY_VISUAL_CHART,
  1633. COMPONENT: PRIORITY_VISUAL_COMPONENT,
  1634. BRUSH: PRIORITY_VISUAL_BRUSH
  1635. }
  1636. };
  1637. return echarts;
  1638. });