Tree.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /* *
  2. *
  3. * (c) 2016-2021 Highsoft AS
  4. *
  5. * Authors: Jon Arild Nygard
  6. *
  7. * License: www.highcharts.com/license
  8. *
  9. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  10. *
  11. * */
  12. /* eslint no-console: 0 */
  13. 'use strict';
  14. import U from '../Core/Utilities.js';
  15. var extend = U.extend, isNumber = U.isNumber, pick = U.pick;
  16. /**
  17. * Creates an object map from parent id to childrens index.
  18. *
  19. * @private
  20. * @function Highcharts.Tree#getListOfParents
  21. *
  22. * @param {Array<*>} data
  23. * List of points set in options. `Array.parent` is parent id of point.
  24. *
  25. * @param {Array<string>} ids
  26. * List of all point ids.
  27. *
  28. * @return {Highcharts.Dictionary<Array<*>>}
  29. * Map from parent id to children index in data
  30. */
  31. var getListOfParents = function (data, ids) {
  32. var listOfParents = data.reduce(function (prev, curr) {
  33. var parent = pick(curr.parent, '');
  34. if (typeof prev[parent] === 'undefined') {
  35. prev[parent] = [];
  36. }
  37. prev[parent].push(curr);
  38. return prev;
  39. }, {}), parents = Object.keys(listOfParents);
  40. // If parent does not exist, hoist parent to root of tree.
  41. parents.forEach(function (parent, list) {
  42. var children = listOfParents[parent];
  43. if ((parent !== '') && (ids.indexOf(parent) === -1)) {
  44. children.forEach(function (child) {
  45. list[''].push(child);
  46. });
  47. delete list[parent];
  48. }
  49. });
  50. return listOfParents;
  51. };
  52. var getNode = function (id, parent, level, data, mapOfIdToChildren, options) {
  53. var descendants = 0, height = 0, after = options && options.after, before = options && options.before, node = {
  54. data: data,
  55. depth: level - 1,
  56. id: id,
  57. level: level,
  58. parent: parent
  59. }, start, end, children;
  60. // Allow custom logic before the children has been created.
  61. if (typeof before === 'function') {
  62. before(node, options);
  63. }
  64. // Call getNode recursively on the children. Calulate the height of the
  65. // node, and the number of descendants.
  66. children = ((mapOfIdToChildren[id] || [])).map(function (child) {
  67. var node = getNode(child.id, id, (level + 1), child, mapOfIdToChildren, options), childStart = child.start, childEnd = (child.milestone === true ?
  68. childStart :
  69. child.end);
  70. // Start should be the lowest child.start.
  71. start = ((!isNumber(start) || childStart < start) ?
  72. childStart :
  73. start);
  74. // End should be the largest child.end.
  75. // If child is milestone, then use start as end.
  76. end = ((!isNumber(end) || childEnd > end) ?
  77. childEnd :
  78. end);
  79. descendants = descendants + 1 + node.descendants;
  80. height = Math.max(node.height + 1, height);
  81. return node;
  82. });
  83. // Calculate start and end for point if it is not already explicitly set.
  84. if (data) {
  85. data.start = pick(data.start, start);
  86. data.end = pick(data.end, end);
  87. }
  88. extend(node, {
  89. children: children,
  90. descendants: descendants,
  91. height: height
  92. });
  93. // Allow custom logic after the children has been created.
  94. if (typeof after === 'function') {
  95. after(node, options);
  96. }
  97. return node;
  98. };
  99. var getTree = function (data, options) {
  100. var ids = data.map(function (d) {
  101. return d.id;
  102. }), mapOfIdToChildren = getListOfParents(data, ids);
  103. return getNode('', null, 1, null, mapOfIdToChildren, options);
  104. };
  105. var Tree = {
  106. getListOfParents: getListOfParents,
  107. getNode: getNode,
  108. getTree: getTree
  109. };
  110. export default Tree;