pie_chart.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /**
  2. * DevExtreme (viz/pie_chart.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. var _consts = require("./components/consts");
  11. var _utils = require("./core/utils");
  12. var _extend2 = require("../core/utils/extend");
  13. var _type = require("../core/utils/type");
  14. var _iterator = require("../core/utils/iterator");
  15. var _range = require("./translators/range");
  16. var _range2 = _interopRequireDefault(_range);
  17. var _component_registrator = require("../core/component_registrator");
  18. var _component_registrator2 = _interopRequireDefault(_component_registrator);
  19. var _base_chart = require("./chart_components/base_chart");
  20. var _common = require("../core/utils/common");
  21. var _translator1d = require("./translators/translator1d");
  22. var _translator1d2 = _interopRequireDefault(_translator1d);
  23. function _interopRequireDefault(obj) {
  24. return obj && obj.__esModule ? obj : {
  25. "default": obj
  26. }
  27. }
  28. var OPTIONS_FOR_REFRESH_SERIES = ["startAngle", "innerRadius", "segmentsDirection", "type"];
  29. var NORMAL_STATE = _consts.states.normalMark;
  30. var MAX_RESOLVE_ITERATION_COUNT = 5;
  31. var LEGEND_ACTIONS = [_consts.states.resetItem, _consts.states.applyHover, _consts.states.applySelected, _consts.states.applySelected];
  32. function getLegendItemAction(points) {
  33. var state = NORMAL_STATE;
  34. points.forEach(function(point) {
  35. state |= point.fullState
  36. });
  37. return LEGEND_ACTIONS[state]
  38. }
  39. function correctPercentValue(value) {
  40. if ((0, _type.isNumeric)(value)) {
  41. if (value > 1) {
  42. value = 1
  43. } else {
  44. if (value < 0) {
  45. value = 0
  46. }
  47. }
  48. } else {
  49. value = void 0
  50. }
  51. return value
  52. }
  53. var dxPieChart = _base_chart.BaseChart.inherit({
  54. _themeSection: "pie",
  55. _layoutManagerOptions: function() {
  56. return (0, _extend2.extend)(true, {}, this.callBase(), {
  57. piePercentage: correctPercentValue(this._themeManager.getOptions("diameter")),
  58. minPiePercentage: correctPercentValue(this._themeManager.getOptions("minDiameter"))
  59. })
  60. },
  61. _optionChangesMap: {
  62. diameter: "REINIT",
  63. minDiameter: "REINIT",
  64. sizeGroup: "REINIT"
  65. },
  66. _disposeCore: function() {
  67. pieSizeEqualizer.remove(this);
  68. this.callBase()
  69. },
  70. _groupSeries: function() {
  71. var series = this.series;
  72. this._groupsData = {
  73. groups: [{
  74. series: series,
  75. valueOptions: {
  76. valueType: "numeric"
  77. }
  78. }],
  79. argumentOptions: series[0] && series[0].getOptions()
  80. }
  81. },
  82. getArgumentAxis: function() {
  83. return null
  84. },
  85. _getValueAxis: function() {
  86. var translator = (new _translator1d2.default.Translator1D).setCodomain(360, 0);
  87. return {
  88. getTranslator: function() {
  89. return translator
  90. },
  91. setBusinessRange: function(range) {
  92. translator.setDomain(range.min, range.max)
  93. }
  94. }
  95. },
  96. _populateBusinessRange: function() {
  97. this.series.map(function(series) {
  98. var range = new _range2.default.Range;
  99. range.addRange(series.getRangeData().val);
  100. series.getValueAxis().setBusinessRange(range);
  101. return range
  102. })
  103. },
  104. _specialProcessSeries: function() {
  105. (0, _iterator.each)(this.series, function(_, singleSeries) {
  106. singleSeries.arrangePoints()
  107. })
  108. },
  109. _checkPaneName: function() {
  110. return true
  111. },
  112. _processSingleSeries: function(singleSeries) {
  113. this.callBase(singleSeries);
  114. singleSeries.arrangePoints()
  115. },
  116. _handleSeriesDataUpdated: function() {
  117. var maxPointCount = 0;
  118. this.series.forEach(function(s) {
  119. maxPointCount = Math.max(s.getPointsCount(), maxPointCount)
  120. });
  121. this.series.forEach(function(s) {
  122. s.setMaxPointsCount(maxPointCount)
  123. });
  124. this.callBase()
  125. },
  126. _getLegendOptions: function(item) {
  127. var legendItem = this.callBase(item);
  128. var legendData = legendItem.legendData;
  129. legendData.argument = item.argument;
  130. legendData.argumentIndex = item.argumentIndex;
  131. legendData.points = [item];
  132. return legendItem
  133. },
  134. _getLegendTargets: function() {
  135. var that = this;
  136. var itemsByArgument = {};
  137. (that.series || []).forEach(function(series) {
  138. series.getPoints().forEach(function(point) {
  139. var argument = point.argument.valueOf();
  140. var index = series.getPointsByArg(argument).indexOf(point);
  141. var key = argument.valueOf().toString() + index;
  142. itemsByArgument[key] = itemsByArgument[key] || [];
  143. var argumentCount = itemsByArgument[key].push(point);
  144. point.index = itemsByArgument[key][argumentCount - 2] ? itemsByArgument[key][argumentCount - 2].index : Object.keys(itemsByArgument).length - 1;
  145. point.argumentIndex = index
  146. })
  147. });
  148. var items = [];
  149. (0, _iterator.each)(itemsByArgument, function(_, points) {
  150. points.forEach(function(point, index) {
  151. if (0 === index) {
  152. items.push(that._getLegendOptions(point));
  153. return
  154. }
  155. var item = items[items.length - 1];
  156. item.legendData.points.push(point);
  157. if (!item.visible) {
  158. item.visible = point.isVisible()
  159. }
  160. })
  161. });
  162. return items
  163. },
  164. _getLayoutTargets: function() {
  165. return [{
  166. canvas: this._canvas
  167. }]
  168. },
  169. _getLayoutSeries: function(series, drawOptions) {
  170. var that = this;
  171. var layout;
  172. var canvas = that._canvas;
  173. var drawnLabels = false;
  174. layout = that.layoutManager.applyPieChartSeriesLayout(canvas, series, true);
  175. series.forEach(function(singleSeries) {
  176. singleSeries.correctPosition(layout, canvas);
  177. drawnLabels = singleSeries.drawLabelsWOPoints() || drawnLabels
  178. });
  179. if (drawnLabels) {
  180. layout = that.layoutManager.applyPieChartSeriesLayout(canvas, series, drawOptions.hideLayoutLabels)
  181. }
  182. series.forEach(function(singleSeries) {
  183. singleSeries.hideLabels()
  184. });
  185. that._sizeGroupLayout = {
  186. x: layout.centerX,
  187. y: layout.centerY,
  188. radius: layout.radiusOuter,
  189. drawOptions: drawOptions
  190. };
  191. return layout
  192. },
  193. _getLayoutSeriesForEqualPies: function(series, sizeGroupLayout) {
  194. var canvas = this._canvas;
  195. var layout = this.layoutManager.applyEqualPieChartLayout(series, sizeGroupLayout);
  196. series.forEach(function(s) {
  197. s.correctPosition(layout, canvas);
  198. s.drawLabelsWOPoints()
  199. });
  200. this.layoutManager.correctPieLabelRadius(series, layout, canvas);
  201. return layout
  202. },
  203. _updateSeriesDimensions: function(drawOptions) {
  204. var that = this;
  205. var visibleSeries = that._getVisibleSeries();
  206. var lengthVisibleSeries = visibleSeries.length;
  207. var innerRad;
  208. var delta;
  209. var layout;
  210. var sizeGroupLayout = drawOptions.sizeGroupLayout;
  211. if (lengthVisibleSeries) {
  212. layout = sizeGroupLayout ? that._getLayoutSeriesForEqualPies(visibleSeries, sizeGroupLayout) : that._getLayoutSeries(visibleSeries, drawOptions);
  213. delta = (layout.radiusOuter - layout.radiusInner - _consts.pieSeriesSpacing * (lengthVisibleSeries - 1)) / lengthVisibleSeries;
  214. innerRad = layout.radiusInner;
  215. that._setCenter({
  216. x: layout.centerX,
  217. y: layout.centerY
  218. });
  219. visibleSeries.forEach(function(singleSeries) {
  220. singleSeries.correctRadius({
  221. radiusInner: innerRad,
  222. radiusOuter: innerRad + delta
  223. });
  224. innerRad += delta + _consts.pieSeriesSpacing
  225. })
  226. }
  227. },
  228. _renderSeries: function(drawOptions, isRotated, isLegendInside) {
  229. this._calculateSeriesLayout(drawOptions, isRotated);
  230. if (!drawOptions.sizeGroupLayout && this.getSizeGroup()) {
  231. pieSizeEqualizer.queue(this);
  232. this._clearCanvas();
  233. return
  234. }
  235. this._renderSeriesElements(drawOptions, isRotated, isLegendInside)
  236. },
  237. _getLegendCallBack: function() {
  238. var that = this;
  239. var legend = this._legend;
  240. var items = this._getLegendTargets().map(function(i) {
  241. return i.legendData
  242. });
  243. return function(target) {
  244. items.forEach(function(data) {
  245. var points = [];
  246. var callback = legend.getActionCallback({
  247. index: data.id
  248. });
  249. that.series.forEach(function(series) {
  250. var seriesPoints = series.getPointsByKeys(data.argument, data.argumentIndex);
  251. points.push.apply(points, seriesPoints)
  252. });
  253. if (target && target.argument === data.argument && target.argumentIndex === data.argumentIndex) {
  254. points.push(target)
  255. }
  256. callback(getLegendItemAction(points))
  257. })
  258. }
  259. },
  260. _locateLabels: function(resolveLabelOverlapping) {
  261. var iterationCount = 0;
  262. var labelsWereOverlapped;
  263. var wordWrapApplied;
  264. do {
  265. labelsWereOverlapped = this._resolveLabelOverlapping(resolveLabelOverlapping);
  266. wordWrapApplied = this._adjustSeriesLabels("shift" === resolveLabelOverlapping)
  267. } while ((labelsWereOverlapped || wordWrapApplied) && ++iterationCount < MAX_RESOLVE_ITERATION_COUNT)
  268. },
  269. _adjustSeriesLabels: function(moveLabelsFromCenter) {
  270. return this.series.reduce(function(r, s) {
  271. return s.adjustLabels(moveLabelsFromCenter) || r
  272. }, false)
  273. },
  274. _prepareStackPoints: _common.noop,
  275. _resetStackPoints: _common.noop,
  276. _applyExtraSettings: _common.noop,
  277. _resolveLabelOverlappingShift: function() {
  278. var that = this;
  279. var inverseDirection = "anticlockwise" === that.option("segmentsDirection");
  280. var seriesByPosition = that.series.reduce(function(r, s) {
  281. (r[s.getOptions().label.position] || r.outside).push(s);
  282. return r
  283. }, {
  284. inside: [],
  285. columns: [],
  286. outside: []
  287. });
  288. var labelsOverlapped = false;
  289. if (seriesByPosition.inside.length > 0) {
  290. labelsOverlapped = resolve(seriesByPosition.inside.reduce(function(r, singleSeries) {
  291. return singleSeries.getVisiblePoints().reduce(function(r, point) {
  292. r.left.push(point);
  293. return r
  294. }, r)
  295. }, {
  296. left: [],
  297. right: []
  298. }), shiftInColumnFunction) || labelsOverlapped
  299. }
  300. labelsOverlapped = seriesByPosition.columns.reduce(function(r, singleSeries) {
  301. return resolve(dividePoints(singleSeries), shiftInColumnFunction) || r
  302. }, labelsOverlapped);
  303. if (seriesByPosition.outside.length > 0) {
  304. labelsOverlapped = resolve(seriesByPosition.outside.reduce(function(r, singleSeries) {
  305. return dividePoints(singleSeries, r)
  306. }, null), shiftFunction) || labelsOverlapped
  307. }
  308. return labelsOverlapped;
  309. function dividePoints(series, points) {
  310. return series.getVisiblePoints().reduce(function(r, point) {
  311. var angle = (0, _utils.normalizeAngle)(point.middleAngle);
  312. (angle <= 90 || angle >= 270 ? r.right : r.left).push(point);
  313. return r
  314. }, points || {
  315. left: [],
  316. right: []
  317. })
  318. }
  319. function resolve(points, shiftCallback) {
  320. var overlapped = false;
  321. if (inverseDirection) {
  322. points.left.reverse();
  323. points.right.reverse()
  324. }
  325. overlapped = _base_chart.overlapping.resolveLabelOverlappingInOneDirection(points.left, that._canvas, false, shiftCallback);
  326. return _base_chart.overlapping.resolveLabelOverlappingInOneDirection(points.right, that._canvas, false, shiftCallback) || overlapped
  327. }
  328. function shiftFunction(box, length) {
  329. return (0, _utils.getVerticallyShiftedAngularCoords)(box, -length, that._center)
  330. }
  331. function shiftInColumnFunction(box, length) {
  332. return {
  333. x: box.x,
  334. y: box.y - length
  335. }
  336. }
  337. },
  338. _setCenter: function(center) {
  339. this._center = center
  340. },
  341. _disposeSeries: function(seriesIndex) {
  342. this.callBase.apply(this, arguments);
  343. this._abstractSeries = null
  344. },
  345. _legendDataField: "point",
  346. _legendItemTextField: "argument",
  347. _applyPointMarkersAutoHiding: _common.noop,
  348. _renderTrackers: _common.noop,
  349. _trackerType: "PieTracker",
  350. _createScrollBar: _common.noop,
  351. _updateAxesLayout: _common.noop,
  352. _applyClipRects: _common.noop,
  353. _appendAdditionalSeriesGroups: _common.noop,
  354. _prepareToRender: _common.noop,
  355. _isLegendInside: _common.noop,
  356. _renderAxes: _common.noop,
  357. _shrinkAxes: _common.noop,
  358. _isRotated: _common.noop,
  359. _seriesPopulatedHandlerCore: _common.noop,
  360. _reinitAxes: _common.noop,
  361. _correctAxes: _common.noop,
  362. _getExtraOptions: function() {
  363. var that = this;
  364. return {
  365. startAngle: that.option("startAngle"),
  366. innerRadius: that.option("innerRadius"),
  367. segmentsDirection: that.option("segmentsDirection"),
  368. type: that.option("type")
  369. }
  370. },
  371. getSizeGroup: function() {
  372. return this._themeManager.getOptions("sizeGroup")
  373. },
  374. getSizeGroupLayout: function() {
  375. return this._sizeGroupLayout || {}
  376. }
  377. });
  378. (0, _iterator.each)(OPTIONS_FOR_REFRESH_SERIES, function(_, name) {
  379. dxPieChart.prototype._optionChangesMap[name] = "REFRESH_SERIES_DATA_INIT"
  380. });
  381. (0, _component_registrator2.default)("dxPieChart", dxPieChart);
  382. module.exports = dxPieChart;
  383. var pieSizeEqualizer = function() {
  384. function equalize(group, allPies) {
  385. var pies = allPies.filter(function(p) {
  386. return p._isVisible() && p.getSizeGroup() === group
  387. });
  388. var minRadius = Math.min.apply(null, pies.map(function(p) {
  389. return p.getSizeGroupLayout().radius
  390. }));
  391. var minPie = pies.filter(function(p) {
  392. return p.getSizeGroupLayout().radius === minRadius
  393. });
  394. pies.forEach(function(p) {
  395. return p.render({
  396. force: true,
  397. sizeGroupLayout: minPie.length ? minPie[0].getSizeGroupLayout() : {}
  398. })
  399. })
  400. }
  401. function removeFromList(list, item) {
  402. return list.filter(function(li) {
  403. return li !== item
  404. })
  405. }
  406. function addToList(list, item) {
  407. return removeFromList(list, item).concat(item)
  408. }
  409. var pies = [];
  410. var timers = {};
  411. return {
  412. queue: function(pie) {
  413. var group = pie.getSizeGroup();
  414. pies = addToList(pies, pie);
  415. clearTimeout(timers[group]);
  416. timers[group] = setTimeout(function() {
  417. equalize(group, pies)
  418. })
  419. },
  420. remove: function(pie) {
  421. pies = removeFromList(pies, pie);
  422. if (!pies.length) {
  423. timers = {}
  424. }
  425. }
  426. }
  427. }();
  428. module.exports.default = module.exports;