625 lines
25 KiB
JavaScript
625 lines
25 KiB
JavaScript
define('echarts/chart/tree', [
|
|
'require',
|
|
'./base',
|
|
'../util/shape/Icon',
|
|
'zrender/shape/Image',
|
|
'zrender/shape/Line',
|
|
'zrender/shape/BezierCurve',
|
|
'../layout/Tree',
|
|
'../data/Tree',
|
|
'../config',
|
|
'../util/ecData',
|
|
'zrender/config',
|
|
'zrender/tool/event',
|
|
'zrender/tool/util',
|
|
'../chart'
|
|
], function (require) {
|
|
var ChartBase = require('./base');
|
|
var GOLDEN_SECTION = 0.618;
|
|
var IconShape = require('../util/shape/Icon');
|
|
var ImageShape = require('zrender/shape/Image');
|
|
var LineShape = require('zrender/shape/Line');
|
|
var BezierCurveShape = require('zrender/shape/BezierCurve');
|
|
var TreeLayout = require('../layout/Tree');
|
|
var TreeData = require('../data/Tree');
|
|
var ecConfig = require('../config');
|
|
ecConfig.tree = {
|
|
zlevel: 1,
|
|
z: 2,
|
|
calculable: false,
|
|
clickable: true,
|
|
rootLocation: {},
|
|
orient: 'vertical',
|
|
symbol: 'circle',
|
|
symbolSize: 20,
|
|
nodePadding: 30,
|
|
layerPadding: 100,
|
|
itemStyle: {
|
|
normal: {
|
|
label: { show: true },
|
|
lineStyle: {
|
|
width: 1,
|
|
color: '#777',
|
|
type: 'curve'
|
|
}
|
|
},
|
|
emphasis: {}
|
|
}
|
|
};
|
|
var ecData = require('../util/ecData');
|
|
var zrConfig = require('zrender/config');
|
|
var zrEvent = require('zrender/tool/event');
|
|
var zrUtil = require('zrender/tool/util');
|
|
function Tree(ecTheme, messageCenter, zr, option, myChart) {
|
|
ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
|
|
this.refresh(option);
|
|
}
|
|
Tree.prototype = {
|
|
type: ecConfig.CHART_TYPE_TREE,
|
|
_buildShape: function (series, seriesIndex) {
|
|
var data = series.data[0];
|
|
this.tree = TreeData.fromOptionData(data.name, data.children);
|
|
this.tree.root.data = data;
|
|
this._setTreeShape(series);
|
|
this.tree.traverse(function (treeNode) {
|
|
this._buildItem(treeNode, series, seriesIndex);
|
|
if (treeNode.children.length > 0) {
|
|
this._buildLink(treeNode, series);
|
|
}
|
|
}, this);
|
|
var panable = series.roam === true || series.roam === 'move';
|
|
var zoomable = series.roam === true || series.roam === 'scale';
|
|
this.zr.modLayer(this.getZlevelBase(), {
|
|
panable: panable,
|
|
zoomable: zoomable
|
|
});
|
|
if (this.query('markPoint.effect.show') || this.query('markLine.effect.show')) {
|
|
this.zr.modLayer(ecConfig.EFFECT_ZLEVEL, {
|
|
panable: panable,
|
|
zoomable: zoomable
|
|
});
|
|
}
|
|
this.addShapeList();
|
|
},
|
|
_buildItem: function (treeNode, serie, seriesIndex) {
|
|
var queryTarget = [
|
|
treeNode.data,
|
|
serie
|
|
];
|
|
var symbol = this.deepQuery(queryTarget, 'symbol');
|
|
var normal = this.deepMerge(queryTarget, 'itemStyle.normal') || {};
|
|
var emphasis = this.deepMerge(queryTarget, 'itemStyle.emphasis') || {};
|
|
var normalColor = normal.color || this.zr.getColor();
|
|
var emphasisColor = emphasis.color || this.zr.getColor();
|
|
var angle = -treeNode.layout.angle || 0;
|
|
if (treeNode.id === this.tree.root.id) {
|
|
angle = 0;
|
|
}
|
|
var textPosition = 'right';
|
|
if (Math.abs(angle) >= Math.PI / 2 && Math.abs(angle) < Math.PI * 3 / 2) {
|
|
angle += Math.PI;
|
|
textPosition = 'left';
|
|
}
|
|
var rotation = [
|
|
angle,
|
|
treeNode.layout.position[0],
|
|
treeNode.layout.position[1]
|
|
];
|
|
var shape = new IconShape({
|
|
zlevel: this.getZlevelBase(),
|
|
z: this.getZBase() + 1,
|
|
rotation: rotation,
|
|
clickable: this.deepQuery(queryTarget, 'clickable'),
|
|
style: {
|
|
x: treeNode.layout.position[0] - treeNode.layout.width * 0.5,
|
|
y: treeNode.layout.position[1] - treeNode.layout.height * 0.5,
|
|
width: treeNode.layout.width,
|
|
height: treeNode.layout.height,
|
|
iconType: symbol,
|
|
color: normalColor,
|
|
brushType: 'both',
|
|
lineWidth: normal.borderWidth,
|
|
strokeColor: normal.borderColor
|
|
},
|
|
highlightStyle: {
|
|
color: emphasisColor,
|
|
lineWidth: emphasis.borderWidth,
|
|
strokeColor: emphasis.borderColor
|
|
}
|
|
});
|
|
if (shape.style.iconType.match('image')) {
|
|
shape.style.image = shape.style.iconType.replace(new RegExp('^image:\\/\\/'), '');
|
|
shape = new ImageShape({
|
|
rotation: rotation,
|
|
style: shape.style,
|
|
highlightStyle: shape.highlightStyle,
|
|
clickable: shape.clickable,
|
|
zlevel: this.getZlevelBase(),
|
|
z: this.getZBase()
|
|
});
|
|
}
|
|
if (this.deepQuery(queryTarget, 'itemStyle.normal.label.show')) {
|
|
shape.style.text = treeNode.data.label == null ? treeNode.id : treeNode.data.label;
|
|
shape.style.textPosition = this.deepQuery(queryTarget, 'itemStyle.normal.label.position');
|
|
if (serie.orient === 'radial' && shape.style.textPosition !== 'inside') {
|
|
shape.style.textPosition = textPosition;
|
|
}
|
|
shape.style.textColor = this.deepQuery(queryTarget, 'itemStyle.normal.label.textStyle.color');
|
|
shape.style.textFont = this.getFont(this.deepQuery(queryTarget, 'itemStyle.normal.label.textStyle') || {});
|
|
}
|
|
if (this.deepQuery(queryTarget, 'itemStyle.emphasis.label.show')) {
|
|
shape.highlightStyle.textPosition = this.deepQuery(queryTarget, 'itemStyle.emphasis.label.position');
|
|
shape.highlightStyle.textColor = this.deepQuery(queryTarget, 'itemStyle.emphasis.label.textStyle.color');
|
|
shape.highlightStyle.textFont = this.getFont(this.deepQuery(queryTarget, 'itemStyle.emphasis.label.textStyle') || {});
|
|
}
|
|
ecData.pack(shape, serie, seriesIndex, treeNode.data, 0, treeNode.id);
|
|
this.shapeList.push(shape);
|
|
},
|
|
_buildLink: function (parentNode, serie) {
|
|
var lineStyle = serie.itemStyle.normal.lineStyle;
|
|
if (lineStyle.type === 'broken') {
|
|
this._buildBrokenLine(parentNode, lineStyle, serie);
|
|
return;
|
|
}
|
|
for (var i = 0; i < parentNode.children.length; i++) {
|
|
var xStart = parentNode.layout.position[0];
|
|
var yStart = parentNode.layout.position[1];
|
|
var xEnd = parentNode.children[i].layout.position[0];
|
|
var yEnd = parentNode.children[i].layout.position[1];
|
|
switch (lineStyle.type) {
|
|
case 'curve':
|
|
this._buildBezierCurve(parentNode, parentNode.children[i], lineStyle, serie);
|
|
break;
|
|
case 'broken':
|
|
break;
|
|
default:
|
|
var shape = this._getLine(xStart, yStart, xEnd, yEnd, lineStyle);
|
|
this.shapeList.push(shape);
|
|
}
|
|
}
|
|
},
|
|
_buildBrokenLine: function (parentNode, lineStyle, serie) {
|
|
var solidLineStyle = zrUtil.clone(lineStyle);
|
|
solidLineStyle.type = 'solid';
|
|
var shapes = [];
|
|
var xStart = parentNode.layout.position[0];
|
|
var yStart = parentNode.layout.position[1];
|
|
var orient = serie.orient;
|
|
var yEnd = parentNode.children[0].layout.position[1];
|
|
var xMiddle = xStart;
|
|
var yMiddle = yStart + (yEnd - yStart) * (1 - GOLDEN_SECTION);
|
|
var xMiddleStart = parentNode.children[0].layout.position[0];
|
|
var yMiddleStart = yMiddle;
|
|
var xMiddleEnd = parentNode.children[parentNode.children.length - 1].layout.position[0];
|
|
var yMiddleEnd = yMiddle;
|
|
if (orient === 'horizontal') {
|
|
var xEnd = parentNode.children[0].layout.position[0];
|
|
xMiddle = xStart + (xEnd - xStart) * (1 - GOLDEN_SECTION);
|
|
yMiddle = yStart;
|
|
xMiddleStart = xMiddle;
|
|
yMiddleStart = parentNode.children[0].layout.position[1];
|
|
xMiddleEnd = xMiddle;
|
|
yMiddleEnd = parentNode.children[parentNode.children.length - 1].layout.position[1];
|
|
}
|
|
shapes.push(this._getLine(xStart, yStart, xMiddle, yMiddle, solidLineStyle));
|
|
shapes.push(this._getLine(xMiddleStart, yMiddleStart, xMiddleEnd, yMiddleEnd, solidLineStyle));
|
|
for (var i = 0; i < parentNode.children.length; i++) {
|
|
xEnd = parentNode.children[i].layout.position[0];
|
|
yEnd = parentNode.children[i].layout.position[1];
|
|
if (orient === 'horizontal') {
|
|
yMiddleStart = yEnd;
|
|
} else {
|
|
xMiddleStart = xEnd;
|
|
}
|
|
shapes.push(this._getLine(xMiddleStart, yMiddleStart, xEnd, yEnd, solidLineStyle));
|
|
}
|
|
this.shapeList = this.shapeList.concat(shapes);
|
|
},
|
|
_getLine: function (xStart, yStart, xEnd, yEnd, lineStyle) {
|
|
if (xStart === xEnd) {
|
|
xStart = xEnd = this.subPixelOptimize(xStart, lineStyle.width);
|
|
}
|
|
if (yStart === yEnd) {
|
|
yStart = yEnd = this.subPixelOptimize(yStart, lineStyle.width);
|
|
}
|
|
return new LineShape({
|
|
zlevel: this.getZlevelBase(),
|
|
hoverable: false,
|
|
style: zrUtil.merge({
|
|
xStart: xStart,
|
|
yStart: yStart,
|
|
xEnd: xEnd,
|
|
yEnd: yEnd,
|
|
lineType: lineStyle.type,
|
|
strokeColor: lineStyle.color,
|
|
lineWidth: lineStyle.width
|
|
}, lineStyle, true)
|
|
});
|
|
},
|
|
_buildBezierCurve: function (parentNode, treeNode, lineStyle, serie) {
|
|
var offsetRatio = GOLDEN_SECTION;
|
|
var orient = serie.orient;
|
|
var xStart = parentNode.layout.position[0];
|
|
var yStart = parentNode.layout.position[1];
|
|
var xEnd = treeNode.layout.position[0];
|
|
var yEnd = treeNode.layout.position[1];
|
|
var cpX1 = xStart;
|
|
var cpY1 = (yEnd - yStart) * offsetRatio + yStart;
|
|
var cpX2 = xEnd;
|
|
var cpY2 = (yEnd - yStart) * (1 - offsetRatio) + yStart;
|
|
if (orient === 'horizontal') {
|
|
cpX1 = (xEnd - xStart) * offsetRatio + xStart;
|
|
cpY1 = yStart;
|
|
cpX2 = (xEnd - xStart) * (1 - offsetRatio) + xStart;
|
|
cpY2 = yEnd;
|
|
} else if (orient === 'radial') {
|
|
if (parentNode.id === this.tree.root.id) {
|
|
cpX1 = (xEnd - xStart) * offsetRatio + xStart;
|
|
cpY1 = (yEnd - yStart) * offsetRatio + yStart;
|
|
cpX2 = (xEnd - xStart) * (1 - offsetRatio) + xStart;
|
|
cpY2 = (yEnd - yStart) * (1 - offsetRatio) + yStart;
|
|
} else {
|
|
var xStartOrigin = parentNode.layout.originPosition[0];
|
|
var yStartOrigin = parentNode.layout.originPosition[1];
|
|
var xEndOrigin = treeNode.layout.originPosition[0];
|
|
var yEndOrigin = treeNode.layout.originPosition[1];
|
|
var rootX = this.tree.root.layout.position[0];
|
|
var rootY = this.tree.root.layout.position[1];
|
|
cpX1 = xStartOrigin;
|
|
cpY1 = (yEndOrigin - yStartOrigin) * offsetRatio + yStartOrigin;
|
|
cpX2 = xEndOrigin;
|
|
cpY2 = (yEndOrigin - yStartOrigin) * (1 - offsetRatio) + yStartOrigin;
|
|
var rad = (cpX1 - this.minX) / this.width * Math.PI * 2;
|
|
cpX1 = cpY1 * Math.cos(rad) + rootX;
|
|
cpY1 = cpY1 * Math.sin(rad) + rootY;
|
|
rad = (cpX2 - this.minX) / this.width * Math.PI * 2;
|
|
cpX2 = cpY2 * Math.cos(rad) + rootX;
|
|
cpY2 = cpY2 * Math.sin(rad) + rootY;
|
|
}
|
|
}
|
|
var shape = new BezierCurveShape({
|
|
zlevel: this.getZlevelBase(),
|
|
hoverable: false,
|
|
style: zrUtil.merge({
|
|
xStart: xStart,
|
|
yStart: yStart,
|
|
cpX1: cpX1,
|
|
cpY1: cpY1,
|
|
cpX2: cpX2,
|
|
cpY2: cpY2,
|
|
xEnd: xEnd,
|
|
yEnd: yEnd,
|
|
strokeColor: lineStyle.color,
|
|
lineWidth: lineStyle.width
|
|
}, lineStyle, true)
|
|
});
|
|
this.shapeList.push(shape);
|
|
},
|
|
_setTreeShape: function (serie) {
|
|
var treeLayout = new TreeLayout({
|
|
nodePadding: serie.nodePadding,
|
|
layerPadding: serie.layerPadding
|
|
});
|
|
this.tree.traverse(function (treeNode) {
|
|
var queryTarget = [
|
|
treeNode.data,
|
|
serie
|
|
];
|
|
var symbolSize = this.deepQuery(queryTarget, 'symbolSize');
|
|
if (typeof symbolSize === 'number') {
|
|
symbolSize = [
|
|
symbolSize,
|
|
symbolSize
|
|
];
|
|
}
|
|
treeNode.layout = {
|
|
width: symbolSize[0],
|
|
height: symbolSize[1]
|
|
};
|
|
}, this);
|
|
treeLayout.run(this.tree);
|
|
var orient = serie.orient;
|
|
var rootX = serie.rootLocation.x;
|
|
var rootY = serie.rootLocation.y;
|
|
var zrWidth = this.zr.getWidth();
|
|
var zrHeight = this.zr.getHeight();
|
|
if (rootX === 'center') {
|
|
rootX = zrWidth * 0.5;
|
|
} else {
|
|
rootX = this.parsePercent(rootX, zrWidth);
|
|
}
|
|
if (rootY === 'center') {
|
|
rootY = zrHeight * 0.5;
|
|
} else {
|
|
rootY = this.parsePercent(rootY, zrHeight);
|
|
}
|
|
rootY = this.parsePercent(rootY, zrHeight);
|
|
if (orient === 'horizontal') {
|
|
rootX = isNaN(rootX) ? 10 : rootX;
|
|
rootY = isNaN(rootY) ? zrHeight * 0.5 : rootY;
|
|
}
|
|
if (orient === 'radial') {
|
|
rootX = isNaN(rootX) ? zrWidth * 0.5 : rootX;
|
|
rootY = isNaN(rootY) ? zrHeight * 0.5 : rootY;
|
|
} else {
|
|
rootX = isNaN(rootX) ? zrWidth * 0.5 : rootX;
|
|
rootY = isNaN(rootY) ? 10 : rootY;
|
|
}
|
|
var originRootX = this.tree.root.layout.position[0];
|
|
if (orient === 'radial') {
|
|
var minX = Infinity;
|
|
var maxX = 0;
|
|
var maxWidth = 0;
|
|
this.tree.traverse(function (treeNode) {
|
|
maxX = Math.max(maxX, treeNode.layout.position[0]);
|
|
minX = Math.min(minX, treeNode.layout.position[0]);
|
|
maxWidth = Math.max(maxWidth, treeNode.layout.width);
|
|
});
|
|
this.width = maxX - minX + 2 * maxWidth;
|
|
this.minX = minX;
|
|
}
|
|
this.tree.traverse(function (treeNode) {
|
|
var x;
|
|
var y;
|
|
if (orient === 'vertical' && serie.direction === 'inverse') {
|
|
x = treeNode.layout.position[0] - originRootX + rootX;
|
|
y = rootY - treeNode.layout.position[1];
|
|
} else if (orient === 'vertical') {
|
|
x = treeNode.layout.position[0] - originRootX + rootX;
|
|
y = treeNode.layout.position[1] + rootY;
|
|
} else if (orient === 'horizontal' && serie.direction === 'inverse') {
|
|
y = treeNode.layout.position[0] - originRootX + rootY;
|
|
x = rootX - treeNode.layout.position[1];
|
|
} else if (orient === 'horizontal') {
|
|
y = treeNode.layout.position[0] - originRootX + rootY;
|
|
x = treeNode.layout.position[1] + rootX;
|
|
} else {
|
|
x = treeNode.layout.position[0];
|
|
y = treeNode.layout.position[1];
|
|
treeNode.layout.originPosition = [
|
|
x,
|
|
y
|
|
];
|
|
var r = y;
|
|
var angle = (x - minX) / this.width * Math.PI * 2;
|
|
x = r * Math.cos(angle) + rootX;
|
|
y = r * Math.sin(angle) + rootY;
|
|
treeNode.layout.angle = angle;
|
|
}
|
|
treeNode.layout.position[0] = x;
|
|
treeNode.layout.position[1] = y;
|
|
}, this);
|
|
},
|
|
refresh: function (newOption) {
|
|
this.clear();
|
|
if (newOption) {
|
|
this.option = newOption;
|
|
this.series = this.option.series;
|
|
}
|
|
var series = this.series;
|
|
var legend = this.component.legend;
|
|
for (var i = 0; i < series.length; i++) {
|
|
if (series[i].type === ecConfig.CHART_TYPE_TREE) {
|
|
series[i] = this.reformOption(series[i]);
|
|
var seriesName = series[i].name || '';
|
|
this.selectedMap[seriesName] = legend ? legend.isSelected(seriesName) : true;
|
|
if (!this.selectedMap[seriesName]) {
|
|
continue;
|
|
}
|
|
this._buildSeries(series[i], i);
|
|
}
|
|
}
|
|
},
|
|
_buildSeries: function (series, seriesIndex) {
|
|
this._buildShape(series, seriesIndex);
|
|
}
|
|
};
|
|
zrUtil.inherits(Tree, ChartBase);
|
|
require('../chart').define('tree', Tree);
|
|
return Tree;
|
|
});define('echarts/layout/Tree', [
|
|
'require',
|
|
'zrender/tool/vector'
|
|
], function (require) {
|
|
var vec2 = require('zrender/tool/vector');
|
|
function TreeLayout(opts) {
|
|
opts = opts || {};
|
|
this.nodePadding = opts.nodePadding || 30;
|
|
this.layerPadding = opts.layerPadding || 100;
|
|
this._layerOffsets = [];
|
|
this._layers = [];
|
|
}
|
|
TreeLayout.prototype.run = function (tree) {
|
|
this._layerOffsets.length = 0;
|
|
for (var i = 0; i < tree.root.height + 1; i++) {
|
|
this._layerOffsets[i] = 0;
|
|
this._layers[i] = [];
|
|
}
|
|
this._updateNodeXPosition(tree.root);
|
|
var root = tree.root;
|
|
this._updateNodeYPosition(root, 0, root.layout.height);
|
|
};
|
|
TreeLayout.prototype._updateNodeXPosition = function (node) {
|
|
var minX = Infinity;
|
|
var maxX = -Infinity;
|
|
node.layout.position = node.layout.position || vec2.create();
|
|
for (var i = 0; i < node.children.length; i++) {
|
|
var child = node.children[i];
|
|
this._updateNodeXPosition(child);
|
|
var x = child.layout.position[0];
|
|
if (x < minX) {
|
|
minX = x;
|
|
}
|
|
if (x > maxX) {
|
|
maxX = x;
|
|
}
|
|
}
|
|
if (node.children.length > 0) {
|
|
node.layout.position[0] = (minX + maxX) / 2;
|
|
} else {
|
|
node.layout.position[0] = 0;
|
|
}
|
|
var off = this._layerOffsets[node.depth] || 0;
|
|
if (off > node.layout.position[0]) {
|
|
var shift = off - node.layout.position[0];
|
|
this._shiftSubtree(node, shift);
|
|
for (var i = node.depth + 1; i < node.height + node.depth; i++) {
|
|
this._layerOffsets[i] += shift;
|
|
}
|
|
}
|
|
this._layerOffsets[node.depth] = node.layout.position[0] + node.layout.width + this.nodePadding;
|
|
this._layers[node.depth].push(node);
|
|
};
|
|
TreeLayout.prototype._shiftSubtree = function (root, offset) {
|
|
root.layout.position[0] += offset;
|
|
for (var i = 0; i < root.children.length; i++) {
|
|
this._shiftSubtree(root.children[i], offset);
|
|
}
|
|
};
|
|
TreeLayout.prototype._updateNodeYPosition = function (node, y, prevLayerHeight) {
|
|
node.layout.position[1] = y;
|
|
var layerHeight = 0;
|
|
for (var i = 0; i < node.children.length; i++) {
|
|
layerHeight = Math.max(node.children[i].layout.height, layerHeight);
|
|
}
|
|
var layerPadding = this.layerPadding;
|
|
if (typeof layerPadding === 'function') {
|
|
layerPadding = layerPadding(node.depth);
|
|
}
|
|
for (var i = 0; i < node.children.length; i++) {
|
|
this._updateNodeYPosition(node.children[i], y + layerPadding + prevLayerHeight, layerHeight);
|
|
}
|
|
};
|
|
return TreeLayout;
|
|
});define('echarts/data/Tree', [
|
|
'require',
|
|
'zrender/tool/util'
|
|
], function (require) {
|
|
var zrUtil = require('zrender/tool/util');
|
|
function TreeNode(id, data) {
|
|
this.id = id;
|
|
this.depth = 0;
|
|
this.height = 0;
|
|
this.children = [];
|
|
this.parent = null;
|
|
this.data = data || null;
|
|
}
|
|
TreeNode.prototype.add = function (child) {
|
|
var children = this.children;
|
|
if (child.parent === this) {
|
|
return;
|
|
}
|
|
children.push(child);
|
|
child.parent = this;
|
|
};
|
|
TreeNode.prototype.remove = function (child) {
|
|
var children = this.children;
|
|
var idx = zrUtil.indexOf(children, child);
|
|
if (idx >= 0) {
|
|
children.splice(idx, 1);
|
|
child.parent = null;
|
|
}
|
|
};
|
|
TreeNode.prototype.traverse = function (cb, context) {
|
|
cb.call(context, this);
|
|
for (var i = 0; i < this.children.length; i++) {
|
|
this.children[i].traverse(cb, context);
|
|
}
|
|
};
|
|
TreeNode.prototype.updateDepthAndHeight = function (depth) {
|
|
var height = 0;
|
|
this.depth = depth;
|
|
for (var i = 0; i < this.children.length; i++) {
|
|
var child = this.children[i];
|
|
child.updateDepthAndHeight(depth + 1);
|
|
if (child.height > height) {
|
|
height = child.height;
|
|
}
|
|
}
|
|
this.height = height + 1;
|
|
};
|
|
TreeNode.prototype.getNodeById = function (id) {
|
|
if (this.id === id) {
|
|
return this;
|
|
}
|
|
for (var i = 0; i < this.children.length; i++) {
|
|
var res = this.children[i].getNodeById(id);
|
|
if (res) {
|
|
return res;
|
|
}
|
|
}
|
|
};
|
|
function Tree(id) {
|
|
this.root = new TreeNode(id);
|
|
}
|
|
Tree.prototype.traverse = function (cb, context) {
|
|
this.root.traverse(cb, context);
|
|
};
|
|
Tree.prototype.getSubTree = function (id) {
|
|
var root = this.getNodeById(id);
|
|
if (root) {
|
|
var tree = new Tree(root.id);
|
|
tree.root = root;
|
|
return tree;
|
|
}
|
|
};
|
|
Tree.prototype.getNodeById = function (id) {
|
|
return this.root.getNodeById(id);
|
|
};
|
|
Tree.fromOptionData = function (id, data) {
|
|
var tree = new Tree(id);
|
|
var rootNode = tree.root;
|
|
rootNode.data = {
|
|
name: id,
|
|
children: data
|
|
};
|
|
function buildHierarchy(dataNode, parentNode) {
|
|
var node = new TreeNode(dataNode.name, dataNode);
|
|
parentNode.add(node);
|
|
var children = dataNode.children;
|
|
if (children) {
|
|
for (var i = 0; i < children.length; i++) {
|
|
buildHierarchy(children[i], node);
|
|
}
|
|
}
|
|
}
|
|
for (var i = 0; i < data.length; i++) {
|
|
buildHierarchy(data[i], rootNode);
|
|
}
|
|
tree.root.updateDepthAndHeight(0);
|
|
return tree;
|
|
};
|
|
Tree.fromGraph = function (graph) {
|
|
function buildHierarchy(root) {
|
|
var graphNode = graph.getNodeById(root.id);
|
|
for (var i = 0; i < graphNode.outEdges.length; i++) {
|
|
var edge = graphNode.outEdges[i];
|
|
var childTreeNode = treeNodesMap[edge.node2.id];
|
|
root.children.push(childTreeNode);
|
|
buildHierarchy(childTreeNode);
|
|
}
|
|
}
|
|
var treeMap = {};
|
|
var treeNodesMap = {};
|
|
for (var i = 0; i < graph.nodes.length; i++) {
|
|
var node = graph.nodes[i];
|
|
var treeNode;
|
|
if (node.inDegree() === 0) {
|
|
treeMap[node.id] = new Tree(node.id);
|
|
treeNode = treeMap[node.id].root;
|
|
} else {
|
|
treeNode = new TreeNode(node.id);
|
|
}
|
|
treeNode.data = node.data;
|
|
treeNodesMap[node.id] = treeNode;
|
|
}
|
|
var treeList = [];
|
|
for (var id in treeMap) {
|
|
buildHierarchy(treeMap[id].root);
|
|
treeMap[id].root.updateDepthAndHeight(0);
|
|
treeList.push(treeMap[id]);
|
|
}
|
|
return treeList;
|
|
};
|
|
return Tree;
|
|
}); |