tree.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. define('echarts/chart/tree', [
  2. 'require',
  3. './base',
  4. '../util/shape/Icon',
  5. 'zrender/shape/Image',
  6. 'zrender/shape/Line',
  7. 'zrender/shape/BezierCurve',
  8. '../layout/Tree',
  9. '../data/Tree',
  10. '../config',
  11. '../util/ecData',
  12. 'zrender/config',
  13. 'zrender/tool/event',
  14. 'zrender/tool/util',
  15. '../chart'
  16. ], function (require) {
  17. var ChartBase = require('./base');
  18. var GOLDEN_SECTION = 0.618;
  19. var IconShape = require('../util/shape/Icon');
  20. var ImageShape = require('zrender/shape/Image');
  21. var LineShape = require('zrender/shape/Line');
  22. var BezierCurveShape = require('zrender/shape/BezierCurve');
  23. var TreeLayout = require('../layout/Tree');
  24. var TreeData = require('../data/Tree');
  25. var ecConfig = require('../config');
  26. ecConfig.tree = {
  27. zlevel: 1,
  28. z: 2,
  29. calculable: false,
  30. clickable: true,
  31. rootLocation: {},
  32. orient: 'vertical',
  33. symbol: 'circle',
  34. symbolSize: 20,
  35. nodePadding: 30,
  36. layerPadding: 100,
  37. itemStyle: {
  38. normal: {
  39. label: { show: true },
  40. lineStyle: {
  41. width: 1,
  42. color: '#777',
  43. type: 'curve'
  44. }
  45. },
  46. emphasis: {}
  47. }
  48. };
  49. var ecData = require('../util/ecData');
  50. var zrConfig = require('zrender/config');
  51. var zrEvent = require('zrender/tool/event');
  52. var zrUtil = require('zrender/tool/util');
  53. function Tree(ecTheme, messageCenter, zr, option, myChart) {
  54. ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
  55. this.refresh(option);
  56. }
  57. Tree.prototype = {
  58. type: ecConfig.CHART_TYPE_TREE,
  59. _buildShape: function (series, seriesIndex) {
  60. var data = series.data[0];
  61. this.tree = TreeData.fromOptionData(data.name, data.children);
  62. this.tree.root.data = data;
  63. this._setTreeShape(series);
  64. this.tree.traverse(function (treeNode) {
  65. this._buildItem(treeNode, series, seriesIndex);
  66. if (treeNode.children.length > 0) {
  67. this._buildLink(treeNode, series);
  68. }
  69. }, this);
  70. var panable = series.roam === true || series.roam === 'move';
  71. var zoomable = series.roam === true || series.roam === 'scale';
  72. this.zr.modLayer(this.getZlevelBase(), {
  73. panable: panable,
  74. zoomable: zoomable
  75. });
  76. if (this.query('markPoint.effect.show') || this.query('markLine.effect.show')) {
  77. this.zr.modLayer(ecConfig.EFFECT_ZLEVEL, {
  78. panable: panable,
  79. zoomable: zoomable
  80. });
  81. }
  82. this.addShapeList();
  83. },
  84. _buildItem: function (treeNode, serie, seriesIndex) {
  85. var queryTarget = [
  86. treeNode.data,
  87. serie
  88. ];
  89. var symbol = this.deepQuery(queryTarget, 'symbol');
  90. var normal = this.deepMerge(queryTarget, 'itemStyle.normal') || {};
  91. var emphasis = this.deepMerge(queryTarget, 'itemStyle.emphasis') || {};
  92. var normalColor = normal.color || this.zr.getColor();
  93. var emphasisColor = emphasis.color || this.zr.getColor();
  94. var angle = -treeNode.layout.angle || 0;
  95. if (treeNode.id === this.tree.root.id) {
  96. angle = 0;
  97. }
  98. var textPosition = 'right';
  99. if (Math.abs(angle) >= Math.PI / 2 && Math.abs(angle) < Math.PI * 3 / 2) {
  100. angle += Math.PI;
  101. textPosition = 'left';
  102. }
  103. var rotation = [
  104. angle,
  105. treeNode.layout.position[0],
  106. treeNode.layout.position[1]
  107. ];
  108. var shape = new IconShape({
  109. zlevel: this.getZlevelBase(),
  110. z: this.getZBase() + 1,
  111. rotation: rotation,
  112. clickable: this.deepQuery(queryTarget, 'clickable'),
  113. style: {
  114. x: treeNode.layout.position[0] - treeNode.layout.width * 0.5,
  115. y: treeNode.layout.position[1] - treeNode.layout.height * 0.5,
  116. width: treeNode.layout.width,
  117. height: treeNode.layout.height,
  118. iconType: symbol,
  119. color: normalColor,
  120. brushType: 'both',
  121. lineWidth: normal.borderWidth,
  122. strokeColor: normal.borderColor
  123. },
  124. highlightStyle: {
  125. color: emphasisColor,
  126. lineWidth: emphasis.borderWidth,
  127. strokeColor: emphasis.borderColor
  128. }
  129. });
  130. if (shape.style.iconType.match('image')) {
  131. shape.style.image = shape.style.iconType.replace(new RegExp('^image:\\/\\/'), '');
  132. shape = new ImageShape({
  133. rotation: rotation,
  134. style: shape.style,
  135. highlightStyle: shape.highlightStyle,
  136. clickable: shape.clickable,
  137. zlevel: this.getZlevelBase(),
  138. z: this.getZBase()
  139. });
  140. }
  141. if (this.deepQuery(queryTarget, 'itemStyle.normal.label.show')) {
  142. shape.style.text = treeNode.data.label == null ? treeNode.id : treeNode.data.label;
  143. shape.style.textPosition = this.deepQuery(queryTarget, 'itemStyle.normal.label.position');
  144. if (serie.orient === 'radial' && shape.style.textPosition !== 'inside') {
  145. shape.style.textPosition = textPosition;
  146. }
  147. shape.style.textColor = this.deepQuery(queryTarget, 'itemStyle.normal.label.textStyle.color');
  148. shape.style.textFont = this.getFont(this.deepQuery(queryTarget, 'itemStyle.normal.label.textStyle') || {});
  149. }
  150. if (this.deepQuery(queryTarget, 'itemStyle.emphasis.label.show')) {
  151. shape.highlightStyle.textPosition = this.deepQuery(queryTarget, 'itemStyle.emphasis.label.position');
  152. shape.highlightStyle.textColor = this.deepQuery(queryTarget, 'itemStyle.emphasis.label.textStyle.color');
  153. shape.highlightStyle.textFont = this.getFont(this.deepQuery(queryTarget, 'itemStyle.emphasis.label.textStyle') || {});
  154. }
  155. ecData.pack(shape, serie, seriesIndex, treeNode.data, 0, treeNode.id);
  156. this.shapeList.push(shape);
  157. },
  158. _buildLink: function (parentNode, serie) {
  159. var lineStyle = serie.itemStyle.normal.lineStyle;
  160. if (lineStyle.type === 'broken') {
  161. this._buildBrokenLine(parentNode, lineStyle, serie);
  162. return;
  163. }
  164. for (var i = 0; i < parentNode.children.length; i++) {
  165. var xStart = parentNode.layout.position[0];
  166. var yStart = parentNode.layout.position[1];
  167. var xEnd = parentNode.children[i].layout.position[0];
  168. var yEnd = parentNode.children[i].layout.position[1];
  169. switch (lineStyle.type) {
  170. case 'curve':
  171. this._buildBezierCurve(parentNode, parentNode.children[i], lineStyle, serie);
  172. break;
  173. case 'broken':
  174. break;
  175. default:
  176. var shape = this._getLine(xStart, yStart, xEnd, yEnd, lineStyle);
  177. this.shapeList.push(shape);
  178. }
  179. }
  180. },
  181. _buildBrokenLine: function (parentNode, lineStyle, serie) {
  182. var solidLineStyle = zrUtil.clone(lineStyle);
  183. solidLineStyle.type = 'solid';
  184. var shapes = [];
  185. var xStart = parentNode.layout.position[0];
  186. var yStart = parentNode.layout.position[1];
  187. var orient = serie.orient;
  188. var yEnd = parentNode.children[0].layout.position[1];
  189. var xMiddle = xStart;
  190. var yMiddle = yStart + (yEnd - yStart) * (1 - GOLDEN_SECTION);
  191. var xMiddleStart = parentNode.children[0].layout.position[0];
  192. var yMiddleStart = yMiddle;
  193. var xMiddleEnd = parentNode.children[parentNode.children.length - 1].layout.position[0];
  194. var yMiddleEnd = yMiddle;
  195. if (orient === 'horizontal') {
  196. var xEnd = parentNode.children[0].layout.position[0];
  197. xMiddle = xStart + (xEnd - xStart) * (1 - GOLDEN_SECTION);
  198. yMiddle = yStart;
  199. xMiddleStart = xMiddle;
  200. yMiddleStart = parentNode.children[0].layout.position[1];
  201. xMiddleEnd = xMiddle;
  202. yMiddleEnd = parentNode.children[parentNode.children.length - 1].layout.position[1];
  203. }
  204. shapes.push(this._getLine(xStart, yStart, xMiddle, yMiddle, solidLineStyle));
  205. shapes.push(this._getLine(xMiddleStart, yMiddleStart, xMiddleEnd, yMiddleEnd, solidLineStyle));
  206. for (var i = 0; i < parentNode.children.length; i++) {
  207. xEnd = parentNode.children[i].layout.position[0];
  208. yEnd = parentNode.children[i].layout.position[1];
  209. if (orient === 'horizontal') {
  210. yMiddleStart = yEnd;
  211. } else {
  212. xMiddleStart = xEnd;
  213. }
  214. shapes.push(this._getLine(xMiddleStart, yMiddleStart, xEnd, yEnd, solidLineStyle));
  215. }
  216. this.shapeList = this.shapeList.concat(shapes);
  217. },
  218. _getLine: function (xStart, yStart, xEnd, yEnd, lineStyle) {
  219. if (xStart === xEnd) {
  220. xStart = xEnd = this.subPixelOptimize(xStart, lineStyle.width);
  221. }
  222. if (yStart === yEnd) {
  223. yStart = yEnd = this.subPixelOptimize(yStart, lineStyle.width);
  224. }
  225. return new LineShape({
  226. zlevel: this.getZlevelBase(),
  227. hoverable: false,
  228. style: zrUtil.merge({
  229. xStart: xStart,
  230. yStart: yStart,
  231. xEnd: xEnd,
  232. yEnd: yEnd,
  233. lineType: lineStyle.type,
  234. strokeColor: lineStyle.color,
  235. lineWidth: lineStyle.width
  236. }, lineStyle, true)
  237. });
  238. },
  239. _buildBezierCurve: function (parentNode, treeNode, lineStyle, serie) {
  240. var offsetRatio = GOLDEN_SECTION;
  241. var orient = serie.orient;
  242. var xStart = parentNode.layout.position[0];
  243. var yStart = parentNode.layout.position[1];
  244. var xEnd = treeNode.layout.position[0];
  245. var yEnd = treeNode.layout.position[1];
  246. var cpX1 = xStart;
  247. var cpY1 = (yEnd - yStart) * offsetRatio + yStart;
  248. var cpX2 = xEnd;
  249. var cpY2 = (yEnd - yStart) * (1 - offsetRatio) + yStart;
  250. if (orient === 'horizontal') {
  251. cpX1 = (xEnd - xStart) * offsetRatio + xStart;
  252. cpY1 = yStart;
  253. cpX2 = (xEnd - xStart) * (1 - offsetRatio) + xStart;
  254. cpY2 = yEnd;
  255. } else if (orient === 'radial') {
  256. if (parentNode.id === this.tree.root.id) {
  257. cpX1 = (xEnd - xStart) * offsetRatio + xStart;
  258. cpY1 = (yEnd - yStart) * offsetRatio + yStart;
  259. cpX2 = (xEnd - xStart) * (1 - offsetRatio) + xStart;
  260. cpY2 = (yEnd - yStart) * (1 - offsetRatio) + yStart;
  261. } else {
  262. var xStartOrigin = parentNode.layout.originPosition[0];
  263. var yStartOrigin = parentNode.layout.originPosition[1];
  264. var xEndOrigin = treeNode.layout.originPosition[0];
  265. var yEndOrigin = treeNode.layout.originPosition[1];
  266. var rootX = this.tree.root.layout.position[0];
  267. var rootY = this.tree.root.layout.position[1];
  268. cpX1 = xStartOrigin;
  269. cpY1 = (yEndOrigin - yStartOrigin) * offsetRatio + yStartOrigin;
  270. cpX2 = xEndOrigin;
  271. cpY2 = (yEndOrigin - yStartOrigin) * (1 - offsetRatio) + yStartOrigin;
  272. var rad = (cpX1 - this.minX) / this.width * Math.PI * 2;
  273. cpX1 = cpY1 * Math.cos(rad) + rootX;
  274. cpY1 = cpY1 * Math.sin(rad) + rootY;
  275. rad = (cpX2 - this.minX) / this.width * Math.PI * 2;
  276. cpX2 = cpY2 * Math.cos(rad) + rootX;
  277. cpY2 = cpY2 * Math.sin(rad) + rootY;
  278. }
  279. }
  280. var shape = new BezierCurveShape({
  281. zlevel: this.getZlevelBase(),
  282. hoverable: false,
  283. style: zrUtil.merge({
  284. xStart: xStart,
  285. yStart: yStart,
  286. cpX1: cpX1,
  287. cpY1: cpY1,
  288. cpX2: cpX2,
  289. cpY2: cpY2,
  290. xEnd: xEnd,
  291. yEnd: yEnd,
  292. strokeColor: lineStyle.color,
  293. lineWidth: lineStyle.width
  294. }, lineStyle, true)
  295. });
  296. this.shapeList.push(shape);
  297. },
  298. _setTreeShape: function (serie) {
  299. var treeLayout = new TreeLayout({
  300. nodePadding: serie.nodePadding,
  301. layerPadding: serie.layerPadding
  302. });
  303. this.tree.traverse(function (treeNode) {
  304. var queryTarget = [
  305. treeNode.data,
  306. serie
  307. ];
  308. var symbolSize = this.deepQuery(queryTarget, 'symbolSize');
  309. if (typeof symbolSize === 'number') {
  310. symbolSize = [
  311. symbolSize,
  312. symbolSize
  313. ];
  314. }
  315. treeNode.layout = {
  316. width: symbolSize[0],
  317. height: symbolSize[1]
  318. };
  319. }, this);
  320. treeLayout.run(this.tree);
  321. var orient = serie.orient;
  322. var rootX = serie.rootLocation.x;
  323. var rootY = serie.rootLocation.y;
  324. var zrWidth = this.zr.getWidth();
  325. var zrHeight = this.zr.getHeight();
  326. if (rootX === 'center') {
  327. rootX = zrWidth * 0.5;
  328. } else {
  329. rootX = this.parsePercent(rootX, zrWidth);
  330. }
  331. if (rootY === 'center') {
  332. rootY = zrHeight * 0.5;
  333. } else {
  334. rootY = this.parsePercent(rootY, zrHeight);
  335. }
  336. rootY = this.parsePercent(rootY, zrHeight);
  337. if (orient === 'horizontal') {
  338. rootX = isNaN(rootX) ? 10 : rootX;
  339. rootY = isNaN(rootY) ? zrHeight * 0.5 : rootY;
  340. }
  341. if (orient === 'radial') {
  342. rootX = isNaN(rootX) ? zrWidth * 0.5 : rootX;
  343. rootY = isNaN(rootY) ? zrHeight * 0.5 : rootY;
  344. } else {
  345. rootX = isNaN(rootX) ? zrWidth * 0.5 : rootX;
  346. rootY = isNaN(rootY) ? 10 : rootY;
  347. }
  348. var originRootX = this.tree.root.layout.position[0];
  349. if (orient === 'radial') {
  350. var minX = Infinity;
  351. var maxX = 0;
  352. var maxWidth = 0;
  353. this.tree.traverse(function (treeNode) {
  354. maxX = Math.max(maxX, treeNode.layout.position[0]);
  355. minX = Math.min(minX, treeNode.layout.position[0]);
  356. maxWidth = Math.max(maxWidth, treeNode.layout.width);
  357. });
  358. this.width = maxX - minX + 2 * maxWidth;
  359. this.minX = minX;
  360. }
  361. this.tree.traverse(function (treeNode) {
  362. var x;
  363. var y;
  364. if (orient === 'vertical' && serie.direction === 'inverse') {
  365. x = treeNode.layout.position[0] - originRootX + rootX;
  366. y = rootY - treeNode.layout.position[1];
  367. } else if (orient === 'vertical') {
  368. x = treeNode.layout.position[0] - originRootX + rootX;
  369. y = treeNode.layout.position[1] + rootY;
  370. } else if (orient === 'horizontal' && serie.direction === 'inverse') {
  371. y = treeNode.layout.position[0] - originRootX + rootY;
  372. x = rootX - treeNode.layout.position[1];
  373. } else if (orient === 'horizontal') {
  374. y = treeNode.layout.position[0] - originRootX + rootY;
  375. x = treeNode.layout.position[1] + rootX;
  376. } else {
  377. x = treeNode.layout.position[0];
  378. y = treeNode.layout.position[1];
  379. treeNode.layout.originPosition = [
  380. x,
  381. y
  382. ];
  383. var r = y;
  384. var angle = (x - minX) / this.width * Math.PI * 2;
  385. x = r * Math.cos(angle) + rootX;
  386. y = r * Math.sin(angle) + rootY;
  387. treeNode.layout.angle = angle;
  388. }
  389. treeNode.layout.position[0] = x;
  390. treeNode.layout.position[1] = y;
  391. }, this);
  392. },
  393. refresh: function (newOption) {
  394. this.clear();
  395. if (newOption) {
  396. this.option = newOption;
  397. this.series = this.option.series;
  398. }
  399. var series = this.series;
  400. var legend = this.component.legend;
  401. for (var i = 0; i < series.length; i++) {
  402. if (series[i].type === ecConfig.CHART_TYPE_TREE) {
  403. series[i] = this.reformOption(series[i]);
  404. var seriesName = series[i].name || '';
  405. this.selectedMap[seriesName] = legend ? legend.isSelected(seriesName) : true;
  406. if (!this.selectedMap[seriesName]) {
  407. continue;
  408. }
  409. this._buildSeries(series[i], i);
  410. }
  411. }
  412. },
  413. _buildSeries: function (series, seriesIndex) {
  414. this._buildShape(series, seriesIndex);
  415. }
  416. };
  417. zrUtil.inherits(Tree, ChartBase);
  418. require('../chart').define('tree', Tree);
  419. return Tree;
  420. });define('echarts/layout/Tree', [
  421. 'require',
  422. 'zrender/tool/vector'
  423. ], function (require) {
  424. var vec2 = require('zrender/tool/vector');
  425. function TreeLayout(opts) {
  426. opts = opts || {};
  427. this.nodePadding = opts.nodePadding || 30;
  428. this.layerPadding = opts.layerPadding || 100;
  429. this._layerOffsets = [];
  430. this._layers = [];
  431. }
  432. TreeLayout.prototype.run = function (tree) {
  433. this._layerOffsets.length = 0;
  434. for (var i = 0; i < tree.root.height + 1; i++) {
  435. this._layerOffsets[i] = 0;
  436. this._layers[i] = [];
  437. }
  438. this._updateNodeXPosition(tree.root);
  439. var root = tree.root;
  440. this._updateNodeYPosition(root, 0, root.layout.height);
  441. };
  442. TreeLayout.prototype._updateNodeXPosition = function (node) {
  443. var minX = Infinity;
  444. var maxX = -Infinity;
  445. node.layout.position = node.layout.position || vec2.create();
  446. for (var i = 0; i < node.children.length; i++) {
  447. var child = node.children[i];
  448. this._updateNodeXPosition(child);
  449. var x = child.layout.position[0];
  450. if (x < minX) {
  451. minX = x;
  452. }
  453. if (x > maxX) {
  454. maxX = x;
  455. }
  456. }
  457. if (node.children.length > 0) {
  458. node.layout.position[0] = (minX + maxX) / 2;
  459. } else {
  460. node.layout.position[0] = 0;
  461. }
  462. var off = this._layerOffsets[node.depth] || 0;
  463. if (off > node.layout.position[0]) {
  464. var shift = off - node.layout.position[0];
  465. this._shiftSubtree(node, shift);
  466. for (var i = node.depth + 1; i < node.height + node.depth; i++) {
  467. this._layerOffsets[i] += shift;
  468. }
  469. }
  470. this._layerOffsets[node.depth] = node.layout.position[0] + node.layout.width + this.nodePadding;
  471. this._layers[node.depth].push(node);
  472. };
  473. TreeLayout.prototype._shiftSubtree = function (root, offset) {
  474. root.layout.position[0] += offset;
  475. for (var i = 0; i < root.children.length; i++) {
  476. this._shiftSubtree(root.children[i], offset);
  477. }
  478. };
  479. TreeLayout.prototype._updateNodeYPosition = function (node, y, prevLayerHeight) {
  480. node.layout.position[1] = y;
  481. var layerHeight = 0;
  482. for (var i = 0; i < node.children.length; i++) {
  483. layerHeight = Math.max(node.children[i].layout.height, layerHeight);
  484. }
  485. var layerPadding = this.layerPadding;
  486. if (typeof layerPadding === 'function') {
  487. layerPadding = layerPadding(node.depth);
  488. }
  489. for (var i = 0; i < node.children.length; i++) {
  490. this._updateNodeYPosition(node.children[i], y + layerPadding + prevLayerHeight, layerHeight);
  491. }
  492. };
  493. return TreeLayout;
  494. });define('echarts/data/Tree', [
  495. 'require',
  496. 'zrender/tool/util'
  497. ], function (require) {
  498. var zrUtil = require('zrender/tool/util');
  499. function TreeNode(id, data) {
  500. this.id = id;
  501. this.depth = 0;
  502. this.height = 0;
  503. this.children = [];
  504. this.parent = null;
  505. this.data = data || null;
  506. }
  507. TreeNode.prototype.add = function (child) {
  508. var children = this.children;
  509. if (child.parent === this) {
  510. return;
  511. }
  512. children.push(child);
  513. child.parent = this;
  514. };
  515. TreeNode.prototype.remove = function (child) {
  516. var children = this.children;
  517. var idx = zrUtil.indexOf(children, child);
  518. if (idx >= 0) {
  519. children.splice(idx, 1);
  520. child.parent = null;
  521. }
  522. };
  523. TreeNode.prototype.traverse = function (cb, context) {
  524. cb.call(context, this);
  525. for (var i = 0; i < this.children.length; i++) {
  526. this.children[i].traverse(cb, context);
  527. }
  528. };
  529. TreeNode.prototype.updateDepthAndHeight = function (depth) {
  530. var height = 0;
  531. this.depth = depth;
  532. for (var i = 0; i < this.children.length; i++) {
  533. var child = this.children[i];
  534. child.updateDepthAndHeight(depth + 1);
  535. if (child.height > height) {
  536. height = child.height;
  537. }
  538. }
  539. this.height = height + 1;
  540. };
  541. TreeNode.prototype.getNodeById = function (id) {
  542. if (this.id === id) {
  543. return this;
  544. }
  545. for (var i = 0; i < this.children.length; i++) {
  546. var res = this.children[i].getNodeById(id);
  547. if (res) {
  548. return res;
  549. }
  550. }
  551. };
  552. function Tree(id) {
  553. this.root = new TreeNode(id);
  554. }
  555. Tree.prototype.traverse = function (cb, context) {
  556. this.root.traverse(cb, context);
  557. };
  558. Tree.prototype.getSubTree = function (id) {
  559. var root = this.getNodeById(id);
  560. if (root) {
  561. var tree = new Tree(root.id);
  562. tree.root = root;
  563. return tree;
  564. }
  565. };
  566. Tree.prototype.getNodeById = function (id) {
  567. return this.root.getNodeById(id);
  568. };
  569. Tree.fromOptionData = function (id, data) {
  570. var tree = new Tree(id);
  571. var rootNode = tree.root;
  572. rootNode.data = {
  573. name: id,
  574. children: data
  575. };
  576. function buildHierarchy(dataNode, parentNode) {
  577. var node = new TreeNode(dataNode.name, dataNode);
  578. parentNode.add(node);
  579. var children = dataNode.children;
  580. if (children) {
  581. for (var i = 0; i < children.length; i++) {
  582. buildHierarchy(children[i], node);
  583. }
  584. }
  585. }
  586. for (var i = 0; i < data.length; i++) {
  587. buildHierarchy(data[i], rootNode);
  588. }
  589. tree.root.updateDepthAndHeight(0);
  590. return tree;
  591. };
  592. Tree.fromGraph = function (graph) {
  593. function buildHierarchy(root) {
  594. var graphNode = graph.getNodeById(root.id);
  595. for (var i = 0; i < graphNode.outEdges.length; i++) {
  596. var edge = graphNode.outEdges[i];
  597. var childTreeNode = treeNodesMap[edge.node2.id];
  598. root.children.push(childTreeNode);
  599. buildHierarchy(childTreeNode);
  600. }
  601. }
  602. var treeMap = {};
  603. var treeNodesMap = {};
  604. for (var i = 0; i < graph.nodes.length; i++) {
  605. var node = graph.nodes[i];
  606. var treeNode;
  607. if (node.inDegree() === 0) {
  608. treeMap[node.id] = new Tree(node.id);
  609. treeNode = treeMap[node.id].root;
  610. } else {
  611. treeNode = new TreeNode(node.id);
  612. }
  613. treeNode.data = node.data;
  614. treeNodesMap[node.id] = treeNode;
  615. }
  616. var treeList = [];
  617. for (var id in treeMap) {
  618. buildHierarchy(treeMap[id].root);
  619. treeMap[id].root.updateDepthAndHeight(0);
  620. treeList.push(treeMap[id]);
  621. }
  622. return treeList;
  623. };
  624. return Tree;
  625. });