No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

echarts.js 60 KiB

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