425 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			425 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
 | |
| /*
 | |
| * 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.
 | |
| */
 | |
| 
 | |
| var zrUtil = require("zrender/lib/core/util");
 | |
| 
 | |
| var SeriesModel = require("../../model/Series");
 | |
| 
 | |
| var Tree = require("../../data/Tree");
 | |
| 
 | |
| var Model = require("../../model/Model");
 | |
| 
 | |
| var _format = require("../../util/format");
 | |
| 
 | |
| var encodeHTML = _format.encodeHTML;
 | |
| var addCommas = _format.addCommas;
 | |
| 
 | |
| var _treeHelper = require("../helper/treeHelper");
 | |
| 
 | |
| var wrapTreePathInfo = _treeHelper.wrapTreePathInfo;
 | |
| 
 | |
| /*
 | |
| * 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.
 | |
| */
 | |
| var _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;
 | |
| }
 | |
| 
 | |
| module.exports = _default; | 
