treemap.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. define('echarts/chart/treemap', [
  2. 'require',
  3. './base',
  4. 'zrender/tool/area',
  5. 'zrender/shape/Rectangle',
  6. 'zrender/shape/Text',
  7. 'zrender/shape/Line',
  8. '../layout/TreeMap',
  9. '../data/Tree',
  10. '../config',
  11. '../util/ecData',
  12. 'zrender/config',
  13. 'zrender/tool/event',
  14. 'zrender/tool/util',
  15. 'zrender/tool/color',
  16. '../chart'
  17. ], function (require) {
  18. var ChartBase = require('./base');
  19. var toolArea = require('zrender/tool/area');
  20. var RectangleShape = require('zrender/shape/Rectangle');
  21. var TextShape = require('zrender/shape/Text');
  22. var LineShape = require('zrender/shape/Line');
  23. var TreeMapLayout = require('../layout/TreeMap');
  24. var Tree = require('../data/Tree');
  25. var ecConfig = require('../config');
  26. ecConfig.treemap = {
  27. zlevel: 0,
  28. z: 1,
  29. calculable: false,
  30. clickable: true,
  31. center: [
  32. '50%',
  33. '50%'
  34. ],
  35. size: [
  36. '80%',
  37. '80%'
  38. ],
  39. root: '',
  40. itemStyle: {
  41. normal: {
  42. label: {
  43. show: true,
  44. x: 5,
  45. y: 12,
  46. textStyle: {
  47. align: 'left',
  48. color: '#000',
  49. fontFamily: 'Arial',
  50. fontSize: 13,
  51. fontStyle: 'normal',
  52. fontWeight: 'normal'
  53. }
  54. },
  55. breadcrumb: {
  56. show: true,
  57. textStyle: {}
  58. },
  59. borderWidth: 1,
  60. borderColor: '#ccc',
  61. childBorderWidth: 1,
  62. childBorderColor: '#ccc'
  63. },
  64. emphasis: {}
  65. }
  66. };
  67. var ecData = require('../util/ecData');
  68. var zrConfig = require('zrender/config');
  69. var zrEvent = require('zrender/tool/event');
  70. var zrUtil = require('zrender/tool/util');
  71. var zrColor = require('zrender/tool/color');
  72. function Treemap(ecTheme, messageCenter, zr, option, myChart) {
  73. ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
  74. this.refresh(option);
  75. var self = this;
  76. self._onclick = function (params) {
  77. return self.__onclick(params);
  78. };
  79. self.zr.on(zrConfig.EVENT.CLICK, self._onclick);
  80. }
  81. Treemap.prototype = {
  82. type: ecConfig.CHART_TYPE_TREEMAP,
  83. refresh: function (newOption) {
  84. this.clear();
  85. if (newOption) {
  86. this.option = newOption;
  87. this.series = this.option.series;
  88. }
  89. this._treesMap = {};
  90. var series = this.series;
  91. var legend = this.component.legend;
  92. for (var i = 0; i < series.length; i++) {
  93. if (series[i].type === ecConfig.CHART_TYPE_TREEMAP) {
  94. series[i] = this.reformOption(series[i]);
  95. var seriesName = series[i].name || '';
  96. this.selectedMap[seriesName] = legend ? legend.isSelected(seriesName) : true;
  97. if (!this.selectedMap[seriesName]) {
  98. continue;
  99. }
  100. this._buildSeries(series[i], i);
  101. }
  102. }
  103. },
  104. _buildSeries: function (series, seriesIndex) {
  105. var tree = Tree.fromOptionData(series.name, series.data);
  106. this._treesMap[seriesIndex] = tree;
  107. var treeRoot = series.root && tree.getNodeById(series.root) || tree.root;
  108. this._buildTreemap(treeRoot, seriesIndex);
  109. },
  110. _buildTreemap: function (treeRoot, seriesIndex) {
  111. var shapeList = this.shapeList;
  112. for (var i = 0; i < shapeList.length;) {
  113. var shape = shapeList[i];
  114. if (ecData.get(shape, 'seriesIndex') === seriesIndex) {
  115. this.zr.delShape(shapeList[i]);
  116. shapeList.splice(i, 1);
  117. } else {
  118. i++;
  119. }
  120. }
  121. var currentShapeLen = shapeList.length;
  122. var series = this.series[seriesIndex];
  123. var itemStyle = series.itemStyle;
  124. var treemapWidth = this.parsePercent(series.size[0], this.zr.getWidth()) || 400;
  125. var treemapHeight = this.parsePercent(series.size[1], this.zr.getHeight()) || 500;
  126. var center = this.parseCenter(this.zr, series.center);
  127. var treemapX = center[0] - treemapWidth * 0.5;
  128. var treemapY = center[1] - treemapHeight * 0.5;
  129. var treemapArea = treemapWidth * treemapHeight;
  130. var sum = 0;
  131. var areaArr = [];
  132. var children = treeRoot.children;
  133. for (var i = 0; i < children.length; i++) {
  134. sum += children[i].data.value;
  135. }
  136. for (var j = 0; j < children.length; j++) {
  137. areaArr.push(children[j].data.value * treemapArea / sum);
  138. }
  139. var treeMapLayout = new TreeMapLayout({
  140. x: treemapX,
  141. y: treemapY,
  142. width: treemapWidth,
  143. height: treemapHeight
  144. });
  145. var locationArr = treeMapLayout.run(areaArr);
  146. for (var k = 0; k < locationArr.length; k++) {
  147. var dataItem = children[k].data;
  148. var rect = locationArr[k];
  149. var queryTarget = [
  150. dataItem.itemStyle,
  151. itemStyle
  152. ];
  153. var itemStyleMerged = this.deepMerge(queryTarget);
  154. if (!itemStyleMerged.normal.color) {
  155. itemStyleMerged.normal.color = this.zr.getColor(k);
  156. }
  157. if (!itemStyleMerged.emphasis.color) {
  158. itemStyleMerged.emphasis.color = itemStyleMerged.normal.color;
  159. }
  160. this._buildItem(dataItem, itemStyleMerged, rect, seriesIndex, k);
  161. if (dataItem.children) {
  162. this._buildChildrenTreemap(dataItem.children, itemStyleMerged, rect, seriesIndex);
  163. }
  164. }
  165. if (this.query(series, 'itemStyle.normal.breadcrumb.show')) {
  166. this._buildBreadcrumb(treeRoot, seriesIndex, treemapX, treemapY + treemapHeight);
  167. }
  168. for (var i = currentShapeLen; i < shapeList.length; i++) {
  169. this.zr.addShape(shapeList[i]);
  170. }
  171. },
  172. _buildItem: function (dataItem, itemStyle, rect, seriesIndex, dataIndex) {
  173. var series = this.series;
  174. var rectangle = this.getRectangle(dataItem, itemStyle, rect);
  175. ecData.pack(rectangle, series[seriesIndex], seriesIndex, dataItem, dataIndex, dataItem.name);
  176. this.shapeList.push(rectangle);
  177. },
  178. getRectangle: function (dataItem, itemStyle, rect) {
  179. var emphasis = itemStyle.emphasis;
  180. var normal = itemStyle.normal;
  181. var textShape = this.getLabel(itemStyle, rect, dataItem.name, dataItem.value);
  182. var hoverable = this.option.hoverable;
  183. var rectangleShape = {
  184. zlevel: this.getZlevelBase(),
  185. z: this.getZBase(),
  186. hoverable: hoverable,
  187. clickable: true,
  188. style: zrUtil.merge({
  189. x: rect.x,
  190. y: rect.y,
  191. width: rect.width,
  192. height: rect.height,
  193. brushType: 'both',
  194. color: normal.color,
  195. lineWidth: normal.borderWidth,
  196. strokeColor: normal.borderColor
  197. }, textShape.style, true),
  198. highlightStyle: zrUtil.merge({
  199. color: emphasis.color,
  200. lineWidth: emphasis.borderWidth,
  201. strokeColor: emphasis.borderColor
  202. }, textShape.highlightStyle, true)
  203. };
  204. return new RectangleShape(rectangleShape);
  205. },
  206. getLabel: function (itemStyle, rect, name, value) {
  207. var normalTextStyle = itemStyle.normal.label.textStyle;
  208. var queryTarget = [
  209. itemStyle.emphasis.label.textStyle,
  210. normalTextStyle
  211. ];
  212. var emphasisTextStyle = this.deepMerge(queryTarget);
  213. var formatter = itemStyle.normal.label.formatter;
  214. var text = this.getLabelText(name, value, formatter);
  215. var textFont = this.getFont(normalTextStyle);
  216. var textWidth = toolArea.getTextWidth(text, textFont);
  217. var textHeight = toolArea.getTextHeight(text, textFont);
  218. var emphasisFormatter = this.deepQuery([
  219. itemStyle.emphasis,
  220. itemStyle.normal
  221. ], 'label.formatter');
  222. var emphasisText = this.getLabelText(name, value, emphasisFormatter);
  223. var emphasisTextFont = this.getFont(emphasisTextStyle);
  224. var emphasisTextWidth = toolArea.getTextWidth(text, emphasisTextFont);
  225. var emphasisTextHeight = toolArea.getTextHeight(text, emphasisTextFont);
  226. if (!itemStyle.normal.label.show) {
  227. text = '';
  228. } else if (itemStyle.normal.label.x + textWidth > rect.width || itemStyle.normal.label.y + textHeight > rect.height) {
  229. text = '';
  230. }
  231. if (!itemStyle.emphasis.label.show) {
  232. emphasisText = '';
  233. } else if (emphasisTextStyle.x + emphasisTextWidth > rect.width || emphasisTextStyle.y + emphasisTextHeight > rect.height) {
  234. emphasisText = '';
  235. }
  236. var textShape = {
  237. style: {
  238. textX: rect.x + itemStyle.normal.label.x,
  239. textY: rect.y + itemStyle.normal.label.y,
  240. text: text,
  241. textPosition: 'specific',
  242. textColor: normalTextStyle.color,
  243. textFont: textFont
  244. },
  245. highlightStyle: {
  246. textX: rect.x + itemStyle.emphasis.label.x,
  247. textY: rect.y + itemStyle.emphasis.label.y,
  248. text: emphasisText,
  249. textColor: emphasisTextStyle.color,
  250. textPosition: 'specific'
  251. }
  252. };
  253. return textShape;
  254. },
  255. getLabelText: function (name, value, formatter) {
  256. if (formatter) {
  257. if (typeof formatter === 'function') {
  258. return formatter.call(this.myChart, name, value);
  259. } else if (typeof formatter === 'string') {
  260. formatter = formatter.replace('{b}', '{b0}').replace('{c}', '{c0}');
  261. formatter = formatter.replace('{b0}', name).replace('{c0}', value);
  262. return formatter;
  263. }
  264. } else {
  265. return name;
  266. }
  267. },
  268. _buildChildrenTreemap: function (data, itemStyle, rect, seriesIndex) {
  269. var treemapArea = rect.width * rect.height;
  270. var sum = 0;
  271. var areaArr = [];
  272. for (var i = 0; i < data.length; i++) {
  273. sum += data[i].value;
  274. }
  275. for (var j = 0; j < data.length; j++) {
  276. areaArr.push(data[j].value * treemapArea / sum);
  277. }
  278. var treeMapLayout = new TreeMapLayout({
  279. x: rect.x,
  280. y: rect.y,
  281. width: rect.width,
  282. height: rect.height
  283. });
  284. var locationArr = treeMapLayout.run(areaArr);
  285. var lineWidth = itemStyle.normal.childBorderWidth;
  286. var lineColor = itemStyle.normal.childBorderColor;
  287. for (var k = 0; k < locationArr.length; k++) {
  288. var item = locationArr[k];
  289. var lines = [];
  290. if (rect.y.toFixed(2) !== item.y.toFixed(2)) {
  291. lines.push(this._getLine(item.x, item.y, item.x + item.width, item.y, lineWidth, lineColor));
  292. }
  293. if (rect.x.toFixed(2) !== item.x.toFixed(2)) {
  294. lines.push(this._getLine(item.x, item.y, item.x, item.y + item.height, lineWidth, lineColor));
  295. }
  296. if ((rect.y + rect.height).toFixed(2) !== (item.y + item.height).toFixed(2)) {
  297. lines.push(this._getLine(item.x, item.y + item.height, item.x + item.width, item.y + item.height, lineWidth, lineColor));
  298. }
  299. if ((rect.x + rect.width).toFixed(2) !== (item.x + item.width).toFixed(2)) {
  300. lines.push(this._getLine(item.x + item.width, item.y, item.x + item.width, item.y + item.height, lineWidth, lineColor));
  301. }
  302. for (var l = 0; l < lines.length; l++) {
  303. ecData.set(lines[l], 'seriesIndex', seriesIndex);
  304. this.shapeList.push(lines[l]);
  305. }
  306. }
  307. },
  308. _getLine: function (xStart, yStart, xEnd, yEnd, lineWidth, lineColor) {
  309. var lineShape = {
  310. zlevel: this.getZlevelBase(),
  311. z: this.getZBase(),
  312. hoverable: false,
  313. style: {
  314. xStart: xStart,
  315. yStart: yStart,
  316. xEnd: xEnd,
  317. yEnd: yEnd,
  318. lineWidth: lineWidth,
  319. strokeColor: lineColor
  320. }
  321. };
  322. return new LineShape(lineShape);
  323. },
  324. _buildBreadcrumb: function (treeRoot, seriesIndex, x, y) {
  325. var stack = [];
  326. var current = treeRoot;
  327. while (current) {
  328. stack.unshift(current.data.name);
  329. current = current.parent;
  330. }
  331. var series = this.series[seriesIndex];
  332. var textStyle = this.query(series, 'itemStyle.normal.breadcrumb.textStyle') || {};
  333. var textEmphasisStyle = this.query(series, 'itemStyle.emphasis.breadcrumb.textStyle') || {};
  334. var commonStyle = {
  335. y: y + 10,
  336. textBaseline: 'top',
  337. textAlign: 'left',
  338. color: textStyle.color,
  339. textFont: this.getFont(textStyle)
  340. };
  341. var commonHighlightStyle = {
  342. brushType: 'fill',
  343. color: textEmphasisStyle.color || zrColor.lift(textStyle.color, -0.3),
  344. textFont: this.getFont(textEmphasisStyle)
  345. };
  346. for (var i = 0; i < stack.length; i++) {
  347. var textShape = new TextShape({
  348. zlevel: this.getZlevelBase(),
  349. z: this.getZBase(),
  350. style: zrUtil.merge({
  351. x: x,
  352. text: stack[i] + (stack.length - 1 - i ? ' > ' : '')
  353. }, commonStyle),
  354. clickable: true,
  355. highlightStyle: commonHighlightStyle
  356. });
  357. ecData.set(textShape, 'seriesIndex', seriesIndex);
  358. ecData.set(textShape, 'name', stack[i]);
  359. x += textShape.getRect(textShape.style).width;
  360. this.shapeList.push(textShape);
  361. }
  362. },
  363. __onclick: function (params) {
  364. var target = params.target;
  365. if (target) {
  366. var seriesIndex = ecData.get(target, 'seriesIndex');
  367. var name = ecData.get(target, 'name');
  368. var tree = this._treesMap[seriesIndex];
  369. var root = tree.getNodeById(name);
  370. if (root && root.children.length) {
  371. this._buildTreemap(root, seriesIndex);
  372. }
  373. }
  374. }
  375. };
  376. zrUtil.inherits(Treemap, ChartBase);
  377. require('../chart').define('treemap', Treemap);
  378. return Treemap;
  379. });define('echarts/layout/TreeMap', ['require'], function (require) {
  380. function TreeMapLayout(opts) {
  381. var row = {
  382. x: opts.x,
  383. y: opts.y,
  384. width: opts.width,
  385. height: opts.height
  386. };
  387. this.x = opts.x;
  388. this.y = opts.y;
  389. this.width = opts.width;
  390. this.height = opts.height;
  391. }
  392. TreeMapLayout.prototype.run = function (areas) {
  393. var out = [];
  394. this._squarify(areas, {
  395. x: this.x,
  396. y: this.y,
  397. width: this.width,
  398. height: this.height
  399. }, out);
  400. return out;
  401. };
  402. TreeMapLayout.prototype._squarify = function (areas, row, out) {
  403. var layoutDirection = 'VERTICAL';
  404. var width = row.width;
  405. var height = row.height;
  406. if (row.width < row.height) {
  407. layoutDirection = 'HORIZONTAL';
  408. width = row.height;
  409. height = row.width;
  410. }
  411. var shapeArr = this._getShapeListInAbstractRow(areas, width, height);
  412. for (var i = 0; i < shapeArr.length; i++) {
  413. shapeArr[i].x = 0;
  414. shapeArr[i].y = 0;
  415. for (var j = 0; j < i; j++) {
  416. shapeArr[i].y += shapeArr[j].height;
  417. }
  418. }
  419. var nextRow = {};
  420. if (layoutDirection == 'VERTICAL') {
  421. for (var k = 0; k < shapeArr.length; k++) {
  422. out.push({
  423. x: shapeArr[k].x + row.x,
  424. y: shapeArr[k].y + row.y,
  425. width: shapeArr[k].width,
  426. height: shapeArr[k].height
  427. });
  428. }
  429. nextRow = {
  430. x: shapeArr[0].width + row.x,
  431. y: row.y,
  432. width: row.width - shapeArr[0].width,
  433. height: row.height
  434. };
  435. } else {
  436. for (var l = 0; l < shapeArr.length; l++) {
  437. out.push({
  438. x: shapeArr[l].y + row.x,
  439. y: shapeArr[l].x + row.y,
  440. width: shapeArr[l].height,
  441. height: shapeArr[l].width
  442. });
  443. }
  444. nextRow = {
  445. x: row.x,
  446. y: row.y + shapeArr[0].width,
  447. width: row.width,
  448. height: row.height - shapeArr[0].width
  449. };
  450. }
  451. var nextAreaArr = areas.slice(shapeArr.length);
  452. if (nextAreaArr.length === 0) {
  453. return;
  454. } else {
  455. this._squarify(nextAreaArr, nextRow, out);
  456. }
  457. };
  458. TreeMapLayout.prototype._getShapeListInAbstractRow = function (areas, width, height) {
  459. if (areas.length === 1) {
  460. return [{
  461. width: width,
  462. height: height
  463. }];
  464. }
  465. for (var count = 1; count < areas.length; count++) {
  466. var shapeArr0 = this._placeFixedNumberRectangles(areas.slice(0, count), width, height);
  467. var shapeArr1 = this._placeFixedNumberRectangles(areas.slice(0, count + 1), width, height);
  468. if (this._isFirstBetter(shapeArr0, shapeArr1)) {
  469. return shapeArr0;
  470. }
  471. }
  472. };
  473. TreeMapLayout.prototype._placeFixedNumberRectangles = function (areaSubArr, width, height) {
  474. var count = areaSubArr.length;
  475. var shapeArr = [];
  476. var sum = 0;
  477. for (var i = 0; i < areaSubArr.length; i++) {
  478. sum += areaSubArr[i];
  479. }
  480. var cellWidth = sum / height;
  481. for (var j = 0; j < count; j++) {
  482. var cellHeight = height * areaSubArr[j] / sum;
  483. shapeArr.push({
  484. width: cellWidth,
  485. height: cellHeight
  486. });
  487. }
  488. return shapeArr;
  489. };
  490. TreeMapLayout.prototype._isFirstBetter = function (shapeArr0, shapeArr1) {
  491. var ratio0 = shapeArr0[0].height / shapeArr0[0].width;
  492. ratio0 = ratio0 > 1 ? 1 / ratio0 : ratio0;
  493. var ratio1 = shapeArr1[0].height / shapeArr1[0].width;
  494. ratio1 = ratio1 > 1 ? 1 / ratio1 : ratio1;
  495. if (Math.abs(ratio0 - 1) <= Math.abs(ratio1 - 1)) {
  496. return true;
  497. }
  498. return false;
  499. };
  500. return TreeMapLayout;
  501. });define('echarts/data/Tree', [
  502. 'require',
  503. 'zrender/tool/util'
  504. ], function (require) {
  505. var zrUtil = require('zrender/tool/util');
  506. function TreeNode(id, data) {
  507. this.id = id;
  508. this.depth = 0;
  509. this.height = 0;
  510. this.children = [];
  511. this.parent = null;
  512. this.data = data || null;
  513. }
  514. TreeNode.prototype.add = function (child) {
  515. var children = this.children;
  516. if (child.parent === this) {
  517. return;
  518. }
  519. children.push(child);
  520. child.parent = this;
  521. };
  522. TreeNode.prototype.remove = function (child) {
  523. var children = this.children;
  524. var idx = zrUtil.indexOf(children, child);
  525. if (idx >= 0) {
  526. children.splice(idx, 1);
  527. child.parent = null;
  528. }
  529. };
  530. TreeNode.prototype.traverse = function (cb, context) {
  531. cb.call(context, this);
  532. for (var i = 0; i < this.children.length; i++) {
  533. this.children[i].traverse(cb, context);
  534. }
  535. };
  536. TreeNode.prototype.updateDepthAndHeight = function (depth) {
  537. var height = 0;
  538. this.depth = depth;
  539. for (var i = 0; i < this.children.length; i++) {
  540. var child = this.children[i];
  541. child.updateDepthAndHeight(depth + 1);
  542. if (child.height > height) {
  543. height = child.height;
  544. }
  545. }
  546. this.height = height + 1;
  547. };
  548. TreeNode.prototype.getNodeById = function (id) {
  549. if (this.id === id) {
  550. return this;
  551. }
  552. for (var i = 0; i < this.children.length; i++) {
  553. var res = this.children[i].getNodeById(id);
  554. if (res) {
  555. return res;
  556. }
  557. }
  558. };
  559. function Tree(id) {
  560. this.root = new TreeNode(id);
  561. }
  562. Tree.prototype.traverse = function (cb, context) {
  563. this.root.traverse(cb, context);
  564. };
  565. Tree.prototype.getSubTree = function (id) {
  566. var root = this.getNodeById(id);
  567. if (root) {
  568. var tree = new Tree(root.id);
  569. tree.root = root;
  570. return tree;
  571. }
  572. };
  573. Tree.prototype.getNodeById = function (id) {
  574. return this.root.getNodeById(id);
  575. };
  576. Tree.fromOptionData = function (id, data) {
  577. var tree = new Tree(id);
  578. var rootNode = tree.root;
  579. rootNode.data = {
  580. name: id,
  581. children: data
  582. };
  583. function buildHierarchy(dataNode, parentNode) {
  584. var node = new TreeNode(dataNode.name, dataNode);
  585. parentNode.add(node);
  586. var children = dataNode.children;
  587. if (children) {
  588. for (var i = 0; i < children.length; i++) {
  589. buildHierarchy(children[i], node);
  590. }
  591. }
  592. }
  593. for (var i = 0; i < data.length; i++) {
  594. buildHierarchy(data[i], rootNode);
  595. }
  596. tree.root.updateDepthAndHeight(0);
  597. return tree;
  598. };
  599. Tree.fromGraph = function (graph) {
  600. function buildHierarchy(root) {
  601. var graphNode = graph.getNodeById(root.id);
  602. for (var i = 0; i < graphNode.outEdges.length; i++) {
  603. var edge = graphNode.outEdges[i];
  604. var childTreeNode = treeNodesMap[edge.node2.id];
  605. root.children.push(childTreeNode);
  606. buildHierarchy(childTreeNode);
  607. }
  608. }
  609. var treeMap = {};
  610. var treeNodesMap = {};
  611. for (var i = 0; i < graph.nodes.length; i++) {
  612. var node = graph.nodes[i];
  613. var treeNode;
  614. if (node.inDegree() === 0) {
  615. treeMap[node.id] = new Tree(node.id);
  616. treeNode = treeMap[node.id].root;
  617. } else {
  618. treeNode = new TreeNode(node.id);
  619. }
  620. treeNode.data = node.data;
  621. treeNodesMap[node.id] = treeNode;
  622. }
  623. var treeList = [];
  624. for (var id in treeMap) {
  625. buildHierarchy(treeMap[id].root);
  626. treeMap[id].root.updateDepthAndHeight(0);
  627. treeList.push(treeMap[id]);
  628. }
  629. return treeList;
  630. };
  631. return Tree;
  632. });