Tree.js 3.9 KB

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