chart.js 22 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. import { EVENT_AFTER_INIT, EVENT_BEFORE_RENDER, EVENT_AFTER_RENDER, EVENT_BEFORE_DATA_CHANGE, EVENT_AFTER_DATA_CHANGE, EVENT_AFTER_SIZE_CHANGE, EVENT_AFTER_GEOM_INIT, EVENT_BEFORE_GEOM_DRAW, EVENT_AFTER_GEOM_DRAW, EVENT_CLEAR, EVENT_CLEAR_INNER, EVENT_REPAINT } from './const';
  2. import Base from '../base';
  3. import Plot from './plot';
  4. import { each, isString, mix, upperFirst, parsePadding, lowerFirst, isObject, isArray } from '../util/common';
  5. import Coord from '../coord/index';
  6. import Geom from '../geom/base';
  7. import ScaleController from './controller/scale';
  8. import AxisController from './controller/axis';
  9. import Global from '../global';
  10. import { createCanvas } from '../graphic/index';
  11. import { getClip } from '../util/helper';
  12. function compare(a, b) {
  13. return a - b;
  14. }
  15. function _isScaleExist(scales, compareScale) {
  16. var flag = false;
  17. each(scales, function (scale) {
  18. var scaleValues = [].concat(scale.values);
  19. var compareScaleValues = [].concat(compareScale.values);
  20. if (scale.type === compareScale.type && scale.field === compareScale.field && scaleValues.sort(compare).toString() === compareScaleValues.sort(compare).toString()) {
  21. flag = true;
  22. return;
  23. }
  24. });
  25. return flag;
  26. }
  27. class Chart extends Base {
  28. static initPlugins() {
  29. return {
  30. _plugins: [],
  31. _cacheId: 0,
  32. register(plugins) {
  33. var p = this._plugins;
  34. [].concat(plugins).forEach(function (plugin) {
  35. if (p.indexOf(plugin) === -1) {
  36. p.push(plugin);
  37. }
  38. });
  39. this._cacheId++;
  40. },
  41. unregister(plugins) {
  42. var p = this._plugins;
  43. [].concat(plugins).forEach(function (plugin) {
  44. var idx = p.indexOf(plugin);
  45. if (idx !== -1) {
  46. p.splice(idx, 1);
  47. }
  48. });
  49. this._cacheId++;
  50. },
  51. clear() {
  52. this._plugins = [];
  53. this._cacheId++;
  54. },
  55. count() {
  56. return this._plugins.length;
  57. },
  58. getAll() {
  59. return this._plugins;
  60. },
  61. notify(chart, hook, args) {
  62. var descriptors = this.descriptors(chart);
  63. var ilen = descriptors.length;
  64. var i;
  65. var descriptor;
  66. var plugin;
  67. var params;
  68. var method;
  69. for (i = 0; i < ilen; ++i) {
  70. descriptor = descriptors[i];
  71. plugin = descriptor.plugin;
  72. method = plugin[hook];
  73. if (typeof method === 'function') {
  74. params = [chart].concat(args || []);
  75. if (method.apply(plugin, params) === false) {
  76. return false;
  77. }
  78. }
  79. }
  80. return true;
  81. },
  82. descriptors(chart) {
  83. var cache = chart._plugins || (chart._plugins = {});
  84. if (cache.id === this._cacheId) {
  85. return cache.descriptors;
  86. }
  87. var plugins = [];
  88. var descriptors = [];
  89. this._plugins.concat(chart && chart.get('plugins') || []).forEach(function (plugin) {
  90. var idx = plugins.indexOf(plugin);
  91. if (idx !== -1) {
  92. return;
  93. }
  94. plugins.push(plugin);
  95. descriptors.push({
  96. plugin
  97. });
  98. });
  99. cache.descriptors = descriptors;
  100. cache.id = this._cacheId;
  101. return descriptors;
  102. }
  103. };
  104. }
  105. getDefaultCfg() {
  106. return {
  107. /**
  108. * the id of canvas
  109. * @type {String}
  110. */
  111. id: null,
  112. /** 图表渲染引擎 */
  113. renderer: 'canvas',
  114. rendered: false,
  115. /**
  116. * padding
  117. * @type {Array|Number}
  118. */
  119. padding: Global.padding,
  120. /**
  121. * data
  122. * @type {Array}
  123. */
  124. data: null,
  125. /**
  126. * scales of chart
  127. * @type {Object}
  128. */
  129. scales: {},
  130. /**
  131. * @private
  132. * geometry instances
  133. * @type {Array}
  134. */
  135. geoms: [],
  136. /**
  137. * scale configuration
  138. * @type {Object}
  139. */
  140. colDefs: null,
  141. pixelRatio: Global.pixelRatio,
  142. /**
  143. * filter options
  144. * @type {Object}
  145. */
  146. filters: null,
  147. appendPadding: Global.appendPadding
  148. };
  149. }
  150. _syncYScales() {
  151. var syncY = this.get('syncY');
  152. if (!syncY) {
  153. return;
  154. }
  155. var geoms = this.get('geoms');
  156. var syncScales = [];
  157. var min = [];
  158. var max = [];
  159. each(geoms, function (geom) {
  160. var yScale = geom.getYScale();
  161. if (yScale.isLinear) {
  162. syncScales.push(yScale);
  163. min.push(yScale.min);
  164. max.push(yScale.max);
  165. }
  166. });
  167. min = Math.min.apply(null, min);
  168. max = Math.max.apply(null, max);
  169. each(syncScales, function (scale) {
  170. scale.change({
  171. min
  172. });
  173. scale.change({
  174. max
  175. });
  176. });
  177. }
  178. _getFieldsForLegend() {
  179. var fields = [];
  180. var geoms = this.get('geoms');
  181. each(geoms, function (geom) {
  182. var attrOptions = geom.get('attrOptions');
  183. var attrCfg = attrOptions.color;
  184. if (attrCfg && attrCfg.field && isString(attrCfg.field)) {
  185. var arr = attrCfg.field.split('*');
  186. each(arr, function (item) {
  187. if (fields.indexOf(item) === -1) {
  188. fields.push(item);
  189. }
  190. });
  191. }
  192. });
  193. return fields;
  194. }
  195. _getScaleData(field) {
  196. var data = this.get('data');
  197. var filteredData = this.get('filteredData');
  198. if (filteredData.length) {
  199. var legendFields = this._getFieldsForLegend();
  200. if (legendFields.indexOf(field) === -1) {
  201. data = filteredData;
  202. }
  203. }
  204. return data;
  205. } // _updateScales() {
  206. // const scaleController = this.get('scaleController');
  207. // scaleController.updateScales();
  208. // this._adjustScale();
  209. // }
  210. _adjustScale() {
  211. var self = this;
  212. var scaleController = self.get('scaleController'); // 看起来是为了让柱状图最小或最大都默认从0开始
  213. var geoms = this.get('geoms');
  214. for (var i = 0; i < geoms.length; i++) {
  215. var geom = geoms[i];
  216. if (geom.get('type') === 'interval') {
  217. var yScale = geom.getYScale();
  218. scaleController.adjustStartZero(yScale);
  219. }
  220. }
  221. }
  222. _removeGeoms() {
  223. var geoms = this.get('geoms');
  224. while (geoms.length > 0) {
  225. var geom = geoms.shift();
  226. geom.destroy();
  227. }
  228. }
  229. _clearGeoms() {
  230. var geoms = this.get('geoms');
  231. for (var i = 0, length = geoms.length; i < length; i++) {
  232. var geom = geoms[i];
  233. geom.clear();
  234. }
  235. }
  236. _clearInner() {
  237. this._clearGeoms();
  238. Chart.plugins.notify(this, 'clearInner');
  239. this.emit(EVENT_CLEAR_INNER);
  240. this.get('axisController') && this.get('axisController').clear();
  241. }
  242. _initFilteredData() {
  243. var filters = this.get('filters');
  244. var data = this.get('data') || [];
  245. if (filters) {
  246. data = data.filter(function (obj) {
  247. var rst = true;
  248. each(filters, function (fn, k) {
  249. if (fn) {
  250. rst = fn(obj[k], obj);
  251. if (!rst) {
  252. return false;
  253. }
  254. }
  255. });
  256. return rst;
  257. });
  258. }
  259. this.set('filteredData', data);
  260. }
  261. _changeGeomsData() {
  262. var geoms = this.get('geoms');
  263. var data = this.get('filteredData');
  264. for (var i = 0, length = geoms.length; i < length; i++) {
  265. var geom = geoms[i];
  266. geom.changeData(data);
  267. }
  268. }
  269. _initGeom(geom) {
  270. if (geom.get('isInit')) {
  271. return;
  272. }
  273. var coord = this.get('coord');
  274. var data = this.get('filteredData');
  275. var colDefs = this.get('colDefs');
  276. var middlePlot = this.get('middlePlot');
  277. geom.set('chart', this);
  278. geom.set('container', middlePlot.addGroup());
  279. geom.set('data', data);
  280. geom.set('coord', coord);
  281. geom.set('colDefs', colDefs);
  282. geom.init();
  283. this.emit(EVENT_AFTER_GEOM_INIT, geom);
  284. }
  285. _initGeoms() {
  286. var geoms = this.get('geoms');
  287. for (var i = 0, length = geoms.length; i < length; i++) {
  288. this._initGeom(geoms[i]);
  289. }
  290. }
  291. _initCoord() {
  292. var plot = this.get('plotRange');
  293. var coordCfg = mix({
  294. type: 'cartesian'
  295. }, this.get('coordCfg'), {
  296. plot
  297. });
  298. var type = coordCfg.type;
  299. var C = Coord[upperFirst(type)];
  300. var coord = new C(coordCfg);
  301. this.set('coord', coord);
  302. }
  303. _initLayout() {
  304. var padding = this.get('_padding');
  305. if (!padding) {
  306. padding = this.get('margin') || this.get('padding');
  307. padding = parsePadding(padding);
  308. }
  309. var top = padding[0] === 'auto' ? 0 : padding[0];
  310. var right = padding[1] === 'auto' ? 0 : padding[1];
  311. var bottom = padding[2] === 'auto' ? 0 : padding[2];
  312. var left = padding[3] === 'auto' ? 0 : padding[3];
  313. var width = this.get('width');
  314. var height = this.get('height');
  315. var start = {
  316. x: left,
  317. y: top
  318. };
  319. var end = {
  320. x: width - right,
  321. y: height - bottom
  322. };
  323. var plot = this.get('plot');
  324. if (plot) {
  325. plot.reset(start, end);
  326. return;
  327. }
  328. var newPlot = new Plot({
  329. start,
  330. end
  331. });
  332. this.set('plotRange', newPlot);
  333. this.set('plot', newPlot);
  334. }
  335. _initCanvas() {
  336. var self = this;
  337. try {
  338. var canvas = createCanvas({
  339. renderer: self.get('renderer'),
  340. el: self.get('el') || self.get('id'),
  341. context: self.get('context'),
  342. pixelRatio: self.get('pixelRatio'),
  343. width: self.get('width'),
  344. height: self.get('height'),
  345. fontFamily: Global.fontFamily,
  346. aria: self.get('aria'),
  347. title: self.get('title'),
  348. landscape: self.get('landscape')
  349. });
  350. self.set('canvas', canvas);
  351. self.set('el', canvas.get('el'));
  352. self.set('width', canvas.get('width'));
  353. self.set('height', canvas.get('height'));
  354. } catch (error) {
  355. throw error;
  356. }
  357. Chart.plugins.notify(self, 'afterCanvasInit');
  358. }
  359. _initLayers() {
  360. var canvas = this.get('canvas');
  361. this.set('backPlot', canvas.addGroup());
  362. this.set('middlePlot', canvas.addGroup({
  363. zIndex: 10
  364. }));
  365. this.set('frontPlot', canvas.addGroup({
  366. zIndex: 20
  367. }));
  368. }
  369. _initEvents() {
  370. var _this = this;
  371. // 数据更新后的一些更新
  372. this.on(EVENT_AFTER_DATA_CHANGE, function () {
  373. // 数据更新后,重新设置filterdata
  374. _this._initFilteredData(); // 更新geoms里的数据
  375. _this._changeGeomsData();
  376. }); // 大小变化后的一些更新
  377. this.on(EVENT_AFTER_SIZE_CHANGE, function () {
  378. _this._initLayout(); // layout变化后,坐标轴也需要做相应的变化
  379. var coord = _this.get('coord');
  380. if (coord) {
  381. coord.reset(_this.get('plot'));
  382. }
  383. });
  384. }
  385. _initScaleController() {
  386. var scaleController = new ScaleController({
  387. chart: this
  388. }); // 让colDefs 和 scaleController.defs 用同一个对象,这样就不用考虑同步的问题
  389. this.set('colDefs', scaleController.defs); // 已经实例化的scales 也保持统一个对象
  390. this.set('scales', scaleController.scales);
  391. this.set('scaleController', scaleController);
  392. }
  393. _clearScaleController() {
  394. var scaleController = this.get('scaleController');
  395. scaleController.clear();
  396. }
  397. _init() {
  398. var self = this;
  399. self._initCanvas();
  400. self._initLayout();
  401. self._initLayers();
  402. self._initEvents();
  403. self._initScaleController();
  404. self.set('axisController', new AxisController({
  405. frontPlot: self.get('frontPlot').addGroup({
  406. className: 'axisContainer'
  407. }),
  408. backPlot: self.get('backPlot').addGroup({
  409. className: 'axisContainer'
  410. }),
  411. chart: self
  412. }));
  413. Chart.plugins.notify(self, 'init');
  414. }
  415. constructor(cfg) {
  416. super(cfg);
  417. var self = this;
  418. each(Geom, function (geomConstructor, className) {
  419. var methodName = lowerFirst(className);
  420. self[methodName] = function (cfg) {
  421. var geom = new geomConstructor(cfg);
  422. self.addGeom(geom);
  423. return geom;
  424. };
  425. });
  426. self._init();
  427. }
  428. init() {
  429. // 初始filterData
  430. this._initFilteredData(); // initialization coordinate instance
  431. this._initCoord();
  432. Chart.plugins.notify(this, 'beforeGeomInit'); // init all geometry instances
  433. this._initGeoms(); // 多 Y 轴的情况时,统一 Y 轴的数值范围。
  434. this._syncYScales(); // do some adjust for data
  435. this._adjustScale();
  436. this.emit(EVENT_AFTER_INIT);
  437. }
  438. /**
  439. * set data and some scale configuration
  440. * @chainable
  441. * @param {Array} data the dataset to visualize
  442. * @param {Object} colDefs the configuration for scales
  443. * @return {Chart} return the chart instance
  444. */
  445. source(data, colDefs) {
  446. this.set('data', data);
  447. if (colDefs) {
  448. this.scale(colDefs);
  449. }
  450. return this;
  451. }
  452. scale(field, cfg) {
  453. var scaleController = this.get('scaleController');
  454. scaleController.setFieldDef(field, cfg);
  455. return this;
  456. }
  457. /**
  458. * configure the axis
  459. * @chainable
  460. * @param {String|Boolean} field the field name of data
  461. * @param {Object} cfg configuration for axis
  462. * @return {Chart} return the chart instance
  463. */
  464. axis(field, cfg) {
  465. var axisController = this.get('axisController');
  466. if (!field) {
  467. axisController.axisCfg = null;
  468. } else {
  469. axisController.axisCfg = axisController.axisCfg || {};
  470. axisController.axisCfg[field] = cfg;
  471. }
  472. return this;
  473. }
  474. /**
  475. * configure the coordinate
  476. * @chainable
  477. * @param {String} type set the type of coodinate
  478. * @param {Object} cfg configuration for coordinate
  479. * @return {Chart} return the chart instance
  480. */
  481. coord(type, cfg) {
  482. var coordCfg;
  483. if (isObject(type)) {
  484. coordCfg = type;
  485. } else {
  486. coordCfg = cfg || {};
  487. coordCfg.type = type || 'cartesian';
  488. }
  489. this.set('coordCfg', coordCfg);
  490. return this;
  491. }
  492. filter(field, condition) {
  493. var filters = this.get('filters') || {};
  494. filters[field] = condition;
  495. this.set('filters', filters); // 如果已经render过,则再重新触发一次change
  496. if (this.get('rendered')) {
  497. this.emit(EVENT_AFTER_DATA_CHANGE, this.get('data'));
  498. }
  499. }
  500. /**
  501. * render the chart
  502. * @chainable
  503. * @return {Chart} return the chart instance
  504. */
  505. render() {
  506. var rendered = this.get('rendered');
  507. var canvas = this.get('canvas');
  508. var geoms = this.get('geoms'); // 已经渲染过
  509. if (rendered) {
  510. this._initGeoms();
  511. this._adjustScale();
  512. } else {
  513. this.init();
  514. this.set('rendered', true);
  515. }
  516. this.emit(EVENT_BEFORE_RENDER);
  517. Chart.plugins.notify(this, 'beforeGeomDraw');
  518. this._renderAxis();
  519. var middlePlot = this.get('middlePlot');
  520. if (this.get('limitInPlot') && !middlePlot.attr('clip')) {
  521. var coord = this.get('coord');
  522. var clip = getClip(coord);
  523. clip.set('canvas', middlePlot.get('canvas'));
  524. middlePlot.attr('clip', clip);
  525. }
  526. this.emit(EVENT_BEFORE_GEOM_DRAW);
  527. for (var i = 0, length = geoms.length; i < length; i++) {
  528. var geom = geoms[i];
  529. geom.paint();
  530. }
  531. this.emit(EVENT_AFTER_GEOM_DRAW);
  532. Chart.plugins.notify(this, 'afterGeomDraw');
  533. canvas.sort();
  534. this.get('frontPlot').sort();
  535. Chart.plugins.notify(this, 'beforeCanvasDraw');
  536. canvas.draw();
  537. this.emit(EVENT_AFTER_RENDER);
  538. return this;
  539. }
  540. /**
  541. * clear the chart, include geometris and all the shapes
  542. * @chainable
  543. * @return {Chart} return the chart
  544. */
  545. clear() {
  546. Chart.plugins.notify(this, 'clear');
  547. this.emit(EVENT_CLEAR);
  548. this._clearInner();
  549. this._removeGeoms();
  550. this._clearScaleController();
  551. this.set('legendItems', null);
  552. this.set('filters', null);
  553. this.set('isUpdate', false);
  554. this.set('_padding', null);
  555. this.set('rendered', false);
  556. var canvas = this.get('canvas');
  557. canvas.draw();
  558. return this;
  559. }
  560. repaint() {
  561. // 如果在没有render之前就repaint的,就直接return退出
  562. var rendered = this.get('rendered');
  563. if (!rendered) {
  564. return;
  565. }
  566. this.set('isUpdate', true);
  567. this.set('legendItems', null);
  568. Chart.plugins.notify(this, 'repaint');
  569. this._clearInner();
  570. this.emit(EVENT_REPAINT);
  571. this.render();
  572. }
  573. changeData(data) {
  574. this.emit(EVENT_BEFORE_DATA_CHANGE, data);
  575. this.set('data', data);
  576. Chart.plugins.notify(this, 'changeData');
  577. this.emit(EVENT_AFTER_DATA_CHANGE, data);
  578. this.set('_padding', null);
  579. this.repaint();
  580. }
  581. changeSize(width, height) {
  582. if (width) {
  583. this.set('width', width);
  584. } else {
  585. width = this.get('width');
  586. }
  587. if (height) {
  588. this.set('height', height);
  589. } else {
  590. height = this.get('height');
  591. }
  592. var canvas = this.get('canvas');
  593. canvas.changeSize(width, height);
  594. this.emit(EVENT_AFTER_SIZE_CHANGE, {
  595. width,
  596. height
  597. });
  598. this.repaint();
  599. return this;
  600. }
  601. destroy() {
  602. this.clear();
  603. var canvas = this.get('canvas');
  604. canvas.destroy();
  605. Chart.plugins.notify(this, 'afterCanvasDestroyed');
  606. if (this._interactions) {
  607. each(this._interactions, function (interaction) {
  608. interaction.destroy();
  609. });
  610. }
  611. super.destroy();
  612. }
  613. /**
  614. * calculate dataset's position on canvas
  615. * @param {Object} record the dataset
  616. * @return {Object} return the position
  617. */
  618. getPosition(record) {
  619. var self = this;
  620. var coord = self.get('coord');
  621. var xScale = self.getXScale();
  622. var xField = xScale.field;
  623. var yScales = self.getYScales(); // default first
  624. var yScale = yScales[0];
  625. var yField = yScale.field;
  626. for (var i = 0, len = yScales.length; i < len; i++) {
  627. var scale = yScales[i];
  628. var field = scale.field;
  629. if (record[field]) {
  630. yScale = scale;
  631. yField = field;
  632. break;
  633. }
  634. }
  635. var x = xScale.scale(record[xField]);
  636. var y = yScale.scale(record[yField]);
  637. return coord.convertPoint({
  638. x,
  639. y
  640. });
  641. }
  642. /**
  643. * get the data item of the point
  644. * @param {Object} point canvas position
  645. * @return {Object} return the data item
  646. */
  647. getRecord(point) {
  648. var self = this;
  649. var coord = self.get('coord');
  650. var xScale = self.getXScale();
  651. var yScale = self.getYScales()[0];
  652. var invertPoint = coord.invertPoint(point);
  653. var record = {};
  654. record[xScale.field] = xScale.invert(invertPoint.x);
  655. record[yScale.field] = yScale.invert(invertPoint.y);
  656. return record;
  657. }
  658. /**
  659. * get the dataset of the point
  660. * @param {Object} point canvas position
  661. * @return {Array} return the dataset
  662. **/
  663. getSnapRecords(point) {
  664. var geom = this.get('geoms')[0];
  665. var data = [];
  666. if (geom) {
  667. // need to judge
  668. data = geom.getSnapRecords(point);
  669. }
  670. return data;
  671. }
  672. /**
  673. * creat scale instances
  674. * @param {String} field field name of data
  675. * @return {Scale} return the scale
  676. */
  677. createScale(field) {
  678. var data = this._getScaleData(field);
  679. var scaleController = this.get('scaleController');
  680. return scaleController.createScale(field, data);
  681. }
  682. /**
  683. * @protected
  684. * add geometry instance to geoms
  685. * @param {Geom} geom geometry instance
  686. */
  687. addGeom(geom) {
  688. var geoms = this.get('geoms');
  689. geoms.push(geom);
  690. }
  691. /**
  692. * get the scale of x axis
  693. * @return {Scale} return the scale
  694. */
  695. getXScale() {
  696. var self = this;
  697. var geoms = self.get('geoms');
  698. var xScale = geoms[0].getXScale();
  699. return xScale;
  700. }
  701. /**
  702. * get the scale of y axis
  703. * @return {Array} return the scale
  704. */
  705. getYScales() {
  706. var geoms = this.get('geoms');
  707. var rst = [];
  708. each(geoms, function (geom) {
  709. var yScale = geom.getYScale();
  710. if (rst.indexOf(yScale) === -1) {
  711. rst.push(yScale);
  712. }
  713. });
  714. return rst;
  715. }
  716. getLegendItems() {
  717. if (this.get('legendItems')) {
  718. return this.get('legendItems');
  719. }
  720. var legendItems = {};
  721. var scales = [];
  722. var geoms = this.get('geoms');
  723. each(geoms, function (geom) {
  724. var colorAttr = geom.getAttr('color');
  725. if (colorAttr) {
  726. var scale = colorAttr.getScale('color'); // 只支持分类图例
  727. if (scale.isCategory && !_isScaleExist(scales, scale)) {
  728. scales.push(scale);
  729. var field = scale.field;
  730. var ticks = scale.getTicks();
  731. var items = [];
  732. each(ticks, function (tick) {
  733. var text = tick.text;
  734. var name = text;
  735. var scaleValue = tick.value;
  736. var value = scale.invert(scaleValue);
  737. var color = colorAttr.mapping(value).join('') || Global.defaultColor;
  738. var marker = {
  739. fill: color,
  740. radius: 3,
  741. symbol: 'circle',
  742. stroke: '#fff'
  743. };
  744. items.push({
  745. name,
  746. // for display
  747. dataValue: value,
  748. // the origin value
  749. checked: true,
  750. marker
  751. });
  752. });
  753. legendItems[field] = items;
  754. }
  755. }
  756. });
  757. this.set('legendItems', legendItems);
  758. return legendItems;
  759. } // register the plugins
  760. registerPlugins(plugins) {
  761. var self = this;
  762. var chartPlugins = self.get('plugins') || [];
  763. if (!isArray(chartPlugins)) {
  764. chartPlugins = [chartPlugins];
  765. }
  766. [].concat(plugins).forEach(function (plugin) {
  767. if (chartPlugins.indexOf(plugin) === -1) {
  768. plugin.init && plugin.init(self); // init
  769. chartPlugins.push(plugin);
  770. }
  771. });
  772. Chart.plugins._cacheId++;
  773. self.set('plugins', chartPlugins);
  774. }
  775. _renderAxis() {
  776. var axisController = this.get('axisController');
  777. var xScale = this.getXScale();
  778. var yScales = this.getYScales();
  779. var coord = this.get('coord');
  780. Chart.plugins.notify(this, 'beforeRenderAxis');
  781. axisController.createAxis(coord, xScale, yScales);
  782. }
  783. _isAutoPadding() {
  784. if (this.get('_padding')) {
  785. return false;
  786. }
  787. var padding = this.get('padding');
  788. if (isArray(padding)) {
  789. return padding.indexOf('auto') !== -1;
  790. }
  791. return padding === 'auto';
  792. }
  793. _updateLayout(padding) {
  794. var width = this.get('width');
  795. var height = this.get('height');
  796. var start = {
  797. x: padding[3],
  798. y: padding[0]
  799. };
  800. var end = {
  801. x: width - padding[1],
  802. y: height - padding[2]
  803. };
  804. var plot = this.get('plot');
  805. var coord = this.get('coord');
  806. plot.reset(start, end);
  807. coord.reset(plot);
  808. }
  809. /**
  810. * 是否为横屏展示
  811. *
  812. * @param {Boolean} landscape 是否为横屏
  813. */
  814. landscape(landscape) {
  815. var canvas = this.get('canvas');
  816. canvas.set('landscape', landscape);
  817. }
  818. }
  819. Chart.plugins = Chart.initPlugins();
  820. export default Chart;