layoutHelper.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. /**
  20. * AUTO-GENERATED FILE. DO NOT MODIFY.
  21. */
  22. /*
  23. * Licensed to the Apache Software Foundation (ASF) under one
  24. * or more contributor license agreements. See the NOTICE file
  25. * distributed with this work for additional information
  26. * regarding copyright ownership. The ASF licenses this file
  27. * to you under the Apache License, Version 2.0 (the
  28. * "License"); you may not use this file except in compliance
  29. * with the License. You may obtain a copy of the License at
  30. *
  31. * http://www.apache.org/licenses/LICENSE-2.0
  32. *
  33. * Unless required by applicable law or agreed to in writing,
  34. * software distributed under the License is distributed on an
  35. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  36. * KIND, either express or implied. See the License for the
  37. * specific language governing permissions and limitations
  38. * under the License.
  39. */
  40. /**
  41. * Initialize all computational message for following algorithm.
  42. */
  43. export function init(inRoot) {
  44. var root = inRoot;
  45. root.hierNode = {
  46. defaultAncestor: null,
  47. ancestor: root,
  48. prelim: 0,
  49. modifier: 0,
  50. change: 0,
  51. shift: 0,
  52. i: 0,
  53. thread: null
  54. };
  55. var nodes = [root];
  56. var node;
  57. var children;
  58. while (node = nodes.pop()) {
  59. // jshint ignore:line
  60. children = node.children;
  61. if (node.isExpand && children.length) {
  62. var n = children.length;
  63. for (var i = n - 1; i >= 0; i--) {
  64. var child = children[i];
  65. child.hierNode = {
  66. defaultAncestor: null,
  67. ancestor: child,
  68. prelim: 0,
  69. modifier: 0,
  70. change: 0,
  71. shift: 0,
  72. i: i,
  73. thread: null
  74. };
  75. nodes.push(child);
  76. }
  77. }
  78. }
  79. }
  80. /**
  81. * The implementation of this function was originally copied from "d3.js"
  82. * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>
  83. * with some modifications made for this program.
  84. * See the license statement at the head of this file.
  85. *
  86. * Computes a preliminary x coordinate for node. Before that, this function is
  87. * applied recursively to the children of node, as well as the function
  88. * apportion(). After spacing out the children by calling executeShifts(), the
  89. * node is placed to the midpoint of its outermost children.
  90. */
  91. export function firstWalk(node, separation) {
  92. var children = node.isExpand ? node.children : [];
  93. var siblings = node.parentNode.children;
  94. var subtreeW = node.hierNode.i ? siblings[node.hierNode.i - 1] : null;
  95. if (children.length) {
  96. executeShifts(node);
  97. var midPoint = (children[0].hierNode.prelim + children[children.length - 1].hierNode.prelim) / 2;
  98. if (subtreeW) {
  99. node.hierNode.prelim = subtreeW.hierNode.prelim + separation(node, subtreeW);
  100. node.hierNode.modifier = node.hierNode.prelim - midPoint;
  101. } else {
  102. node.hierNode.prelim = midPoint;
  103. }
  104. } else if (subtreeW) {
  105. node.hierNode.prelim = subtreeW.hierNode.prelim + separation(node, subtreeW);
  106. }
  107. node.parentNode.hierNode.defaultAncestor = apportion(node, subtreeW, node.parentNode.hierNode.defaultAncestor || siblings[0], separation);
  108. }
  109. /**
  110. * The implementation of this function was originally copied from "d3.js"
  111. * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>
  112. * with some modifications made for this program.
  113. * See the license statement at the head of this file.
  114. *
  115. * Computes all real x-coordinates by summing up the modifiers recursively.
  116. */
  117. export function secondWalk(node) {
  118. var nodeX = node.hierNode.prelim + node.parentNode.hierNode.modifier;
  119. node.setLayout({
  120. x: nodeX
  121. }, true);
  122. node.hierNode.modifier += node.parentNode.hierNode.modifier;
  123. }
  124. export function separation(cb) {
  125. return arguments.length ? cb : defaultSeparation;
  126. }
  127. /**
  128. * Transform the common coordinate to radial coordinate.
  129. */
  130. export function radialCoordinate(rad, r) {
  131. rad -= Math.PI / 2;
  132. return {
  133. x: r * Math.cos(rad),
  134. y: r * Math.sin(rad)
  135. };
  136. }
  137. /**
  138. * All other shifts, applied to the smaller subtrees between w- and w+, are
  139. * performed by this function.
  140. *
  141. * The implementation of this function was originally copied from "d3.js"
  142. * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>
  143. * with some modifications made for this program.
  144. * See the license statement at the head of this file.
  145. */
  146. function executeShifts(node) {
  147. var children = node.children;
  148. var n = children.length;
  149. var shift = 0;
  150. var change = 0;
  151. while (--n >= 0) {
  152. var child = children[n];
  153. child.hierNode.prelim += shift;
  154. child.hierNode.modifier += shift;
  155. change += child.hierNode.change;
  156. shift += child.hierNode.shift + change;
  157. }
  158. }
  159. /**
  160. * The implementation of this function was originally copied from "d3.js"
  161. * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>
  162. * with some modifications made for this program.
  163. * See the license statement at the head of this file.
  164. *
  165. * The core of the algorithm. Here, a new subtree is combined with the
  166. * previous subtrees. Threads are used to traverse the inside and outside
  167. * contours of the left and right subtree up to the highest common level.
  168. * Whenever two nodes of the inside contours conflict, we compute the left
  169. * one of the greatest uncommon ancestors using the function nextAncestor()
  170. * and call moveSubtree() to shift the subtree and prepare the shifts of
  171. * smaller subtrees. Finally, we add a new thread (if necessary).
  172. */
  173. function apportion(subtreeV, subtreeW, ancestor, separation) {
  174. if (subtreeW) {
  175. var nodeOutRight = subtreeV;
  176. var nodeInRight = subtreeV;
  177. var nodeOutLeft = nodeInRight.parentNode.children[0];
  178. var nodeInLeft = subtreeW;
  179. var sumOutRight = nodeOutRight.hierNode.modifier;
  180. var sumInRight = nodeInRight.hierNode.modifier;
  181. var sumOutLeft = nodeOutLeft.hierNode.modifier;
  182. var sumInLeft = nodeInLeft.hierNode.modifier;
  183. while (nodeInLeft = nextRight(nodeInLeft), nodeInRight = nextLeft(nodeInRight), nodeInLeft && nodeInRight) {
  184. nodeOutRight = nextRight(nodeOutRight);
  185. nodeOutLeft = nextLeft(nodeOutLeft);
  186. nodeOutRight.hierNode.ancestor = subtreeV;
  187. var shift = nodeInLeft.hierNode.prelim + sumInLeft - nodeInRight.hierNode.prelim - sumInRight + separation(nodeInLeft, nodeInRight);
  188. if (shift > 0) {
  189. moveSubtree(nextAncestor(nodeInLeft, subtreeV, ancestor), subtreeV, shift);
  190. sumInRight += shift;
  191. sumOutRight += shift;
  192. }
  193. sumInLeft += nodeInLeft.hierNode.modifier;
  194. sumInRight += nodeInRight.hierNode.modifier;
  195. sumOutRight += nodeOutRight.hierNode.modifier;
  196. sumOutLeft += nodeOutLeft.hierNode.modifier;
  197. }
  198. if (nodeInLeft && !nextRight(nodeOutRight)) {
  199. nodeOutRight.hierNode.thread = nodeInLeft;
  200. nodeOutRight.hierNode.modifier += sumInLeft - sumOutRight;
  201. }
  202. if (nodeInRight && !nextLeft(nodeOutLeft)) {
  203. nodeOutLeft.hierNode.thread = nodeInRight;
  204. nodeOutLeft.hierNode.modifier += sumInRight - sumOutLeft;
  205. ancestor = subtreeV;
  206. }
  207. }
  208. return ancestor;
  209. }
  210. /**
  211. * This function is used to traverse the right contour of a subtree.
  212. * It returns the rightmost child of node or the thread of node. The function
  213. * returns null if and only if node is on the highest depth of its subtree.
  214. */
  215. function nextRight(node) {
  216. var children = node.children;
  217. return children.length && node.isExpand ? children[children.length - 1] : node.hierNode.thread;
  218. }
  219. /**
  220. * This function is used to traverse the left contour of a subtree (or a subforest).
  221. * It returns the leftmost child of node or the thread of node. The function
  222. * returns null if and only if node is on the highest depth of its subtree.
  223. */
  224. function nextLeft(node) {
  225. var children = node.children;
  226. return children.length && node.isExpand ? children[0] : node.hierNode.thread;
  227. }
  228. /**
  229. * If nodeInLeft’s ancestor is a sibling of node, returns nodeInLeft’s ancestor.
  230. * Otherwise, returns the specified ancestor.
  231. */
  232. function nextAncestor(nodeInLeft, node, ancestor) {
  233. return nodeInLeft.hierNode.ancestor.parentNode === node.parentNode ? nodeInLeft.hierNode.ancestor : ancestor;
  234. }
  235. /**
  236. * The implementation of this function was originally copied from "d3.js"
  237. * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>
  238. * with some modifications made for this program.
  239. * See the license statement at the head of this file.
  240. *
  241. * Shifts the current subtree rooted at wr.
  242. * This is done by increasing prelim(w+) and modifier(w+) by shift.
  243. */
  244. function moveSubtree(wl, wr, shift) {
  245. var change = shift / (wr.hierNode.i - wl.hierNode.i);
  246. wr.hierNode.change -= change;
  247. wr.hierNode.shift += shift;
  248. wr.hierNode.modifier += shift;
  249. wr.hierNode.prelim += shift;
  250. wl.hierNode.change += change;
  251. }
  252. /**
  253. * The implementation of this function was originally copied from "d3.js"
  254. * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>
  255. * with some modifications made for this program.
  256. * See the license statement at the head of this file.
  257. */
  258. function defaultSeparation(node1, node2) {
  259. return node1.parentNode === node2.parentNode ? 1 : 2;
  260. }