Current File : //home/tradevaly/www/node_modules/echarts/src/chart/treemap/TreemapSeries.js |
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import * as zrUtil from 'zrender/src/core/util';
import SeriesModel from '../../model/Series';
import Tree from '../../data/Tree';
import Model from '../../model/Model';
import {encodeHTML, addCommas} from '../../util/format';
import {wrapTreePathInfo} from '../helper/treeHelper';
export default SeriesModel.extend({
type: 'series.treemap',
layoutMode: 'box',
dependencies: ['grid', 'polar'],
preventUsingHoverLayer: true,
/**
* @type {module:echarts/data/Tree~Node}
*/
_viewRoot: null,
defaultOption: {
// Disable progressive rendering
progressive: 0,
// center: ['50%', '50%'], // not supported in ec3.
// size: ['80%', '80%'], // deprecated, compatible with ec2.
left: 'center',
top: 'middle',
right: null,
bottom: null,
width: '80%',
height: '80%',
sort: true, // Can be null or false or true
// (order by desc default, asc not supported yet (strange effect))
clipWindow: 'origin', // Size of clipped window when zooming. 'origin' or 'fullscreen'
squareRatio: 0.5 * (1 + Math.sqrt(5)), // golden ratio
leafDepth: null, // Nodes on depth from root are regarded as leaves.
// Count from zero (zero represents only view root).
drillDownIcon: '▶', // Use html character temporarily because it is complicated
// to align specialized icon. ▷▶❒❐▼✚
zoomToNodeRatio: 0.32 * 0.32, // Be effective when using zoomToNode. Specify the proportion of the
// target node area in the view area.
roam: true, // true, false, 'scale' or 'zoom', 'move'.
nodeClick: 'zoomToNode', // Leaf node click behaviour: 'zoomToNode', 'link', false.
// If leafDepth is set and clicking a node which has children but
// be on left depth, the behaviour would be changing root. Otherwise
// use behavious defined above.
animation: true,
animationDurationUpdate: 900,
animationEasing: 'quinticInOut',
breadcrumb: {
show: true,
height: 22,
left: 'center',
top: 'bottom',
// right
// bottom
emptyItemWidth: 25, // Width of empty node.
itemStyle: {
color: 'rgba(0,0,0,0.7)', //'#5793f3',
borderColor: 'rgba(255,255,255,0.7)',
borderWidth: 1,
shadowColor: 'rgba(150,150,150,1)',
shadowBlur: 3,
shadowOffsetX: 0,
shadowOffsetY: 0,
textStyle: {
color: '#fff'
}
},
emphasis: {
textStyle: {}
}
},
label: {
show: true,
// Do not use textDistance, for ellipsis rect just the same as treemap node rect.
distance: 0,
padding: 5,
position: 'inside', // Can be [5, '5%'] or position stirng like 'insideTopLeft', ...
// formatter: null,
color: '#fff',
ellipsis: true
// align
// verticalAlign
},
upperLabel: { // Label when node is parent.
show: false,
position: [0, '50%'],
height: 20,
// formatter: null,
color: '#fff',
ellipsis: true,
// align: null,
verticalAlign: 'middle'
},
itemStyle: {
color: null, // Can be 'none' if not necessary.
colorAlpha: null, // Can be 'none' if not necessary.
colorSaturation: null, // Can be 'none' if not necessary.
borderWidth: 0,
gapWidth: 0,
borderColor: '#fff',
borderColorSaturation: null // If specified, borderColor will be ineffective, and the
// border color is evaluated by color of current node and
// borderColorSaturation.
},
emphasis: {
upperLabel: {
show: true,
position: [0, '50%'],
color: '#fff',
ellipsis: true,
verticalAlign: 'middle'
}
},
visualDimension: 0, // Can be 0, 1, 2, 3.
visualMin: null,
visualMax: null,
color: [], // + treemapSeries.color should not be modified. Please only modified
// level[n].color (if necessary).
// + Specify color list of each level. level[0].color would be global
// color list if not specified. (see method `setDefault`).
// + But set as a empty array to forbid fetch color from global palette
// when using nodeModel.get('color'), otherwise nodes on deep level
// will always has color palette set and are not able to inherit color
// from parent node.
// + TreemapSeries.color can not be set as 'none', otherwise effect
// legend color fetching (see seriesColor.js).
colorAlpha: null, // Array. Specify color alpha range of each level, like [0.2, 0.8]
colorSaturation: null, // Array. Specify color saturation of each level, like [0.2, 0.5]
colorMappingBy: 'index', // 'value' or 'index' or 'id'.
visibleMin: 10, // If area less than this threshold (unit: pixel^2), node will not
// be rendered. Only works when sort is 'asc' or 'desc'.
childrenVisibleMin: null, // If area of a node less than this threshold (unit: pixel^2),
// grandchildren will not show.
// Why grandchildren? If not grandchildren but children,
// some siblings show children and some not,
// the appearance may be mess and not consistent,
levels: [] // Each item: {
// visibleMin, itemStyle, visualDimension, label
// }
// data: {
// value: [],
// children: [],
// link: 'http://xxx.xxx.xxx',
// target: 'blank' or 'self'
// }
},
/**
* @override
*/
getInitialData: function (option, ecModel) {
// Create a virtual root.
var root = {name: option.name, children: option.data};
completeTreeValue(root);
var levels = option.levels || [];
// Used in "visual priority" in `treemapVisual.js`.
// This way is a little tricky, must satisfy the precondition:
// 1. There is no `treeNode.getModel('itemStyle.xxx')` used.
// 2. The `Model.prototype.getModel()` will not use any clone-like way.
var designatedVisualItemStyle = this.designatedVisualItemStyle = {};
var designatedVisualModel = new Model({itemStyle: designatedVisualItemStyle}, this, ecModel);
levels = option.levels = setDefault(levels, ecModel);
var levelModels = zrUtil.map(levels || [], function (levelDefine) {
return new Model(levelDefine, designatedVisualModel, ecModel);
}, this);
// Make sure always a new tree is created when setOption,
// in TreemapView, we check whether oldTree === newTree
// to choose mappings approach among old shapes and new shapes.
var tree = Tree.createTree(root, this, beforeLink);
function beforeLink(nodeData) {
nodeData.wrapMethod('getItemModel', function (model, idx) {
var node = tree.getNodeByDataIndex(idx);
var levelModel = levelModels[node.depth];
// If no levelModel, we also need `designatedVisualModel`.
model.parentModel = levelModel || designatedVisualModel;
return model;
});
}
return tree.data;
},
optionUpdated: function () {
this.resetViewRoot();
},
/**
* @override
* @param {number} dataIndex
* @param {boolean} [mutipleSeries=false]
*/
formatTooltip: function (dataIndex) {
var data = this.getData();
var value = this.getRawValue(dataIndex);
var formattedValue = zrUtil.isArray(value)
? addCommas(value[0]) : addCommas(value);
var name = data.getName(dataIndex);
return encodeHTML(name + ': ' + formattedValue);
},
/**
* Add tree path to tooltip param
*
* @override
* @param {number} dataIndex
* @return {Object}
*/
getDataParams: function (dataIndex) {
var params = SeriesModel.prototype.getDataParams.apply(this, arguments);
var node = this.getData().tree.getNodeByDataIndex(dataIndex);
params.treePathInfo = wrapTreePathInfo(node, this);
return params;
},
/**
* @public
* @param {Object} layoutInfo {
* x: containerGroup x
* y: containerGroup y
* width: containerGroup width
* height: containerGroup height
* }
*/
setLayoutInfo: function (layoutInfo) {
/**
* @readOnly
* @type {Object}
*/
this.layoutInfo = this.layoutInfo || {};
zrUtil.extend(this.layoutInfo, layoutInfo);
},
/**
* @param {string} id
* @return {number} index
*/
mapIdToIndex: function (id) {
// A feature is implemented:
// index is monotone increasing with the sequence of
// input id at the first time.
// This feature can make sure that each data item and its
// mapped color have the same index between data list and
// color list at the beginning, which is useful for user
// to adjust data-color mapping.
/**
* @private
* @type {Object}
*/
var idIndexMap = this._idIndexMap;
if (!idIndexMap) {
idIndexMap = this._idIndexMap = zrUtil.createHashMap();
/**
* @private
* @type {number}
*/
this._idIndexMapCount = 0;
}
var index = idIndexMap.get(id);
if (index == null) {
idIndexMap.set(id, index = this._idIndexMapCount++);
}
return index;
},
getViewRoot: function () {
return this._viewRoot;
},
/**
* @param {module:echarts/data/Tree~Node} [viewRoot]
*/
resetViewRoot: function (viewRoot) {
viewRoot
? (this._viewRoot = viewRoot)
: (viewRoot = this._viewRoot);
var root = this.getRawData().tree.root;
if (!viewRoot
|| (viewRoot !== root && !root.contains(viewRoot))
) {
this._viewRoot = root;
}
}
});
/**
* @param {Object} dataNode
*/
function completeTreeValue(dataNode) {
// Postorder travel tree.
// If value of none-leaf node is not set,
// calculate it by suming up the value of all children.
var sum = 0;
zrUtil.each(dataNode.children, function (child) {
completeTreeValue(child);
var childValue = child.value;
zrUtil.isArray(childValue) && (childValue = childValue[0]);
sum += childValue;
});
var thisValue = dataNode.value;
if (zrUtil.isArray(thisValue)) {
thisValue = thisValue[0];
}
if (thisValue == null || isNaN(thisValue)) {
thisValue = sum;
}
// Value should not less than 0.
if (thisValue < 0) {
thisValue = 0;
}
zrUtil.isArray(dataNode.value)
? (dataNode.value[0] = thisValue)
: (dataNode.value = thisValue);
}
/**
* set default to level configuration
*/
function setDefault(levels, ecModel) {
var globalColorList = ecModel.get('color');
if (!globalColorList) {
return;
}
levels = levels || [];
var hasColorDefine;
zrUtil.each(levels, function (levelDefine) {
var model = new Model(levelDefine);
var modelColor = model.get('color');
if (model.get('itemStyle.color')
|| (modelColor && modelColor !== 'none')
) {
hasColorDefine = true;
}
});
if (!hasColorDefine) {
var level0 = levels[0] || (levels[0] = {});
level0.color = globalColorList.slice();
}
return levels;
}