layoutHelper.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  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. * A third-party license is embedded for some of the code in this file:
  42. * The tree layoutHelper implementation was originally copied from
  43. * "d3.js"(https://github.com/d3/d3-hierarchy) with
  44. * some modifications made for this project.
  45. * (see more details in the comment of the specific method below.)
  46. * The use of the source code of this file is also subject to the terms
  47. * and consitions of the licence of "d3.js" (BSD-3Clause, see
  48. * </licenses/LICENSE-d3>).
  49. */
  50. /**
  51. * @file The layout algorithm of node-link tree diagrams. Here we using Reingold-Tilford algorithm to drawing
  52. * the tree.
  53. */
  54. import * as layout from '../../util/layout.js';
  55. /**
  56. * Initialize all computational message for following algorithm.
  57. */
  58. export function init(inRoot) {
  59. var root = inRoot;
  60. root.hierNode = {
  61. defaultAncestor: null,
  62. ancestor: root,
  63. prelim: 0,
  64. modifier: 0,
  65. change: 0,
  66. shift: 0,
  67. i: 0,
  68. thread: null
  69. };
  70. var nodes = [root];
  71. var node;
  72. var children;
  73. while (node = nodes.pop()) {
  74. // jshint ignore:line
  75. children = node.children;
  76. if (node.isExpand && children.length) {
  77. var n = children.length;
  78. for (var i = n - 1; i >= 0; i--) {
  79. var child = children[i];
  80. child.hierNode = {
  81. defaultAncestor: null,
  82. ancestor: child,
  83. prelim: 0,
  84. modifier: 0,
  85. change: 0,
  86. shift: 0,
  87. i: i,
  88. thread: null
  89. };
  90. nodes.push(child);
  91. }
  92. }
  93. }
  94. }
  95. /**
  96. * The implementation of this function was originally copied from "d3.js"
  97. * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>
  98. * with some modifications made for this program.
  99. * See the license statement at the head of this file.
  100. *
  101. * Computes a preliminary x coordinate for node. Before that, this function is
  102. * applied recursively to the children of node, as well as the function
  103. * apportion(). After spacing out the children by calling executeShifts(), the
  104. * node is placed to the midpoint of its outermost children.
  105. */
  106. export function firstWalk(node, separation) {
  107. var children = node.isExpand ? node.children : [];
  108. var siblings = node.parentNode.children;
  109. var subtreeW = node.hierNode.i ? siblings[node.hierNode.i - 1] : null;
  110. if (children.length) {
  111. executeShifts(node);
  112. var midPoint = (children[0].hierNode.prelim + children[children.length - 1].hierNode.prelim) / 2;
  113. if (subtreeW) {
  114. node.hierNode.prelim = subtreeW.hierNode.prelim + separation(node, subtreeW);
  115. node.hierNode.modifier = node.hierNode.prelim - midPoint;
  116. } else {
  117. node.hierNode.prelim = midPoint;
  118. }
  119. } else if (subtreeW) {
  120. node.hierNode.prelim = subtreeW.hierNode.prelim + separation(node, subtreeW);
  121. }
  122. node.parentNode.hierNode.defaultAncestor = apportion(node, subtreeW, node.parentNode.hierNode.defaultAncestor || siblings[0], separation);
  123. }
  124. /**
  125. * The implementation of this function was originally copied from "d3.js"
  126. * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>
  127. * with some modifications made for this program.
  128. * See the license statement at the head of this file.
  129. *
  130. * Computes all real x-coordinates by summing up the modifiers recursively.
  131. */
  132. export function secondWalk(node) {
  133. var nodeX = node.hierNode.prelim + node.parentNode.hierNode.modifier;
  134. node.setLayout({
  135. x: nodeX
  136. }, true);
  137. node.hierNode.modifier += node.parentNode.hierNode.modifier;
  138. }
  139. export function separation(cb) {
  140. return arguments.length ? cb : defaultSeparation;
  141. }
  142. /**
  143. * Transform the common coordinate to radial coordinate.
  144. */
  145. export function radialCoordinate(rad, r) {
  146. rad -= Math.PI / 2;
  147. return {
  148. x: r * Math.cos(rad),
  149. y: r * Math.sin(rad)
  150. };
  151. }
  152. /**
  153. * Get the layout position of the whole view.
  154. */
  155. export function getViewRect(seriesModel, api) {
  156. return layout.getLayoutRect(seriesModel.getBoxLayoutParams(), {
  157. width: api.getWidth(),
  158. height: api.getHeight()
  159. });
  160. }
  161. /**
  162. * All other shifts, applied to the smaller subtrees between w- and w+, are
  163. * performed by this function.
  164. *
  165. * The implementation of this function was originally copied from "d3.js"
  166. * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>
  167. * with some modifications made for this program.
  168. * See the license statement at the head of this file.
  169. */
  170. function executeShifts(node) {
  171. var children = node.children;
  172. var n = children.length;
  173. var shift = 0;
  174. var change = 0;
  175. while (--n >= 0) {
  176. var child = children[n];
  177. child.hierNode.prelim += shift;
  178. child.hierNode.modifier += shift;
  179. change += child.hierNode.change;
  180. shift += child.hierNode.shift + change;
  181. }
  182. }
  183. /**
  184. * The implementation of this function was originally copied from "d3.js"
  185. * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>
  186. * with some modifications made for this program.
  187. * See the license statement at the head of this file.
  188. *
  189. * The core of the algorithm. Here, a new subtree is combined with the
  190. * previous subtrees. Threads are used to traverse the inside and outside
  191. * contours of the left and right subtree up to the highest common level.
  192. * Whenever two nodes of the inside contours conflict, we compute the left
  193. * one of the greatest uncommon ancestors using the function nextAncestor()
  194. * and call moveSubtree() to shift the subtree and prepare the shifts of
  195. * smaller subtrees. Finally, we add a new thread (if necessary).
  196. */
  197. function apportion(subtreeV, subtreeW, ancestor, separation) {
  198. if (subtreeW) {
  199. var nodeOutRight = subtreeV;
  200. var nodeInRight = subtreeV;
  201. var nodeOutLeft = nodeInRight.parentNode.children[0];
  202. var nodeInLeft = subtreeW;
  203. var sumOutRight = nodeOutRight.hierNode.modifier;
  204. var sumInRight = nodeInRight.hierNode.modifier;
  205. var sumOutLeft = nodeOutLeft.hierNode.modifier;
  206. var sumInLeft = nodeInLeft.hierNode.modifier;
  207. while (nodeInLeft = nextRight(nodeInLeft), nodeInRight = nextLeft(nodeInRight), nodeInLeft && nodeInRight) {
  208. nodeOutRight = nextRight(nodeOutRight);
  209. nodeOutLeft = nextLeft(nodeOutLeft);
  210. nodeOutRight.hierNode.ancestor = subtreeV;
  211. var shift = nodeInLeft.hierNode.prelim + sumInLeft - nodeInRight.hierNode.prelim - sumInRight + separation(nodeInLeft, nodeInRight);
  212. if (shift > 0) {
  213. moveSubtree(nextAncestor(nodeInLeft, subtreeV, ancestor), subtreeV, shift);
  214. sumInRight += shift;
  215. sumOutRight += shift;
  216. }
  217. sumInLeft += nodeInLeft.hierNode.modifier;
  218. sumInRight += nodeInRight.hierNode.modifier;
  219. sumOutRight += nodeOutRight.hierNode.modifier;
  220. sumOutLeft += nodeOutLeft.hierNode.modifier;
  221. }
  222. if (nodeInLeft && !nextRight(nodeOutRight)) {
  223. nodeOutRight.hierNode.thread = nodeInLeft;
  224. nodeOutRight.hierNode.modifier += sumInLeft - sumOutRight;
  225. }
  226. if (nodeInRight && !nextLeft(nodeOutLeft)) {
  227. nodeOutLeft.hierNode.thread = nodeInRight;
  228. nodeOutLeft.hierNode.modifier += sumInRight - sumOutLeft;
  229. ancestor = subtreeV;
  230. }
  231. }
  232. return ancestor;
  233. }
  234. /**
  235. * This function is used to traverse the right contour of a subtree.
  236. * It returns the rightmost child of node or the thread of node. The function
  237. * returns null if and only if node is on the highest depth of its subtree.
  238. */
  239. function nextRight(node) {
  240. var children = node.children;
  241. return children.length && node.isExpand ? children[children.length - 1] : node.hierNode.thread;
  242. }
  243. /**
  244. * This function is used to traverse the left contour of a subtree (or a subforest).
  245. * It returns the leftmost child of node or the thread of node. The function
  246. * returns null if and only if node is on the highest depth of its subtree.
  247. */
  248. function nextLeft(node) {
  249. var children = node.children;
  250. return children.length && node.isExpand ? children[0] : node.hierNode.thread;
  251. }
  252. /**
  253. * If nodeInLeft’s ancestor is a sibling of node, returns nodeInLeft’s ancestor.
  254. * Otherwise, returns the specified ancestor.
  255. */
  256. function nextAncestor(nodeInLeft, node, ancestor) {
  257. return nodeInLeft.hierNode.ancestor.parentNode === node.parentNode ? nodeInLeft.hierNode.ancestor : ancestor;
  258. }
  259. /**
  260. * The implementation of this function was originally copied from "d3.js"
  261. * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>
  262. * with some modifications made for this program.
  263. * See the license statement at the head of this file.
  264. *
  265. * Shifts the current subtree rooted at wr.
  266. * This is done by increasing prelim(w+) and modifier(w+) by shift.
  267. */
  268. function moveSubtree(wl, wr, shift) {
  269. var change = shift / (wr.hierNode.i - wl.hierNode.i);
  270. wr.hierNode.change -= change;
  271. wr.hierNode.shift += shift;
  272. wr.hierNode.modifier += shift;
  273. wr.hierNode.prelim += shift;
  274. wl.hierNode.change += change;
  275. }
  276. /**
  277. * The implementation of this function was originally copied from "d3.js"
  278. * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>
  279. * with some modifications made for this program.
  280. * See the license statement at the head of this file.
  281. */
  282. function defaultSeparation(node1, node2) {
  283. return node1.parentNode === node2.parentNode ? 1 : 2;
  284. }