funnel.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /**
  2. * DevExtreme (viz/funnel/funnel.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 tiling = require("./tiling");
  11. var dynamicSlope = require("./tiling.funnel");
  12. var dynamicHeight = require("./tiling.pyramid");
  13. var noop = require("../../core/utils/common").noop;
  14. var Item = require("./item");
  15. var NODES_CREATE_CHANGE = "NODES_CREATE";
  16. tiling.addAlgorithm("dynamicslope", dynamicSlope, true);
  17. tiling.addAlgorithm("dynamicheight", dynamicHeight);
  18. function invertFigure(figure) {
  19. return figure.map(function(coord, index) {
  20. return index % 2 ? 1 - coord : coord
  21. })
  22. }
  23. var dxFunnel = require("../core/base_widget").inherit({
  24. _rootClass: "dxf-funnel",
  25. _rootClassPrefix: "dxf",
  26. _proxyData: [],
  27. _optionChangesMap: {
  28. dataSource: "DATA_SOURCE",
  29. neckWidth: NODES_CREATE_CHANGE,
  30. neckHeight: NODES_CREATE_CHANGE,
  31. inverted: NODES_CREATE_CHANGE,
  32. algorithm: NODES_CREATE_CHANGE,
  33. item: NODES_CREATE_CHANGE,
  34. valueField: NODES_CREATE_CHANGE,
  35. argumentField: NODES_CREATE_CHANGE,
  36. colorField: NODES_CREATE_CHANGE,
  37. palette: NODES_CREATE_CHANGE,
  38. paletteExtensionMode: NODES_CREATE_CHANGE,
  39. sortData: NODES_CREATE_CHANGE
  40. },
  41. _themeDependentChanges: [NODES_CREATE_CHANGE],
  42. _getDefaultSize: function() {
  43. return {
  44. width: 400,
  45. height: 400
  46. }
  47. },
  48. _themeSection: "funnel",
  49. _fontFields: ["legend.title.font", "legend.title.subtitle.font", "legend.font"],
  50. _optionChangesOrder: ["DATA_SOURCE"],
  51. _initialChanges: ["DATA_SOURCE"],
  52. _initCore: function() {
  53. this._group = this._renderer.g().append(this._renderer.root);
  54. this._items = []
  55. },
  56. _eventsMap: {
  57. onHoverChanged: {
  58. name: "hoverChanged"
  59. },
  60. onSelectionChanged: {
  61. name: "selectionChanged"
  62. }
  63. },
  64. _disposeCore: noop,
  65. _applySize: function(rect) {
  66. this._rect = rect.slice();
  67. this._change(["TILING"]);
  68. return this._rect
  69. },
  70. _getAlignmentRect: function() {
  71. return this._rect
  72. },
  73. _change_TILING: function() {
  74. var that = this;
  75. var items = that._items;
  76. var rect = that._rect;
  77. var convertCoord = function(coord, index) {
  78. var offset = index % 2;
  79. return rect[0 + offset] + (rect[2 + offset] - rect[0 + offset]) * coord
  80. };
  81. this._group.clear();
  82. items.forEach(function(item, index) {
  83. var coords = item.figure.map(convertCoord);
  84. var element = that._renderer.path([], "area").attr({
  85. points: coords
  86. }).append(that._group);
  87. item.coords = coords;
  88. item.element = element
  89. });
  90. this._requestChange(["TILES"])
  91. },
  92. _customChangesOrder: [NODES_CREATE_CHANGE, "LAYOUT", "TILING", "TILES", "DRAWN"],
  93. _dataSourceChangedHandler: function() {
  94. this._requestChange([NODES_CREATE_CHANGE])
  95. },
  96. _change_DRAWN: function() {
  97. this._drawn()
  98. },
  99. _change_DATA_SOURCE: function() {
  100. this._change(["DRAWN"]);
  101. this._updateDataSource()
  102. },
  103. _change_NODES_CREATE: function() {
  104. this._buildNodes()
  105. },
  106. _change_TILES: function() {
  107. this._applyTilesAppearance()
  108. },
  109. _suspend: function() {
  110. if (!this._applyingChanges) {
  111. this._suspendChanges()
  112. }
  113. },
  114. _resume: function() {
  115. if (!this._applyingChanges) {
  116. this._resumeChanges()
  117. }
  118. },
  119. _applyTilesAppearance: function() {
  120. this._items.forEach(function(item) {
  121. var state = item.getState();
  122. item.element.smartAttr(item.states[state])
  123. })
  124. },
  125. _hitTestTargets: function(x, y) {
  126. var that = this;
  127. var data;
  128. this._proxyData.some(function(callback) {
  129. data = callback.call(that, x, y);
  130. if (data) {
  131. return true
  132. }
  133. });
  134. return data
  135. },
  136. clearHover: function() {
  137. this._suspend();
  138. this._items.forEach(function(item) {
  139. item.isHovered() && item.hover(false)
  140. });
  141. this._resume()
  142. },
  143. clearSelection: function() {
  144. this._suspend();
  145. this._items.forEach(function(item) {
  146. item.isSelected() && item.select(false)
  147. });
  148. this._resume()
  149. },
  150. _getData: function() {
  151. var that = this;
  152. var data = that._dataSourceItems() || [];
  153. var valueField = that._getOption("valueField", true);
  154. var argumentField = that._getOption("argumentField", true);
  155. var colorField = that._getOption("colorField", true);
  156. var processedData = data.reduce(function(d, item) {
  157. var value = Number(item[valueField]);
  158. if (value >= 0) {
  159. d[0].push({
  160. value: value,
  161. color: item[colorField],
  162. argument: item[argumentField],
  163. dataItem: item
  164. });
  165. d[1] += value
  166. }
  167. return d
  168. }, [
  169. [], 0
  170. ]);
  171. var items = processedData[0];
  172. if (!processedData[1]) {
  173. items = items.map(function(item) {
  174. item.value += 1;
  175. return item
  176. })
  177. }
  178. if (data.length > 0 && 0 === items.length) {
  179. that._incidentOccurred("E2005", valueField)
  180. }
  181. if (that._getOption("sortData", true)) {
  182. items.sort(function(a, b) {
  183. return b.value - a.value
  184. })
  185. }
  186. return items
  187. },
  188. _buildNodes: function() {
  189. var that = this;
  190. var data = that._getData();
  191. var algorithm = tiling.getAlgorithm(that._getOption("algorithm", true));
  192. var percents = algorithm.normalizeValues(data);
  193. var itemOptions = that._getOption("item");
  194. var figures = algorithm.getFigures(percents, that._getOption("neckWidth", true), that._getOption("neckHeight", true));
  195. var palette = that._themeManager.createPalette(that._getOption("palette", true), {
  196. useHighlight: true,
  197. extensionMode: that._getOption("paletteExtensionMode", true),
  198. count: figures.length
  199. });
  200. that._items = figures.map(function(figure, index) {
  201. var curData = data[index];
  202. var node = new Item(that, {
  203. figure: figure,
  204. data: curData,
  205. percent: percents[index],
  206. id: index,
  207. color: curData.color || palette.getNextColor(),
  208. itemOptions: itemOptions
  209. });
  210. return node
  211. });
  212. if (that._getOption("inverted", true)) {
  213. that._items.forEach(function(item) {
  214. item.figure = invertFigure(item.figure)
  215. })
  216. }
  217. that._renderer.initHatching();
  218. that._change(["TILING", "DRAWN"])
  219. },
  220. _showTooltip: noop,
  221. hideTooltip: noop,
  222. getAllItems: function() {
  223. return this._items.slice()
  224. },
  225. _getLegendData: function() {
  226. return this._items.map(function(item) {
  227. return {
  228. id: item.id,
  229. visible: true,
  230. text: item.argument,
  231. item: item,
  232. states: item.states
  233. }
  234. })
  235. },
  236. _getMinSize: function() {
  237. var adaptiveLayout = this._getOption("adaptiveLayout");
  238. return [adaptiveLayout.width, adaptiveLayout.height]
  239. }
  240. });
  241. require("../../core/component_registrator")("dxFunnel", dxFunnel);
  242. module.exports = dxFunnel;
  243. dxFunnel.addPlugin(require("../core/data_source").plugin);