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

632 lines
24 KiB
JavaScript

define('echarts/chart/treemap', [
'require',
'./base',
'zrender/tool/area',
'zrender/shape/Rectangle',
'zrender/shape/Text',
'zrender/shape/Line',
'../layout/TreeMap',
'../data/Tree',
'../config',
'../util/ecData',
'zrender/config',
'zrender/tool/event',
'zrender/tool/util',
'zrender/tool/color',
'../chart'
], function (require) {
var ChartBase = require('./base');
var toolArea = require('zrender/tool/area');
var RectangleShape = require('zrender/shape/Rectangle');
var TextShape = require('zrender/shape/Text');
var LineShape = require('zrender/shape/Line');
var TreeMapLayout = require('../layout/TreeMap');
var Tree = require('../data/Tree');
var ecConfig = require('../config');
ecConfig.treemap = {
zlevel: 0,
z: 1,
calculable: false,
clickable: true,
center: [
'50%',
'50%'
],
size: [
'80%',
'80%'
],
root: '',
itemStyle: {
normal: {
label: {
show: true,
x: 5,
y: 12,
textStyle: {
align: 'left',
color: '#000',
fontFamily: 'Arial',
fontSize: 13,
fontStyle: 'normal',
fontWeight: 'normal'
}
},
breadcrumb: {
show: true,
textStyle: {}
},
borderWidth: 1,
borderColor: '#ccc',
childBorderWidth: 1,
childBorderColor: '#ccc'
},
emphasis: {}
}
};
var ecData = require('../util/ecData');
var zrConfig = require('zrender/config');
var zrEvent = require('zrender/tool/event');
var zrUtil = require('zrender/tool/util');
var zrColor = require('zrender/tool/color');
function Treemap(ecTheme, messageCenter, zr, option, myChart) {
ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
this.refresh(option);
var self = this;
self._onclick = function (params) {
return self.__onclick(params);
};
self.zr.on(zrConfig.EVENT.CLICK, self._onclick);
}
Treemap.prototype = {
type: ecConfig.CHART_TYPE_TREEMAP,
refresh: function (newOption) {
this.clear();
if (newOption) {
this.option = newOption;
this.series = this.option.series;
}
this._treesMap = {};
var series = this.series;
var legend = this.component.legend;
for (var i = 0; i < series.length; i++) {
if (series[i].type === ecConfig.CHART_TYPE_TREEMAP) {
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) {
var tree = Tree.fromOptionData(series.name, series.data);
this._treesMap[seriesIndex] = tree;
var treeRoot = series.root && tree.getNodeById(series.root) || tree.root;
this._buildTreemap(treeRoot, seriesIndex);
},
_buildTreemap: function (treeRoot, seriesIndex) {
var shapeList = this.shapeList;
for (var i = 0; i < shapeList.length;) {
var shape = shapeList[i];
if (ecData.get(shape, 'seriesIndex') === seriesIndex) {
this.zr.delShape(shapeList[i]);
shapeList.splice(i, 1);
} else {
i++;
}
}
var currentShapeLen = shapeList.length;
var series = this.series[seriesIndex];
var itemStyle = series.itemStyle;
var treemapWidth = this.parsePercent(series.size[0], this.zr.getWidth()) || 400;
var treemapHeight = this.parsePercent(series.size[1], this.zr.getHeight()) || 500;
var center = this.parseCenter(this.zr, series.center);
var treemapX = center[0] - treemapWidth * 0.5;
var treemapY = center[1] - treemapHeight * 0.5;
var treemapArea = treemapWidth * treemapHeight;
var sum = 0;
var areaArr = [];
var children = treeRoot.children;
for (var i = 0; i < children.length; i++) {
sum += children[i].data.value;
}
for (var j = 0; j < children.length; j++) {
areaArr.push(children[j].data.value * treemapArea / sum);
}
var treeMapLayout = new TreeMapLayout({
x: treemapX,
y: treemapY,
width: treemapWidth,
height: treemapHeight
});
var locationArr = treeMapLayout.run(areaArr);
for (var k = 0; k < locationArr.length; k++) {
var dataItem = children[k].data;
var rect = locationArr[k];
var queryTarget = [
dataItem.itemStyle,
itemStyle
];
var itemStyleMerged = this.deepMerge(queryTarget);
if (!itemStyleMerged.normal.color) {
itemStyleMerged.normal.color = this.zr.getColor(k);
}
if (!itemStyleMerged.emphasis.color) {
itemStyleMerged.emphasis.color = itemStyleMerged.normal.color;
}
this._buildItem(dataItem, itemStyleMerged, rect, seriesIndex, k);
if (dataItem.children) {
this._buildChildrenTreemap(dataItem.children, itemStyleMerged, rect, seriesIndex);
}
}
if (this.query(series, 'itemStyle.normal.breadcrumb.show')) {
this._buildBreadcrumb(treeRoot, seriesIndex, treemapX, treemapY + treemapHeight);
}
for (var i = currentShapeLen; i < shapeList.length; i++) {
this.zr.addShape(shapeList[i]);
}
},
_buildItem: function (dataItem, itemStyle, rect, seriesIndex, dataIndex) {
var series = this.series;
var rectangle = this.getRectangle(dataItem, itemStyle, rect);
ecData.pack(rectangle, series[seriesIndex], seriesIndex, dataItem, dataIndex, dataItem.name);
this.shapeList.push(rectangle);
},
getRectangle: function (dataItem, itemStyle, rect) {
var emphasis = itemStyle.emphasis;
var normal = itemStyle.normal;
var textShape = this.getLabel(itemStyle, rect, dataItem.name, dataItem.value);
var hoverable = this.option.hoverable;
var rectangleShape = {
zlevel: this.getZlevelBase(),
z: this.getZBase(),
hoverable: hoverable,
clickable: true,
style: zrUtil.merge({
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height,
brushType: 'both',
color: normal.color,
lineWidth: normal.borderWidth,
strokeColor: normal.borderColor
}, textShape.style, true),
highlightStyle: zrUtil.merge({
color: emphasis.color,
lineWidth: emphasis.borderWidth,
strokeColor: emphasis.borderColor
}, textShape.highlightStyle, true)
};
return new RectangleShape(rectangleShape);
},
getLabel: function (itemStyle, rect, name, value) {
var normalTextStyle = itemStyle.normal.label.textStyle;
var queryTarget = [
itemStyle.emphasis.label.textStyle,
normalTextStyle
];
var emphasisTextStyle = this.deepMerge(queryTarget);
var formatter = itemStyle.normal.label.formatter;
var text = this.getLabelText(name, value, formatter);
var textFont = this.getFont(normalTextStyle);
var textWidth = toolArea.getTextWidth(text, textFont);
var textHeight = toolArea.getTextHeight(text, textFont);
var emphasisFormatter = this.deepQuery([
itemStyle.emphasis,
itemStyle.normal
], 'label.formatter');
var emphasisText = this.getLabelText(name, value, emphasisFormatter);
var emphasisTextFont = this.getFont(emphasisTextStyle);
var emphasisTextWidth = toolArea.getTextWidth(text, emphasisTextFont);
var emphasisTextHeight = toolArea.getTextHeight(text, emphasisTextFont);
if (!itemStyle.normal.label.show) {
text = '';
} else if (itemStyle.normal.label.x + textWidth > rect.width || itemStyle.normal.label.y + textHeight > rect.height) {
text = '';
}
if (!itemStyle.emphasis.label.show) {
emphasisText = '';
} else if (emphasisTextStyle.x + emphasisTextWidth > rect.width || emphasisTextStyle.y + emphasisTextHeight > rect.height) {
emphasisText = '';
}
var textShape = {
style: {
textX: rect.x + itemStyle.normal.label.x,
textY: rect.y + itemStyle.normal.label.y,
text: text,
textPosition: 'specific',
textColor: normalTextStyle.color,
textFont: textFont
},
highlightStyle: {
textX: rect.x + itemStyle.emphasis.label.x,
textY: rect.y + itemStyle.emphasis.label.y,
text: emphasisText,
textColor: emphasisTextStyle.color,
textPosition: 'specific'
}
};
return textShape;
},
getLabelText: function (name, value, formatter) {
if (formatter) {
if (typeof formatter === 'function') {
return formatter.call(this.myChart, name, value);
} else if (typeof formatter === 'string') {
formatter = formatter.replace('{b}', '{b0}').replace('{c}', '{c0}');
formatter = formatter.replace('{b0}', name).replace('{c0}', value);
return formatter;
}
} else {
return name;
}
},
_buildChildrenTreemap: function (data, itemStyle, rect, seriesIndex) {
var treemapArea = rect.width * rect.height;
var sum = 0;
var areaArr = [];
for (var i = 0; i < data.length; i++) {
sum += data[i].value;
}
for (var j = 0; j < data.length; j++) {
areaArr.push(data[j].value * treemapArea / sum);
}
var treeMapLayout = new TreeMapLayout({
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height
});
var locationArr = treeMapLayout.run(areaArr);
var lineWidth = itemStyle.normal.childBorderWidth;
var lineColor = itemStyle.normal.childBorderColor;
for (var k = 0; k < locationArr.length; k++) {
var item = locationArr[k];
var lines = [];
if (rect.y.toFixed(2) !== item.y.toFixed(2)) {
lines.push(this._getLine(item.x, item.y, item.x + item.width, item.y, lineWidth, lineColor));
}
if (rect.x.toFixed(2) !== item.x.toFixed(2)) {
lines.push(this._getLine(item.x, item.y, item.x, item.y + item.height, lineWidth, lineColor));
}
if ((rect.y + rect.height).toFixed(2) !== (item.y + item.height).toFixed(2)) {
lines.push(this._getLine(item.x, item.y + item.height, item.x + item.width, item.y + item.height, lineWidth, lineColor));
}
if ((rect.x + rect.width).toFixed(2) !== (item.x + item.width).toFixed(2)) {
lines.push(this._getLine(item.x + item.width, item.y, item.x + item.width, item.y + item.height, lineWidth, lineColor));
}
for (var l = 0; l < lines.length; l++) {
ecData.set(lines[l], 'seriesIndex', seriesIndex);
this.shapeList.push(lines[l]);
}
}
},
_getLine: function (xStart, yStart, xEnd, yEnd, lineWidth, lineColor) {
var lineShape = {
zlevel: this.getZlevelBase(),
z: this.getZBase(),
hoverable: false,
style: {
xStart: xStart,
yStart: yStart,
xEnd: xEnd,
yEnd: yEnd,
lineWidth: lineWidth,
strokeColor: lineColor
}
};
return new LineShape(lineShape);
},
_buildBreadcrumb: function (treeRoot, seriesIndex, x, y) {
var stack = [];
var current = treeRoot;
while (current) {
stack.unshift(current.data.name);
current = current.parent;
}
var series = this.series[seriesIndex];
var textStyle = this.query(series, 'itemStyle.normal.breadcrumb.textStyle') || {};
var textEmphasisStyle = this.query(series, 'itemStyle.emphasis.breadcrumb.textStyle') || {};
var commonStyle = {
y: y + 10,
textBaseline: 'top',
textAlign: 'left',
color: textStyle.color,
textFont: this.getFont(textStyle)
};
var commonHighlightStyle = {
brushType: 'fill',
color: textEmphasisStyle.color || zrColor.lift(textStyle.color, -0.3),
textFont: this.getFont(textEmphasisStyle)
};
for (var i = 0; i < stack.length; i++) {
var textShape = new TextShape({
zlevel: this.getZlevelBase(),
z: this.getZBase(),
style: zrUtil.merge({
x: x,
text: stack[i] + (stack.length - 1 - i ? ' > ' : '')
}, commonStyle),
clickable: true,
highlightStyle: commonHighlightStyle
});
ecData.set(textShape, 'seriesIndex', seriesIndex);
ecData.set(textShape, 'name', stack[i]);
x += textShape.getRect(textShape.style).width;
this.shapeList.push(textShape);
}
},
__onclick: function (params) {
var target = params.target;
if (target) {
var seriesIndex = ecData.get(target, 'seriesIndex');
var name = ecData.get(target, 'name');
var tree = this._treesMap[seriesIndex];
var root = tree.getNodeById(name);
if (root && root.children.length) {
this._buildTreemap(root, seriesIndex);
}
}
}
};
zrUtil.inherits(Treemap, ChartBase);
require('../chart').define('treemap', Treemap);
return Treemap;
});define('echarts/layout/TreeMap', ['require'], function (require) {
function TreeMapLayout(opts) {
var row = {
x: opts.x,
y: opts.y,
width: opts.width,
height: opts.height
};
this.x = opts.x;
this.y = opts.y;
this.width = opts.width;
this.height = opts.height;
}
TreeMapLayout.prototype.run = function (areas) {
var out = [];
this._squarify(areas, {
x: this.x,
y: this.y,
width: this.width,
height: this.height
}, out);
return out;
};
TreeMapLayout.prototype._squarify = function (areas, row, out) {
var layoutDirection = 'VERTICAL';
var width = row.width;
var height = row.height;
if (row.width < row.height) {
layoutDirection = 'HORIZONTAL';
width = row.height;
height = row.width;
}
var shapeArr = this._getShapeListInAbstractRow(areas, width, height);
for (var i = 0; i < shapeArr.length; i++) {
shapeArr[i].x = 0;
shapeArr[i].y = 0;
for (var j = 0; j < i; j++) {
shapeArr[i].y += shapeArr[j].height;
}
}
var nextRow = {};
if (layoutDirection == 'VERTICAL') {
for (var k = 0; k < shapeArr.length; k++) {
out.push({
x: shapeArr[k].x + row.x,
y: shapeArr[k].y + row.y,
width: shapeArr[k].width,
height: shapeArr[k].height
});
}
nextRow = {
x: shapeArr[0].width + row.x,
y: row.y,
width: row.width - shapeArr[0].width,
height: row.height
};
} else {
for (var l = 0; l < shapeArr.length; l++) {
out.push({
x: shapeArr[l].y + row.x,
y: shapeArr[l].x + row.y,
width: shapeArr[l].height,
height: shapeArr[l].width
});
}
nextRow = {
x: row.x,
y: row.y + shapeArr[0].width,
width: row.width,
height: row.height - shapeArr[0].width
};
}
var nextAreaArr = areas.slice(shapeArr.length);
if (nextAreaArr.length === 0) {
return;
} else {
this._squarify(nextAreaArr, nextRow, out);
}
};
TreeMapLayout.prototype._getShapeListInAbstractRow = function (areas, width, height) {
if (areas.length === 1) {
return [{
width: width,
height: height
}];
}
for (var count = 1; count < areas.length; count++) {
var shapeArr0 = this._placeFixedNumberRectangles(areas.slice(0, count), width, height);
var shapeArr1 = this._placeFixedNumberRectangles(areas.slice(0, count + 1), width, height);
if (this._isFirstBetter(shapeArr0, shapeArr1)) {
return shapeArr0;
}
}
};
TreeMapLayout.prototype._placeFixedNumberRectangles = function (areaSubArr, width, height) {
var count = areaSubArr.length;
var shapeArr = [];
var sum = 0;
for (var i = 0; i < areaSubArr.length; i++) {
sum += areaSubArr[i];
}
var cellWidth = sum / height;
for (var j = 0; j < count; j++) {
var cellHeight = height * areaSubArr[j] / sum;
shapeArr.push({
width: cellWidth,
height: cellHeight
});
}
return shapeArr;
};
TreeMapLayout.prototype._isFirstBetter = function (shapeArr0, shapeArr1) {
var ratio0 = shapeArr0[0].height / shapeArr0[0].width;
ratio0 = ratio0 > 1 ? 1 / ratio0 : ratio0;
var ratio1 = shapeArr1[0].height / shapeArr1[0].width;
ratio1 = ratio1 > 1 ? 1 / ratio1 : ratio1;
if (Math.abs(ratio0 - 1) <= Math.abs(ratio1 - 1)) {
return true;
}
return false;
};
return TreeMapLayout;
});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;
});