bkjxxxw/WebContent/static/echarts-2.2.7/build/source/chart/tree.js

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;
});