blob: 7bca340a3dc81ccf1e1ca944b030e8c8e5fb0d58 [file] [log] [blame]
/*
* 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 SeriesModel from '../../model/Series';
import Tree from '../../data/Tree';
import {
SeriesOption,
SymbolOptionMixin,
BoxLayoutOptionMixin,
RoamOptionMixin,
LineStyleOption,
ItemStyleOption,
SeriesLabelOption,
OptionDataValue,
StatesOptionMixin,
OptionDataItemObject,
CallbackDataParams,
DefaultEmphasisFocus
} from '../../util/types';
import List from '../../data/List';
import View from '../../coord/View';
import { LayoutRect } from '../../util/layout';
import Model from '../../model/Model';
import { createTooltipMarkup } from '../../component/tooltip/tooltipMarkup';
interface CurveLineStyleOption extends LineStyleOption{
curveness?: number
}
export interface TreeSeriesStateOption {
itemStyle?: ItemStyleOption
/**
* Line style of the edge between node and it's parent.
*/
lineStyle?: CurveLineStyleOption
label?: SeriesLabelOption
}
interface ExtraStateOption {
emphasis?: {
focus?: DefaultEmphasisFocus | 'ancestor' | 'descendant'
scale?: boolean
}
}
export interface TreeSeriesNodeItemOption extends SymbolOptionMixin<CallbackDataParams>,
TreeSeriesStateOption, StatesOptionMixin<TreeSeriesStateOption, ExtraStateOption>,
OptionDataItemObject<OptionDataValue> {
children?: TreeSeriesNodeItemOption[]
collapsed?: boolean
link?: string
target?: string
}
/**
* Configuration of leaves nodes.
*/
export interface TreeSeriesLeavesOption extends TreeSeriesStateOption, StatesOptionMixin<TreeSeriesStateOption> {
}
export interface TreeSeriesOption extends
SeriesOption<TreeSeriesStateOption, ExtraStateOption>, TreeSeriesStateOption,
SymbolOptionMixin, BoxLayoutOptionMixin, RoamOptionMixin {
type?: 'tree'
layout?: 'orthogonal' | 'radial'
edgeShape?: 'polyline' | 'curve'
/**
* Available when edgeShape is polyline
*/
edgeForkPosition?: string | number
nodeScaleRatio?: number
/**
* The orient of orthoginal layout, can be setted to 'LR', 'TB', 'RL', 'BT'.
* and the backward compatibility configuration 'horizontal = LR', 'vertical = TB'.
*/
orient?: 'LR' | 'TB' | 'RL' | 'BT' | 'horizontal' | 'vertical'
expandAndCollapse?: boolean
/**
* The initial expanded depth of tree
*/
initialTreeDepth?: number
leaves?: TreeSeriesLeavesOption
data?: TreeSeriesNodeItemOption[]
}
class TreeSeriesModel extends SeriesModel<TreeSeriesOption> {
static readonly type = 'series.tree';
// can support the position parameters 'left', 'top','right','bottom', 'width',
// 'height' in the setOption() with 'merge' mode normal.
static readonly layoutMode = 'box';
coordinateSystem: View;
layoutInfo: LayoutRect;
hasSymbolVisual = true;
// Do it self.
ignoreStyleOnData = true;
/**
* Init a tree data structure from data in option series
* @param option the object used to config echarts view
* @return storage initial data
*/
getInitialData(option: TreeSeriesOption): List {
//create an virtual root
const root: TreeSeriesNodeItemOption = {
name: option.name,
children: option.data
};
const leaves = option.leaves || {};
const leavesModel = new Model(leaves, this, this.ecModel);
const tree = Tree.createTree(root, this, beforeLink);
function beforeLink(nodeData: List) {
nodeData.wrapMethod('getItemModel', function (model, idx) {
const node = tree.getNodeByDataIndex(idx);
if (!node.children.length || !node.isExpand) {
model.parentModel = leavesModel;
}
return model;
});
}
let treeDepth = 0;
tree.eachNode('preorder', function (node) {
if (node.depth > treeDepth) {
treeDepth = node.depth;
}
});
const expandAndCollapse = option.expandAndCollapse;
const expandTreeDepth = (expandAndCollapse && option.initialTreeDepth >= 0)
? option.initialTreeDepth : treeDepth;
tree.root.eachNode('preorder', function (node) {
const item = node.hostTree.data.getRawDataItem(node.dataIndex) as TreeSeriesNodeItemOption;
// Add item.collapsed != null, because users can collapse node original in the series.data.
node.isExpand = (item && item.collapsed != null)
? !item.collapsed
: node.depth <= expandTreeDepth;
});
return tree.data;
}
/**
* Make the configuration 'orient' backward compatibly, with 'horizontal = LR', 'vertical = TB'.
* @returns {string} orient
*/
getOrient() {
let orient = this.get('orient');
if (orient === 'horizontal') {
orient = 'LR';
}
else if (orient === 'vertical') {
orient = 'TB';
}
return orient;
}
setZoom(zoom: number) {
this.option.zoom = zoom;
}
setCenter(center: number[]) {
this.option.center = center;
}
formatTooltip(
dataIndex: number,
multipleSeries: boolean,
dataType: string
) {
const tree = this.getData().tree;
const realRoot = tree.root.children[0];
let node = tree.getNodeByDataIndex(dataIndex);
const value = node.getValue();
let name = node.name;
while (node && (node !== realRoot)) {
name = node.parentNode.name + '.' + name;
node = node.parentNode;
}
return createTooltipMarkup('nameValue', {
name: name,
value: value,
noValue: isNaN(value as number) || value == null
});
}
static defaultOption: TreeSeriesOption = {
zlevel: 0,
z: 2,
coordinateSystem: 'view',
// the position of the whole view
left: '12%',
top: '12%',
right: '12%',
bottom: '12%',
// the layout of the tree, two value can be selected, 'orthogonal' or 'radial'
layout: 'orthogonal',
// value can be 'polyline'
edgeShape: 'curve',
edgeForkPosition: '50%',
// true | false | 'move' | 'scale', see module:component/helper/RoamController.
roam: false,
// Symbol size scale ratio in roam
nodeScaleRatio: 0.4,
// Default on center of graph
center: null,
zoom: 1,
orient: 'LR',
symbol: 'emptyCircle',
symbolSize: 7,
expandAndCollapse: true,
initialTreeDepth: 2,
lineStyle: {
color: '#ccc',
width: 1.5,
curveness: 0.5
},
itemStyle: {
color: 'lightsteelblue',
borderColor: '#c23531',
borderWidth: 1.5
},
label: {
show: true
},
animationEasing: 'linear',
animationDuration: 700,
animationDurationUpdate: 500
};
}
export default TreeSeriesModel;