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