提交 a08bcd5a 编写于 作者: O Ovilia

feat(sunburst): drill down and roll up support

上级 0ea912c0
import * as zrUtil from 'zrender/src/core/util';
export function retrieveTargetInfo(payload, seriesModel) {
if (payload
&& (
payload.type === 'treemapZoomToNode'
|| payload.type === 'treemapRootToNode'
)
) {
export function retrieveTargetInfo(payload, validPayloadTypes, seriesModel) {
if (payload && zrUtil.indexOf(validPayloadTypes, payload.type) >= 0) {
var root = seriesModel.getData().tree.root;
var targetNode = payload.targetNode;
if (targetNode && root.contains(targetNode)) {
......
......@@ -3,6 +3,7 @@ import * as zrUtil from 'zrender/src/core/util';
import './sunburst/SunburstSeries';
import './sunburst/SunburstView';
import './sunburst/sunburstAction';
import dataColor from '../visual/dataColor';
import sunburstLayout from './sunburst/sunburstLayout';
......
......@@ -288,7 +288,7 @@ export default SunburstPiece;
function getNodeColor(node, seriesModel, ecModel) {
if (node.depth === 0) {
// Virtual root node
return 'transparent';
return ecModel.option.color[0];
}
else {
// Self color or level color
......
import * as zrUtil from 'zrender/src/core/util';
import SeriesModel from '../../model/Series';
import Tree from '../../data/Tree';
import {wrapTreePathInfo} from '../treemap/helper';
import {wrapTreePathInfo} from '../helper/treeHelper';
export default SeriesModel.extend({
......@@ -73,6 +73,9 @@ export default SeriesModel.extend({
// 'ancestor', 'self'
highlightPolicy: 'descendant',
// 'zoomToNode', 'link', or false
nodeClick: 'zoomToNode',
label: {
normal: {
// could be: 'radial', 'tangential', or 'none'
......
import * as zrUtil from 'zrender/src/core/util';
import * as graphic from '../../util/graphic';
import ChartView from '../../view/Chart';
import SunburstPiece from './SunburstPiece';
import DataDiffer from '../../data/DataDiffer';
var ROOT_TO_NODE_ACTION = 'sunburstRootToNode';
var SunburstView = ChartView.extend({
type: 'sunburst',
init: function () {
var sectorGroup = new graphic.Group();
this._sectorGroup = sectorGroup;
/**
* @private
* @type {module:echarts/data/Tree}
* @type {module:echarts/data/Node}
*/
this._oldTree;
this._oldRoot;
},
render: function (seriesModel, ecModel, api, payload) {
if (payload && (payload.from === this.uid)) {
return;
}
var that = this;
this.seriesModel = seriesModel;
this.api = api;
this.ecModel = ecModel;
var virtualRoot = seriesModel.getData().tree.root;
var oldTree = this._oldTree;
var newTree = seriesModel.getData().tree;
var oldRoot = this._oldRoot;
var newRoot = seriesModel.getViewRoot();
var group = this.group;
dualTravel(
newTree.root ? [newTree.root] : [],
(oldTree && oldTree.root) ? [oldTree.root] : []
newRoot ? [newRoot] : [],
oldRoot ? [oldRoot] : []
);
this._data = newTree.root;
this._oldTree = newTree;
renderRollUp(virtualRoot, newRoot);
this._initEvents();
this._oldRoot = newRoot;
function dualTravel(newChildren, oldChildren) {
if (newChildren.length === 0 && oldChildren.length === 0) {
......@@ -66,32 +71,118 @@ var SunburstView = ChartView.extend({
}
function doRenderNode(newNode, oldNode) {
if (newNode !== newTree.root) {
if (newNode !== virtualRoot) {
if (oldNode && oldNode.piece) {
if (newNode) {
// Update
oldNode.piece
.updateData(false, newNode, seriesModel, ecModel);
return;
}
else {
// Remove
group.remove(oldNode.piece);
}
else {
if (newNode) {
// Add
var piece = new SunburstPiece(
newNode,
seriesModel,
ecModel
);
group.add(piece);
return;
}
}
}
// Remove
removeNode(oldNode);
}
function removeNode(node) {
if (!node) {
return;
}
if (node.piece) {
group.remove(node.piece);
node.piece = null;
}
zrUtil.each(node.children, function (child) {
removeNode(child);
});
}
function renderRollUp(virtualRoot, viewRoot) {
if (virtualRoot !== viewRoot) {
// Render
if (virtualRoot.piece) {
// Update
virtualRoot.piece
.updateData(false, virtualRoot, seriesModel, ecModel);
}
else {
// Add
var piece = new SunburstPiece(
newNode,
virtualRoot.piece = new SunburstPiece(
virtualRoot,
seriesModel,
ecModel
);
group.add(piece);
group.add(virtualRoot.piece);
}
virtualRoot.piece.on('click', function (e) {
that._rootToNode(viewRoot.parentNode);
});
}
else if (virtualRoot.piece) {
// Remove
group.remove(virtualRoot.piece);
virtualRoot.piece = null;
}
}
},
dispose: function () {},
dispose: function () {
},
/**
* @private
*/
_initEvents: function () {
var that = this;
this.group.on('click', function (e) {
var nodeClick = that.seriesModel.get('nodeClick', true);
if (!nodeClick) {
return;
}
if (nodeClick === 'zoomToNode') {
var targetFound = false;
var viewRoot = that.seriesModel.getViewRoot();
viewRoot.eachNode(function (node) {
if (!targetFound
&& node.piece && node.piece.childAt(0) === e.target
) {
that._rootToNode(node);
targetFound = true;
}
});
}
});
},
/**
* @private
*/
_rootToNode: function (node) {
this.api.dispatchAction({
type: ROOT_TO_NODE_ACTION,
from: this.uid,
seriesId: this.seriesModel.id,
targetNode: node
});
},
/**
* @implement
......
/**
* @file Sunburst action
*/
import * as echarts from '../../echarts';
import * as helper from '../helper/treeHelper';
var ROOT_TO_NODE_ACTION = 'sunburstRootToNode';
echarts.registerAction(
{type: ROOT_TO_NODE_ACTION, update: 'updateView'},
function (payload, ecModel) {
ecModel.eachComponent(
{mainType: 'series', subType: 'sunburst', query: payload},
handleRootToNode
);
function handleRootToNode(model, index) {
var targetInfo = helper
.retrieveTargetInfo(payload, [ROOT_TO_NODE_ACTION], model);
if (targetInfo) {
var originViewRoot = model.getViewRoot();
if (originViewRoot) {
payload.direction = helper.aboveViewRoot(originViewRoot, targetInfo.node)
? 'rollUp' : 'drillDown';
}
model.resetViewRoot(targetInfo.node);
}
}
}
);
......@@ -25,12 +25,14 @@ export default function (seriesType, ecModel, api, payload) {
var r0 = parsePercent(radius[0], size / 2);
var r = parsePercent(radius[1], size / 2);
var data = seriesModel.getData();
// var data = seriesModel.getData();
var startAngle = -seriesModel.get('startAngle') * RADIAN;
var minAngle = seriesModel.get('minAngle') * RADIAN;
var treeRoot = data.tree.root;
var virtualRoot = seriesModel.getData().tree.root;
var treeRoot = seriesModel.getViewRoot();
var rootDepth = treeRoot.depth;
var sortOrder = seriesModel.get('sortOrder');
if (sortOrder != null) {
......@@ -46,7 +48,9 @@ export default function (seriesType, ecModel, api, payload) {
// Sum may be 0
var unitRadian = Math.PI / (sum || validDataCount) * 2;
var rPerLevel = (r - r0) / (treeRoot.height || 1);
var renderRollupNode = treeRoot !== virtualRoot;
var levels = treeRoot.height + (renderRollupNode ? 1 : 0);
var rPerLevel = (r - r0) / (levels || 1);
var clockwise = seriesModel.get('clockwise');
......@@ -62,17 +66,17 @@ export default function (seriesType, ecModel, api, payload) {
* Render a tree
* @return increased angle
*/
var renderNode = function (root, startAngle) {
if (!root) {
var renderNode = function (node, startAngle) {
if (!node) {
return;
}
var endAngle = startAngle;
// Render self
if (root !== treeRoot) {
// Tree root is virtual, so it doesn't need to be drawn
var value = root.getValue();
if (node !== virtualRoot) {
// Tree node is virtual, so it doesn't need to be drawn
var value = node.getValue();
var angle = (sum === 0 && stillShowZeroSum)
? unitRadian : (value * unitRadian);
......@@ -86,16 +90,19 @@ export default function (seriesType, ecModel, api, payload) {
endAngle = startAngle + dir * angle;
var rStart = r0 + rPerLevel * (root.depth - 1);
var rEnd = r0 + rPerLevel * root.depth;
var depth = node.depth - rootDepth + (renderRollupNode ? 1 : 0);
var rStart = r0 + rPerLevel * depth;
var rEnd = r0 + rPerLevel * (depth + 1);
var itemModel = root.getModel();
var itemModel = node.getModel();
if (itemModel.get('r0') != null) {
rStart = parsePercent(itemModel.get('r0'), size / 2);
}
if (itemModel.get('r') != null) {
rEnd = parsePercent(itemModel.get('r'), size / 2);
}
root.setLayout({
node.setLayout({
angle: angle,
startAngle: startAngle,
endAngle: endAngle,
......@@ -108,10 +115,10 @@ export default function (seriesType, ecModel, api, payload) {
}
// Render children
if (root.children && root.children.length) {
if (node.children && node.children.length) {
// currentAngle = startAngle;
var siblingAngle = 0;
zrUtil.each(root.children, function (node) {
zrUtil.each(node.children, function (node) {
siblingAngle += renderNode(node, startAngle + siblingAngle);
});
}
......@@ -119,6 +126,24 @@ export default function (seriesType, ecModel, api, payload) {
return endAngle - startAngle;
};
// Virtual root node for roll up
if (renderRollupNode) {
var rStart = r0;
var rEnd = r0 + rPerLevel;
var angle = Math.PI * 2;
virtualRoot.setLayout({
angle: angle,
startAngle: startAngle,
endAngle: startAngle + angle,
clockwise: clockwise,
cx: cx,
cy: cy,
r0: rStart,
r: rEnd
});
}
renderNode(treeRoot, startAngle);
});
}
......
import * as graphic from '../../util/graphic';
import * as layout from '../../util/layout';
import * as zrUtil from 'zrender/src/core/util';
import {wrapTreePathInfo} from './helper';
import {wrapTreePathInfo} from '../helper/treeHelper';
var TEXT_PADDING = 8;
var ITEM_GAP = 8;
......
......@@ -3,7 +3,7 @@ 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';
import {wrapTreePathInfo} from '../helper/treeHelper';
export default SeriesModel.extend({
......
......@@ -2,7 +2,7 @@ import * as echarts from '../../echarts';
import * as zrUtil from 'zrender/src/core/util';
import * as graphic from '../../util/graphic';
import DataDiffer from '../../data/DataDiffer';
import * as helper from './helper';
import * as helper from '../helper/treeHelper';
import Breadcrumb from './Breadcrumb';
import RoamController from '../../component/helper/RoamController';
import BoundingRect from 'zrender/src/core/BoundingRect';
......@@ -105,7 +105,9 @@ export default echarts.extendChartView({
this.api = api;
this.ecModel = ecModel;
var targetInfo = helper.retrieveTargetInfo(payload, seriesModel);
var types = ['treemapZoomToNode', 'treemapRootToNode'];
var targetInfo = helper
.retrieveTargetInfo(payload, types, seriesModel);
var payloadType = payload && payload.type;
var layoutInfo = seriesModel.layoutInfo;
var isInit = !this._oldTree;
......
......@@ -3,7 +3,7 @@
*/
import * as echarts from '../../echarts';
import * as helper from './helper';
import * as helper from '../helper/treeHelper';
var noop = function () {};
......@@ -27,7 +27,8 @@ echarts.registerAction(
);
function handleRootToNode(model, index) {
var targetInfo = helper.retrieveTargetInfo(payload, model);
var types = ['treemapZoomToNode', 'treemapRootToNode'];
var targetInfo = helper.retrieveTargetInfo(payload, types, model);
if (targetInfo) {
var originViewRoot = model.getViewRoot();
......
......@@ -2,7 +2,7 @@ import * as zrUtil from 'zrender/src/core/util';
import BoundingRect from 'zrender/src/core/BoundingRect';
import {parsePercent, MAX_SAFE_INTEGER} from '../../util/number';
import * as layout from '../../util/layout';
import * as helper from './helper';
import * as helper from '../helper/treeHelper';
var mathMax = Math.max;
var mathMin = Math.min;
......@@ -47,7 +47,9 @@ export default function (ecModel, api, payload) {
// Fetch payload info.
var payloadType = payload && payload.type;
var targetInfo = helper.retrieveTargetInfo(payload, seriesModel);
var types = ['treemapZoomToNode', 'treemapRootToNode'];
var targetInfo = helper
.retrieveTargetInfo(payload, types, seriesModel);
var rootRect = (payloadType === 'treemapRender' || payloadType === 'treemapMove')
? payload.rootRect : null;
var viewRoot = seriesModel.getViewRoot();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册