TreeGridAxis.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. /* *
  2. *
  3. * (c) 2016 Highsoft AS
  4. * Authors: Jon Arild Nygard
  5. *
  6. * License: www.highcharts.com/license
  7. *
  8. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  9. *
  10. * */
  11. 'use strict';
  12. import Axis from '../parts/Axis.js';
  13. import Tick from '../parts/Tick.js';
  14. import Tree from './Tree.js';
  15. import TreeGridTick from './TreeGridTick.js';
  16. import TreeSeriesMixin from '../mixins/tree-series.js';
  17. import U from '../parts/Utilities.js';
  18. var addEvent = U.addEvent, find = U.find, fireEvent = U.fireEvent, isNumber = U.isNumber, isObject = U.isObject, isString = U.isString, merge = U.merge, pick = U.pick, wrap = U.wrap;
  19. import './GridAxis.js';
  20. import '../modules/broken-axis.src.js';
  21. /**
  22. * @private
  23. */
  24. var TreeGridAxis;
  25. (function (TreeGridAxis) {
  26. /* *
  27. *
  28. * Interfaces
  29. *
  30. * */
  31. /* *
  32. *
  33. * Variables
  34. *
  35. * */
  36. var applied = false;
  37. /* *
  38. *
  39. * Functions
  40. *
  41. * */
  42. /**
  43. * @private
  44. */
  45. function compose(AxisClass) {
  46. if (!applied) {
  47. wrap(AxisClass.prototype, 'generateTick', wrapGenerateTick);
  48. wrap(AxisClass.prototype, 'getMaxLabelDimensions', wrapGetMaxLabelDimensions);
  49. wrap(AxisClass.prototype, 'init', wrapInit);
  50. wrap(AxisClass.prototype, 'setTickInterval', wrapSetTickInterval);
  51. TreeGridTick.compose(Tick);
  52. applied = true;
  53. }
  54. }
  55. TreeGridAxis.compose = compose;
  56. /**
  57. * @private
  58. */
  59. function getBreakFromNode(node, max) {
  60. var from = node.collapseStart || 0, to = node.collapseEnd || 0;
  61. // In broken-axis, the axis.max is minimized until it is not within a
  62. // break. Therefore, if break.to is larger than axis.max, the axis.to
  63. // should not add the 0.5 axis.tickMarkOffset, to avoid adding a break
  64. // larger than axis.max.
  65. // TODO consider simplifying broken-axis and this might solve itself
  66. if (to >= max) {
  67. from -= 0.5;
  68. }
  69. return {
  70. from: from,
  71. to: to,
  72. showPoints: false
  73. };
  74. }
  75. /**
  76. * Creates a tree structure of the data, and the treegrid. Calculates
  77. * categories, and y-values of points based on the tree.
  78. *
  79. * @private
  80. * @function getTreeGridFromData
  81. *
  82. * @param {Array<Highcharts.GanttPointOptions>} data
  83. * All the data points to display in the axis.
  84. *
  85. * @param {boolean} uniqueNames
  86. * Wether or not the data node with the same name should share grid cell. If
  87. * true they do share cell. False by default.
  88. *
  89. * @param {number} numberOfSeries
  90. *
  91. * @return {object}
  92. * Returns an object containing categories, mapOfIdToNode,
  93. * mapOfPosToGridNode, and tree.
  94. *
  95. * @todo There should be only one point per line.
  96. * @todo It should be optional to have one category per point, or merge
  97. * cells
  98. * @todo Add unit-tests.
  99. */
  100. function getTreeGridFromData(data, uniqueNames, numberOfSeries) {
  101. var categories = [], collapsedNodes = [], mapOfIdToNode = {}, mapOfPosToGridNode = {}, posIterator = -1, uniqueNamesEnabled = typeof uniqueNames === 'boolean' ? uniqueNames : false, tree;
  102. // Build the tree from the series data.
  103. var treeParams = {
  104. // After the children has been created.
  105. after: function (node) {
  106. var gridNode = mapOfPosToGridNode[node.pos], height = 0, descendants = 0;
  107. gridNode.children.forEach(function (child) {
  108. descendants += (child.descendants || 0) + 1;
  109. height = Math.max((child.height || 0) + 1, height);
  110. });
  111. gridNode.descendants = descendants;
  112. gridNode.height = height;
  113. if (gridNode.collapsed) {
  114. collapsedNodes.push(gridNode);
  115. }
  116. },
  117. // Before the children has been created.
  118. before: function (node) {
  119. var data = isObject(node.data, true) ? node.data : {}, name = isString(data.name) ? data.name : '', parentNode = mapOfIdToNode[node.parent], parentGridNode = (isObject(parentNode, true) ?
  120. mapOfPosToGridNode[parentNode.pos] :
  121. null), hasSameName = function (x) {
  122. return x.name === name;
  123. }, gridNode, pos;
  124. // If not unique names, look for sibling node with the same name
  125. if (uniqueNamesEnabled &&
  126. isObject(parentGridNode, true) &&
  127. !!(gridNode = find(parentGridNode.children, hasSameName))) {
  128. // If there is a gridNode with the same name, reuse position
  129. pos = gridNode.pos;
  130. // Add data node to list of nodes in the grid node.
  131. gridNode.nodes.push(node);
  132. }
  133. else {
  134. // If it is a new grid node, increment position.
  135. pos = posIterator++;
  136. }
  137. // Add new grid node to map.
  138. if (!mapOfPosToGridNode[pos]) {
  139. mapOfPosToGridNode[pos] = gridNode = {
  140. depth: parentGridNode ? parentGridNode.depth + 1 : 0,
  141. name: name,
  142. nodes: [node],
  143. children: [],
  144. pos: pos
  145. };
  146. // If not root, then add name to categories.
  147. if (pos !== -1) {
  148. categories.push(name);
  149. }
  150. // Add name to list of children.
  151. if (isObject(parentGridNode, true)) {
  152. parentGridNode.children.push(gridNode);
  153. }
  154. }
  155. // Add data node to map
  156. if (isString(node.id)) {
  157. mapOfIdToNode[node.id] = node;
  158. }
  159. // If one of the points are collapsed, then start the grid node
  160. // in collapsed state.
  161. if (gridNode &&
  162. data.collapsed === true) {
  163. gridNode.collapsed = true;
  164. }
  165. // Assign pos to data node
  166. node.pos = pos;
  167. }
  168. };
  169. var updateYValuesAndTickPos = function (map, numberOfSeries) {
  170. var setValues = function (gridNode, start, result) {
  171. var nodes = gridNode.nodes, end = start + (start === -1 ? 0 : numberOfSeries - 1), diff = (end - start) / 2, padding = 0.5, pos = start + diff;
  172. nodes.forEach(function (node) {
  173. var data = node.data;
  174. if (isObject(data, true)) {
  175. // Update point
  176. data.y = start + (data.seriesIndex || 0);
  177. // Remove the property once used
  178. delete data.seriesIndex;
  179. }
  180. node.pos = pos;
  181. });
  182. result[pos] = gridNode;
  183. gridNode.pos = pos;
  184. gridNode.tickmarkOffset = diff + padding;
  185. gridNode.collapseStart = end + padding;
  186. gridNode.children.forEach(function (child) {
  187. setValues(child, end + 1, result);
  188. end = (child.collapseEnd || 0) - padding;
  189. });
  190. // Set collapseEnd to the end of the last child node.
  191. gridNode.collapseEnd = end + padding;
  192. return result;
  193. };
  194. return setValues(map['-1'], -1, {});
  195. };
  196. // Create tree from data
  197. tree = Tree.getTree(data, treeParams);
  198. // Update y values of data, and set calculate tick positions.
  199. mapOfPosToGridNode = updateYValuesAndTickPos(mapOfPosToGridNode, numberOfSeries);
  200. // Return the resulting data.
  201. return {
  202. categories: categories,
  203. mapOfIdToNode: mapOfIdToNode,
  204. mapOfPosToGridNode: mapOfPosToGridNode,
  205. collapsedNodes: collapsedNodes,
  206. tree: tree
  207. };
  208. }
  209. /**
  210. * Builds the tree of categories and calculates its positions.
  211. * @private
  212. * @param {object} e Event object
  213. * @param {object} e.target The chart instance which the event was fired on.
  214. * @param {object[]} e.target.axes The axes of the chart.
  215. */
  216. function onBeforeRender(e) {
  217. var chart = e.target, axes = chart.axes;
  218. axes.filter(function (axis) {
  219. return axis.options.type === 'treegrid';
  220. }).forEach(function (axis) {
  221. var options = axis.options || {}, labelOptions = options.labels, uniqueNames = options.uniqueNames, numberOfSeries = 0, isDirty, data, treeGrid;
  222. // Check whether any of series is rendering for the first time,
  223. // visibility has changed, or its data is dirty,
  224. // and only then update. #10570, #10580
  225. // Also check if mapOfPosToGridNode exists. #10887
  226. isDirty = (!axis.treeGrid.mapOfPosToGridNode ||
  227. axis.series.some(function (series) {
  228. return !series.hasRendered ||
  229. series.isDirtyData ||
  230. series.isDirty;
  231. }));
  232. if (isDirty) {
  233. // Concatenate data from all series assigned to this axis.
  234. data = axis.series.reduce(function (arr, s) {
  235. if (s.visible) {
  236. // Push all data to array
  237. (s.options.data || []).forEach(function (data) {
  238. if (isObject(data, true)) {
  239. // Set series index on data. Removed again
  240. // after use.
  241. data.seriesIndex = numberOfSeries;
  242. arr.push(data);
  243. }
  244. });
  245. // Increment series index
  246. if (uniqueNames === true) {
  247. numberOfSeries++;
  248. }
  249. }
  250. return arr;
  251. }, []);
  252. // setScale is fired after all the series is initialized,
  253. // which is an ideal time to update the axis.categories.
  254. treeGrid = getTreeGridFromData(data, uniqueNames || false, (uniqueNames === true) ? numberOfSeries : 1);
  255. // Assign values to the axis.
  256. axis.categories = treeGrid.categories;
  257. axis.treeGrid.mapOfPosToGridNode = treeGrid.mapOfPosToGridNode;
  258. axis.hasNames = true;
  259. axis.treeGrid.tree = treeGrid.tree;
  260. // Update yData now that we have calculated the y values
  261. axis.series.forEach(function (series) {
  262. var data = (series.options.data || []).map(function (d) {
  263. return isObject(d, true) ? merge(d) : d;
  264. });
  265. // Avoid destroying points when series is not visible
  266. if (series.visible) {
  267. series.setData(data, false);
  268. }
  269. });
  270. // Calculate the label options for each level in the tree.
  271. axis.treeGrid.mapOptionsToLevel =
  272. TreeSeriesMixin.getLevelOptions({
  273. defaults: labelOptions,
  274. from: 1,
  275. levels: labelOptions && labelOptions.levels,
  276. to: axis.treeGrid.tree && axis.treeGrid.tree.height
  277. });
  278. // Setting initial collapsed nodes
  279. if (e.type === 'beforeRender') {
  280. axis.treeGrid.collapsedNodes = treeGrid.collapsedNodes;
  281. }
  282. }
  283. });
  284. }
  285. /**
  286. * Generates a tick for initial positioning.
  287. *
  288. * @private
  289. * @function Highcharts.GridAxis#generateTick
  290. *
  291. * @param {Function} proceed
  292. * The original generateTick function.
  293. *
  294. * @param {number} pos
  295. * The tick position in axis values.
  296. */
  297. function wrapGenerateTick(proceed, pos) {
  298. var axis = this, mapOptionsToLevel = axis.treeGrid.mapOptionsToLevel || {}, isTreeGrid = axis.options.type === 'treegrid', ticks = axis.ticks;
  299. var tick = ticks[pos], levelOptions, options, gridNode;
  300. if (isTreeGrid &&
  301. axis.treeGrid.mapOfPosToGridNode) {
  302. gridNode = axis.treeGrid.mapOfPosToGridNode[pos];
  303. levelOptions = mapOptionsToLevel[gridNode.depth];
  304. if (levelOptions) {
  305. options = {
  306. labels: levelOptions
  307. };
  308. }
  309. if (!tick) {
  310. ticks[pos] = tick =
  311. new Tick(axis, pos, void 0, void 0, {
  312. category: gridNode.name,
  313. tickmarkOffset: gridNode.tickmarkOffset,
  314. options: options
  315. });
  316. }
  317. else {
  318. // update labels depending on tick interval
  319. tick.parameters.category = gridNode.name;
  320. tick.options = options;
  321. tick.addLabel();
  322. }
  323. }
  324. else {
  325. proceed.apply(axis, Array.prototype.slice.call(arguments, 1));
  326. }
  327. }
  328. /**
  329. * Override to add indentation to axis.maxLabelDimensions.
  330. *
  331. * @private
  332. * @function Highcharts.GridAxis#getMaxLabelDimensions
  333. *
  334. * @param {Function} proceed
  335. * The original function
  336. */
  337. function wrapGetMaxLabelDimensions(proceed) {
  338. var axis = this, options = axis.options, labelOptions = options && options.labels, indentation = (labelOptions && isNumber(labelOptions.indentation) ?
  339. labelOptions.indentation :
  340. 0), retVal = proceed.apply(axis, Array.prototype.slice.call(arguments, 1)), isTreeGrid = axis.options.type === 'treegrid';
  341. var treeDepth;
  342. if (isTreeGrid && axis.treeGrid.mapOfPosToGridNode) {
  343. treeDepth = axis.treeGrid.mapOfPosToGridNode[-1].height || 0;
  344. retVal.width += indentation * (treeDepth - 1);
  345. }
  346. return retVal;
  347. }
  348. /**
  349. * @private
  350. */
  351. function wrapInit(proceed, chart, userOptions) {
  352. var axis = this, isTreeGrid = userOptions.type === 'treegrid';
  353. if (!axis.treeGrid) {
  354. axis.treeGrid = new Additions(axis);
  355. }
  356. // Set default and forced options for TreeGrid
  357. if (isTreeGrid) {
  358. // Add event for updating the categories of a treegrid.
  359. // NOTE Preferably these events should be set on the axis.
  360. addEvent(chart, 'beforeRender', onBeforeRender);
  361. addEvent(chart, 'beforeRedraw', onBeforeRender);
  362. // Add new collapsed nodes on addseries
  363. addEvent(chart, 'addSeries', function (e) {
  364. if (e.options.data) {
  365. var treeGrid = getTreeGridFromData(e.options.data, userOptions.uniqueNames || false, 1);
  366. axis.treeGrid.collapsedNodes = (axis.treeGrid.collapsedNodes || []).concat(treeGrid.collapsedNodes);
  367. }
  368. });
  369. // Collapse all nodes in axis.treegrid.collapsednodes
  370. // where collapsed equals true.
  371. addEvent(axis, 'foundExtremes', function () {
  372. if (axis.treeGrid.collapsedNodes) {
  373. axis.treeGrid.collapsedNodes.forEach(function (node) {
  374. var breaks = axis.treeGrid.collapse(node);
  375. if (axis.brokenAxis) {
  376. axis.brokenAxis.setBreaks(breaks, false);
  377. // remove the node from the axis collapsedNodes
  378. if (axis.treeGrid.collapsedNodes) {
  379. axis.treeGrid.collapsedNodes = axis.treeGrid.collapsedNodes.filter(function (n) {
  380. return node.collapseStart !== n.collapseStart ||
  381. node.collapseEnd !== n.collapseEnd;
  382. });
  383. }
  384. }
  385. });
  386. }
  387. });
  388. // If staticScale is not defined on the yAxis
  389. // and chart height is set, set axis.isDirty
  390. // to ensure collapsing works (#12012)
  391. addEvent(axis, 'afterBreaks', function () {
  392. var _a;
  393. if (axis.coll === 'yAxis' && !axis.staticScale && ((_a = axis.chart.options.chart) === null || _a === void 0 ? void 0 : _a.height)) {
  394. axis.isDirty = true;
  395. }
  396. });
  397. userOptions = merge({
  398. // Default options
  399. grid: {
  400. enabled: true
  401. },
  402. // TODO: add support for align in treegrid.
  403. labels: {
  404. align: 'left',
  405. /**
  406. * Set options on specific levels in a tree grid axis. Takes
  407. * precedence over labels options.
  408. *
  409. * @sample {gantt} gantt/treegrid-axis/labels-levels
  410. * Levels on TreeGrid Labels
  411. *
  412. * @type {Array<*>}
  413. * @product gantt
  414. * @apioption yAxis.labels.levels
  415. *
  416. * @private
  417. */
  418. levels: [{
  419. /**
  420. * Specify the level which the options within this object
  421. * applies to.
  422. *
  423. * @type {number}
  424. * @product gantt
  425. * @apioption yAxis.labels.levels.level
  426. *
  427. * @private
  428. */
  429. level: void 0
  430. }, {
  431. level: 1,
  432. /**
  433. * @type {Highcharts.CSSObject}
  434. * @product gantt
  435. * @apioption yAxis.labels.levels.style
  436. *
  437. * @private
  438. */
  439. style: {
  440. /** @ignore-option */
  441. fontWeight: 'bold'
  442. }
  443. }],
  444. /**
  445. * The symbol for the collapse and expand icon in a
  446. * treegrid.
  447. *
  448. * @product gantt
  449. * @optionparent yAxis.labels.symbol
  450. *
  451. * @private
  452. */
  453. symbol: {
  454. /**
  455. * The symbol type. Points to a definition function in
  456. * the `Highcharts.Renderer.symbols` collection.
  457. *
  458. * @type {Highcharts.SymbolKeyValue}
  459. *
  460. * @private
  461. */
  462. type: 'triangle',
  463. x: -5,
  464. y: -5,
  465. height: 10,
  466. width: 10,
  467. padding: 5
  468. }
  469. },
  470. uniqueNames: false
  471. }, userOptions, {
  472. // Forced options
  473. reversed: true,
  474. // grid.columns is not supported in treegrid
  475. grid: {
  476. columns: void 0
  477. }
  478. });
  479. }
  480. // Now apply the original function with the original arguments,
  481. // which are sliced off this function's arguments
  482. proceed.apply(axis, [chart, userOptions]);
  483. if (isTreeGrid) {
  484. axis.hasNames = true;
  485. axis.options.showLastLabel = true;
  486. }
  487. }
  488. /**
  489. * Set the tick positions, tickInterval, axis min and max.
  490. *
  491. * @private
  492. * @function Highcharts.GridAxis#setTickInterval
  493. *
  494. * @param {Function} proceed
  495. * The original setTickInterval function.
  496. */
  497. function wrapSetTickInterval(proceed) {
  498. var axis = this, options = axis.options, isTreeGrid = options.type === 'treegrid';
  499. if (isTreeGrid) {
  500. axis.min = pick(axis.userMin, options.min, axis.dataMin);
  501. axis.max = pick(axis.userMax, options.max, axis.dataMax);
  502. fireEvent(axis, 'foundExtremes');
  503. // setAxisTranslation modifies the min and max according to
  504. // axis breaks.
  505. axis.setAxisTranslation(true);
  506. axis.tickmarkOffset = 0.5;
  507. axis.tickInterval = 1;
  508. axis.tickPositions = axis.treeGrid.mapOfPosToGridNode ?
  509. axis.treeGrid.getTickPositions() :
  510. [];
  511. }
  512. else {
  513. proceed.apply(axis, Array.prototype.slice.call(arguments, 1));
  514. }
  515. }
  516. /* *
  517. *
  518. * Classes
  519. *
  520. * */
  521. /**
  522. * @private
  523. * @class
  524. */
  525. var Additions = /** @class */ (function () {
  526. /* *
  527. *
  528. * Constructors
  529. *
  530. * */
  531. /**
  532. * @private
  533. */
  534. function Additions(axis) {
  535. this.axis = axis;
  536. }
  537. /* *
  538. *
  539. * Functions
  540. *
  541. * */
  542. /**
  543. * Calculates the new axis breaks to collapse a node.
  544. *
  545. * @private
  546. *
  547. * @param {Highcharts.Axis} axis
  548. * The axis to check against.
  549. *
  550. * @param {Highcharts.GridNode} node
  551. * The node to collapse.
  552. *
  553. * @param {number} pos
  554. * The tick position to collapse.
  555. *
  556. * @return {Array<object>}
  557. * Returns an array of the new breaks for the axis.
  558. */
  559. Additions.prototype.collapse = function (node) {
  560. var axis = this.axis, breaks = (axis.options.breaks || []), obj = getBreakFromNode(node, axis.max);
  561. breaks.push(obj);
  562. return breaks;
  563. };
  564. /**
  565. * Calculates the new axis breaks to expand a node.
  566. *
  567. * @private
  568. *
  569. * @param {Highcharts.Axis} axis
  570. * The axis to check against.
  571. *
  572. * @param {Highcharts.GridNode} node
  573. * The node to expand.
  574. *
  575. * @param {number} pos
  576. * The tick position to expand.
  577. *
  578. * @return {Array<object>}
  579. * Returns an array of the new breaks for the axis.
  580. */
  581. Additions.prototype.expand = function (node) {
  582. var axis = this.axis, breaks = (axis.options.breaks || []), obj = getBreakFromNode(node, axis.max);
  583. // Remove the break from the axis breaks array.
  584. return breaks.reduce(function (arr, b) {
  585. if (b.to !== obj.to || b.from !== obj.from) {
  586. arr.push(b);
  587. }
  588. return arr;
  589. }, []);
  590. };
  591. /**
  592. * Creates a list of positions for the ticks on the axis. Filters out
  593. * positions that are outside min and max, or is inside an axis break.
  594. *
  595. * @private
  596. *
  597. * @return {Array<number>}
  598. * List of positions.
  599. */
  600. Additions.prototype.getTickPositions = function () {
  601. var axis = this.axis;
  602. return Object.keys(axis.treeGrid.mapOfPosToGridNode || {}).reduce(function (arr, key) {
  603. var pos = +key;
  604. if (axis.min <= pos &&
  605. axis.max >= pos &&
  606. !(axis.brokenAxis && axis.brokenAxis.isInAnyBreak(pos))) {
  607. arr.push(pos);
  608. }
  609. return arr;
  610. }, []);
  611. };
  612. /**
  613. * Check if a node is collapsed.
  614. *
  615. * @private
  616. *
  617. * @param {Highcharts.Axis} axis
  618. * The axis to check against.
  619. *
  620. * @param {object} node
  621. * The node to check if is collapsed.
  622. *
  623. * @param {number} pos
  624. * The tick position to collapse.
  625. *
  626. * @return {boolean}
  627. * Returns true if collapsed, false if expanded.
  628. */
  629. Additions.prototype.isCollapsed = function (node) {
  630. var axis = this.axis, breaks = (axis.options.breaks || []), obj = getBreakFromNode(node, axis.max);
  631. return breaks.some(function (b) {
  632. return b.from === obj.from && b.to === obj.to;
  633. });
  634. };
  635. /**
  636. * Calculates the new axis breaks after toggling the collapse/expand
  637. * state of a node. If it is collapsed it will be expanded, and if it is
  638. * exapended it will be collapsed.
  639. *
  640. * @private
  641. *
  642. * @param {Highcharts.Axis} axis
  643. * The axis to check against.
  644. *
  645. * @param {Highcharts.GridNode} node
  646. * The node to toggle.
  647. *
  648. * @return {Array<object>}
  649. * Returns an array of the new breaks for the axis.
  650. */
  651. Additions.prototype.toggleCollapse = function (node) {
  652. return (this.isCollapsed(node) ?
  653. this.expand(node) :
  654. this.collapse(node));
  655. };
  656. return Additions;
  657. }());
  658. TreeGridAxis.Additions = Additions;
  659. })(TreeGridAxis || (TreeGridAxis = {}));
  660. // Make utility functions available for testing.
  661. Axis.prototype.utils = {
  662. getNode: Tree.getNode
  663. };
  664. TreeGridAxis.compose(Axis);
  665. export default TreeGridAxis;