TreeGridAxis.js 26 KB

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