123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883 |
- /*
- * 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.
- */
- /**
- * AUTO-GENERATED FILE. DO NOT MODIFY.
- */
- /*
- * 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 { __extends } from "tslib";
- import { bind, each, indexOf, curry, extend, normalizeCssArray, isFunction } from 'zrender/lib/core/util.js';
- import * as graphic from '../../util/graphic.js';
- import { getECData } from '../../util/innerStore.js';
- import { isHighDownDispatcher, setAsHighDownDispatcher, setDefaultStateProxy, enableHoverFocus, Z2_EMPHASIS_LIFT } from '../../util/states.js';
- import DataDiffer from '../../data/DataDiffer.js';
- import * as helper from '../helper/treeHelper.js';
- import Breadcrumb from './Breadcrumb.js';
- import RoamController from '../../component/helper/RoamController.js';
- import BoundingRect from 'zrender/lib/core/BoundingRect.js';
- import * as matrix from 'zrender/lib/core/matrix.js';
- import * as animationUtil from '../../util/animation.js';
- import makeStyleMapper from '../../model/mixin/makeStyleMapper.js';
- import ChartView from '../../view/Chart.js';
- import Displayable from 'zrender/lib/graphic/Displayable.js';
- import { makeInner, convertOptionIdName } from '../../util/model.js';
- import { windowOpen } from '../../util/format.js';
- import { setLabelStyle, getLabelStatesModels } from '../../label/labelStyle.js';
- var Group = graphic.Group;
- var Rect = graphic.Rect;
- var DRAG_THRESHOLD = 3;
- var PATH_LABEL_NOAMAL = 'label';
- var PATH_UPPERLABEL_NORMAL = 'upperLabel';
- // Should larger than emphasis states lift z
- var Z2_BASE = Z2_EMPHASIS_LIFT * 10; // Should bigger than every z2.
- var Z2_BG = Z2_EMPHASIS_LIFT * 2;
- var Z2_CONTENT = Z2_EMPHASIS_LIFT * 3;
- var getStateItemStyle = makeStyleMapper([['fill', 'color'],
- // `borderColor` and `borderWidth` has been occupied,
- // so use `stroke` to indicate the stroke of the rect.
- ['stroke', 'strokeColor'], ['lineWidth', 'strokeWidth'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor']
- // Option decal is in `DecalObject` but style.decal is in `PatternObject`.
- // So do not transfer decal directly.
- ]);
- var getItemStyleNormal = function (model) {
- // Normal style props should include emphasis style props.
- var itemStyle = getStateItemStyle(model);
- // Clear styles set by emphasis.
- itemStyle.stroke = itemStyle.fill = itemStyle.lineWidth = null;
- return itemStyle;
- };
- var inner = makeInner();
- var TreemapView = /** @class */function (_super) {
- __extends(TreemapView, _super);
- function TreemapView() {
- var _this = _super !== null && _super.apply(this, arguments) || this;
- _this.type = TreemapView.type;
- _this._state = 'ready';
- _this._storage = createStorage();
- return _this;
- }
- /**
- * @override
- */
- TreemapView.prototype.render = function (seriesModel, ecModel, api, payload) {
- var models = ecModel.findComponents({
- mainType: 'series',
- subType: 'treemap',
- query: payload
- });
- if (indexOf(models, seriesModel) < 0) {
- return;
- }
- this.seriesModel = seriesModel;
- this.api = api;
- this.ecModel = ecModel;
- var types = ['treemapZoomToNode', 'treemapRootToNode'];
- var targetInfo = helper.retrieveTargetInfo(payload, types, seriesModel);
- var payloadType = payload && payload.type;
- var layoutInfo = seriesModel.layoutInfo;
- var isInit = !this._oldTree;
- var thisStorage = this._storage;
- // Mark new root when action is treemapRootToNode.
- var reRoot = payloadType === 'treemapRootToNode' && targetInfo && thisStorage ? {
- rootNodeGroup: thisStorage.nodeGroup[targetInfo.node.getRawIndex()],
- direction: payload.direction
- } : null;
- var containerGroup = this._giveContainerGroup(layoutInfo);
- var hasAnimation = seriesModel.get('animation');
- var renderResult = this._doRender(containerGroup, seriesModel, reRoot);
- hasAnimation && !isInit && (!payloadType || payloadType === 'treemapZoomToNode' || payloadType === 'treemapRootToNode') ? this._doAnimation(containerGroup, renderResult, seriesModel, reRoot) : renderResult.renderFinally();
- this._resetController(api);
- this._renderBreadcrumb(seriesModel, api, targetInfo);
- };
- TreemapView.prototype._giveContainerGroup = function (layoutInfo) {
- var containerGroup = this._containerGroup;
- if (!containerGroup) {
- // FIXME
- // 加一层containerGroup是为了clip,但是现在clip功能并没有实现。
- containerGroup = this._containerGroup = new Group();
- this._initEvents(containerGroup);
- this.group.add(containerGroup);
- }
- containerGroup.x = layoutInfo.x;
- containerGroup.y = layoutInfo.y;
- return containerGroup;
- };
- TreemapView.prototype._doRender = function (containerGroup, seriesModel, reRoot) {
- var thisTree = seriesModel.getData().tree;
- var oldTree = this._oldTree;
- // Clear last shape records.
- var lastsForAnimation = createStorage();
- var thisStorage = createStorage();
- var oldStorage = this._storage;
- var willInvisibleEls = [];
- function doRenderNode(thisNode, oldNode, parentGroup, depth) {
- return renderNode(seriesModel, thisStorage, oldStorage, reRoot, lastsForAnimation, willInvisibleEls, thisNode, oldNode, parentGroup, depth);
- }
- // Notice: When thisTree and oldTree are the same tree (see list.cloneShallow),
- // the oldTree is actually losted, so we cannot find all of the old graphic
- // elements from tree. So we use this strategy: make element storage, move
- // from old storage to new storage, clear old storage.
- dualTravel(thisTree.root ? [thisTree.root] : [], oldTree && oldTree.root ? [oldTree.root] : [], containerGroup, thisTree === oldTree || !oldTree, 0);
- // Process all removing.
- var willDeleteEls = clearStorage(oldStorage);
- this._oldTree = thisTree;
- this._storage = thisStorage;
- if (this._controllerHost) {
- var _oldRootLayout = this.seriesModel.layoutInfo;
- var rootLayout = thisTree.root.getLayout();
- if (rootLayout.width === _oldRootLayout.width && rootLayout.height === _oldRootLayout.height) {
- this._controllerHost.zoom = 1;
- }
- }
- return {
- lastsForAnimation: lastsForAnimation,
- willDeleteEls: willDeleteEls,
- renderFinally: renderFinally
- };
- function dualTravel(thisViewChildren, oldViewChildren, parentGroup, sameTree, depth) {
- // When 'render' is triggered by action,
- // 'this' and 'old' may be the same tree,
- // we use rawIndex in that case.
- if (sameTree) {
- oldViewChildren = thisViewChildren;
- each(thisViewChildren, function (child, index) {
- !child.isRemoved() && processNode(index, index);
- });
- }
- // Diff hierarchically (diff only in each subtree, but not whole).
- // because, consistency of view is important.
- else {
- new DataDiffer(oldViewChildren, thisViewChildren, getKey, getKey).add(processNode).update(processNode).remove(curry(processNode, null)).execute();
- }
- function getKey(node) {
- // Identify by name or raw index.
- return node.getId();
- }
- function processNode(newIndex, oldIndex) {
- var thisNode = newIndex != null ? thisViewChildren[newIndex] : null;
- var oldNode = oldIndex != null ? oldViewChildren[oldIndex] : null;
- var group = doRenderNode(thisNode, oldNode, parentGroup, depth);
- group && dualTravel(thisNode && thisNode.viewChildren || [], oldNode && oldNode.viewChildren || [], group, sameTree, depth + 1);
- }
- }
- function clearStorage(storage) {
- var willDeleteEls = createStorage();
- storage && each(storage, function (store, storageName) {
- var delEls = willDeleteEls[storageName];
- each(store, function (el) {
- el && (delEls.push(el), inner(el).willDelete = true);
- });
- });
- return willDeleteEls;
- }
- function renderFinally() {
- each(willDeleteEls, function (els) {
- each(els, function (el) {
- el.parent && el.parent.remove(el);
- });
- });
- each(willInvisibleEls, function (el) {
- el.invisible = true;
- // Setting invisible is for optimizing, so no need to set dirty,
- // just mark as invisible.
- el.dirty();
- });
- }
- };
- TreemapView.prototype._doAnimation = function (containerGroup, renderResult, seriesModel, reRoot) {
- var durationOption = seriesModel.get('animationDurationUpdate');
- var easingOption = seriesModel.get('animationEasing');
- // TODO: do not support function until necessary.
- var duration = (isFunction(durationOption) ? 0 : durationOption) || 0;
- var easing = (isFunction(easingOption) ? null : easingOption) || 'cubicOut';
- var animationWrap = animationUtil.createWrap();
- // Make delete animations.
- each(renderResult.willDeleteEls, function (store, storageName) {
- each(store, function (el, rawIndex) {
- if (el.invisible) {
- return;
- }
- var parent = el.parent; // Always has parent, and parent is nodeGroup.
- var target;
- var innerStore = inner(parent);
- if (reRoot && reRoot.direction === 'drillDown') {
- target = parent === reRoot.rootNodeGroup
- // This is the content element of view root.
- // Only `content` will enter this branch, because
- // `background` and `nodeGroup` will not be deleted.
- ? {
- shape: {
- x: 0,
- y: 0,
- width: innerStore.nodeWidth,
- height: innerStore.nodeHeight
- },
- style: {
- opacity: 0
- }
- }
- // Others.
- : {
- style: {
- opacity: 0
- }
- };
- } else {
- var targetX = 0;
- var targetY = 0;
- if (!innerStore.willDelete) {
- // Let node animate to right-bottom corner, cooperating with fadeout,
- // which is appropriate for user understanding.
- // Divided by 2 for reRoot rolling up effect.
- targetX = innerStore.nodeWidth / 2;
- targetY = innerStore.nodeHeight / 2;
- }
- target = storageName === 'nodeGroup' ? {
- x: targetX,
- y: targetY,
- style: {
- opacity: 0
- }
- } : {
- shape: {
- x: targetX,
- y: targetY,
- width: 0,
- height: 0
- },
- style: {
- opacity: 0
- }
- };
- }
- // TODO: do not support delay until necessary.
- target && animationWrap.add(el, target, duration, 0, easing);
- });
- });
- // Make other animations
- each(this._storage, function (store, storageName) {
- each(store, function (el, rawIndex) {
- var last = renderResult.lastsForAnimation[storageName][rawIndex];
- var target = {};
- if (!last) {
- return;
- }
- if (el instanceof graphic.Group) {
- if (last.oldX != null) {
- target.x = el.x;
- target.y = el.y;
- el.x = last.oldX;
- el.y = last.oldY;
- }
- } else {
- if (last.oldShape) {
- target.shape = extend({}, el.shape);
- el.setShape(last.oldShape);
- }
- if (last.fadein) {
- el.setStyle('opacity', 0);
- target.style = {
- opacity: 1
- };
- }
- // When animation is stopped for succedent animation starting,
- // el.style.opacity might not be 1
- else if (el.style.opacity !== 1) {
- target.style = {
- opacity: 1
- };
- }
- }
- animationWrap.add(el, target, duration, 0, easing);
- });
- }, this);
- this._state = 'animating';
- animationWrap.finished(bind(function () {
- this._state = 'ready';
- renderResult.renderFinally();
- }, this)).start();
- };
- TreemapView.prototype._resetController = function (api) {
- var controller = this._controller;
- var controllerHost = this._controllerHost;
- if (!controllerHost) {
- this._controllerHost = {
- target: this.group
- };
- controllerHost = this._controllerHost;
- }
- // Init controller.
- if (!controller) {
- controller = this._controller = new RoamController(api.getZr());
- controller.enable(this.seriesModel.get('roam'));
- controllerHost.zoomLimit = this.seriesModel.get('scaleLimit');
- controllerHost.zoom = this.seriesModel.get('zoom');
- controller.on('pan', bind(this._onPan, this));
- controller.on('zoom', bind(this._onZoom, this));
- }
- var rect = new BoundingRect(0, 0, api.getWidth(), api.getHeight());
- controller.setPointerChecker(function (e, x, y) {
- return rect.contain(x, y);
- });
- };
- TreemapView.prototype._clearController = function () {
- var controller = this._controller;
- this._controllerHost = null;
- if (controller) {
- controller.dispose();
- controller = null;
- }
- };
- TreemapView.prototype._onPan = function (e) {
- if (this._state !== 'animating' && (Math.abs(e.dx) > DRAG_THRESHOLD || Math.abs(e.dy) > DRAG_THRESHOLD)) {
- // These param must not be cached.
- var root = this.seriesModel.getData().tree.root;
- if (!root) {
- return;
- }
- var rootLayout = root.getLayout();
- if (!rootLayout) {
- return;
- }
- this.api.dispatchAction({
- type: 'treemapMove',
- from: this.uid,
- seriesId: this.seriesModel.id,
- rootRect: {
- x: rootLayout.x + e.dx,
- y: rootLayout.y + e.dy,
- width: rootLayout.width,
- height: rootLayout.height
- }
- });
- }
- };
- TreemapView.prototype._onZoom = function (e) {
- var mouseX = e.originX;
- var mouseY = e.originY;
- var zoomDelta = e.scale;
- if (this._state !== 'animating') {
- // These param must not be cached.
- var root = this.seriesModel.getData().tree.root;
- if (!root) {
- return;
- }
- var rootLayout = root.getLayout();
- if (!rootLayout) {
- return;
- }
- var rect = new BoundingRect(rootLayout.x, rootLayout.y, rootLayout.width, rootLayout.height);
- // scaleLimit
- var zoomLimit = null;
- var _controllerHost = this._controllerHost;
- zoomLimit = _controllerHost.zoomLimit;
- var newZoom = _controllerHost.zoom = _controllerHost.zoom || 1;
- newZoom *= zoomDelta;
- if (zoomLimit) {
- var zoomMin = zoomLimit.min || 0;
- var zoomMax = zoomLimit.max || Infinity;
- newZoom = Math.max(Math.min(zoomMax, newZoom), zoomMin);
- }
- var zoomScale = newZoom / _controllerHost.zoom;
- _controllerHost.zoom = newZoom;
- var layoutInfo = this.seriesModel.layoutInfo;
- // Transform mouse coord from global to containerGroup.
- mouseX -= layoutInfo.x;
- mouseY -= layoutInfo.y;
- // Scale root bounding rect.
- var m = matrix.create();
- matrix.translate(m, m, [-mouseX, -mouseY]);
- matrix.scale(m, m, [zoomScale, zoomScale]);
- matrix.translate(m, m, [mouseX, mouseY]);
- rect.applyTransform(m);
- this.api.dispatchAction({
- type: 'treemapRender',
- from: this.uid,
- seriesId: this.seriesModel.id,
- rootRect: {
- x: rect.x,
- y: rect.y,
- width: rect.width,
- height: rect.height
- }
- });
- }
- };
- TreemapView.prototype._initEvents = function (containerGroup) {
- var _this = this;
- containerGroup.on('click', function (e) {
- if (_this._state !== 'ready') {
- return;
- }
- var nodeClick = _this.seriesModel.get('nodeClick', true);
- if (!nodeClick) {
- return;
- }
- var targetInfo = _this.findTarget(e.offsetX, e.offsetY);
- if (!targetInfo) {
- return;
- }
- var node = targetInfo.node;
- if (node.getLayout().isLeafRoot) {
- _this._rootToNode(targetInfo);
- } else {
- if (nodeClick === 'zoomToNode') {
- _this._zoomToNode(targetInfo);
- } else if (nodeClick === 'link') {
- var itemModel = node.hostTree.data.getItemModel(node.dataIndex);
- var link = itemModel.get('link', true);
- var linkTarget = itemModel.get('target', true) || 'blank';
- link && windowOpen(link, linkTarget);
- }
- }
- }, this);
- };
- TreemapView.prototype._renderBreadcrumb = function (seriesModel, api, targetInfo) {
- var _this = this;
- if (!targetInfo) {
- targetInfo = seriesModel.get('leafDepth', true) != null ? {
- node: seriesModel.getViewRoot()
- }
- // FIXME
- // better way?
- // Find breadcrumb tail on center of containerGroup.
- : this.findTarget(api.getWidth() / 2, api.getHeight() / 2);
- if (!targetInfo) {
- targetInfo = {
- node: seriesModel.getData().tree.root
- };
- }
- }
- (this._breadcrumb || (this._breadcrumb = new Breadcrumb(this.group))).render(seriesModel, api, targetInfo.node, function (node) {
- if (_this._state !== 'animating') {
- helper.aboveViewRoot(seriesModel.getViewRoot(), node) ? _this._rootToNode({
- node: node
- }) : _this._zoomToNode({
- node: node
- });
- }
- });
- };
- /**
- * @override
- */
- TreemapView.prototype.remove = function () {
- this._clearController();
- this._containerGroup && this._containerGroup.removeAll();
- this._storage = createStorage();
- this._state = 'ready';
- this._breadcrumb && this._breadcrumb.remove();
- };
- TreemapView.prototype.dispose = function () {
- this._clearController();
- };
- TreemapView.prototype._zoomToNode = function (targetInfo) {
- this.api.dispatchAction({
- type: 'treemapZoomToNode',
- from: this.uid,
- seriesId: this.seriesModel.id,
- targetNode: targetInfo.node
- });
- };
- TreemapView.prototype._rootToNode = function (targetInfo) {
- this.api.dispatchAction({
- type: 'treemapRootToNode',
- from: this.uid,
- seriesId: this.seriesModel.id,
- targetNode: targetInfo.node
- });
- };
- /**
- * @public
- * @param {number} x Global coord x.
- * @param {number} y Global coord y.
- * @return {Object} info If not found, return undefined;
- * @return {number} info.node Target node.
- * @return {number} info.offsetX x refer to target node.
- * @return {number} info.offsetY y refer to target node.
- */
- TreemapView.prototype.findTarget = function (x, y) {
- var targetInfo;
- var viewRoot = this.seriesModel.getViewRoot();
- viewRoot.eachNode({
- attr: 'viewChildren',
- order: 'preorder'
- }, function (node) {
- var bgEl = this._storage.background[node.getRawIndex()];
- // If invisible, there might be no element.
- if (bgEl) {
- var point = bgEl.transformCoordToLocal(x, y);
- var shape = bgEl.shape;
- // For performance consideration, don't use 'getBoundingRect'.
- if (shape.x <= point[0] && point[0] <= shape.x + shape.width && shape.y <= point[1] && point[1] <= shape.y + shape.height) {
- targetInfo = {
- node: node,
- offsetX: point[0],
- offsetY: point[1]
- };
- } else {
- return false; // Suppress visit subtree.
- }
- }
- }, this);
- return targetInfo;
- };
- TreemapView.type = 'treemap';
- return TreemapView;
- }(ChartView);
- /**
- * @inner
- */
- function createStorage() {
- return {
- nodeGroup: [],
- background: [],
- content: []
- };
- }
- /**
- * @inner
- * @return Return undefined means do not travel further.
- */
- function renderNode(seriesModel, thisStorage, oldStorage, reRoot, lastsForAnimation, willInvisibleEls, thisNode, oldNode, parentGroup, depth) {
- // Whether under viewRoot.
- if (!thisNode) {
- // Deleting nodes will be performed finally. This method just find
- // element from old storage, or create new element, set them to new
- // storage, and set styles.
- return;
- }
- // -------------------------------------------------------------------
- // Start of closure variables available in "Procedures in renderNode".
- var thisLayout = thisNode.getLayout();
- var data = seriesModel.getData();
- var nodeModel = thisNode.getModel();
- // Only for enabling highlight/downplay. Clear firstly.
- // Because some node will not be rendered.
- data.setItemGraphicEl(thisNode.dataIndex, null);
- if (!thisLayout || !thisLayout.isInView) {
- return;
- }
- var thisWidth = thisLayout.width;
- var thisHeight = thisLayout.height;
- var borderWidth = thisLayout.borderWidth;
- var thisInvisible = thisLayout.invisible;
- var thisRawIndex = thisNode.getRawIndex();
- var oldRawIndex = oldNode && oldNode.getRawIndex();
- var thisViewChildren = thisNode.viewChildren;
- var upperHeight = thisLayout.upperHeight;
- var isParent = thisViewChildren && thisViewChildren.length;
- var itemStyleNormalModel = nodeModel.getModel('itemStyle');
- var itemStyleEmphasisModel = nodeModel.getModel(['emphasis', 'itemStyle']);
- var itemStyleBlurModel = nodeModel.getModel(['blur', 'itemStyle']);
- var itemStyleSelectModel = nodeModel.getModel(['select', 'itemStyle']);
- var borderRadius = itemStyleNormalModel.get('borderRadius') || 0;
- // End of closure ariables available in "Procedures in renderNode".
- // -----------------------------------------------------------------
- // Node group
- var group = giveGraphic('nodeGroup', Group);
- if (!group) {
- return;
- }
- parentGroup.add(group);
- // x,y are not set when el is above view root.
- group.x = thisLayout.x || 0;
- group.y = thisLayout.y || 0;
- group.markRedraw();
- inner(group).nodeWidth = thisWidth;
- inner(group).nodeHeight = thisHeight;
- if (thisLayout.isAboveViewRoot) {
- return group;
- }
- // Background
- var bg = giveGraphic('background', Rect, depth, Z2_BG);
- bg && renderBackground(group, bg, isParent && thisLayout.upperLabelHeight);
- var emphasisModel = nodeModel.getModel('emphasis');
- var focus = emphasisModel.get('focus');
- var blurScope = emphasisModel.get('blurScope');
- var isDisabled = emphasisModel.get('disabled');
- var focusOrIndices = focus === 'ancestor' ? thisNode.getAncestorsIndices() : focus === 'descendant' ? thisNode.getDescendantIndices() : focus;
- // No children, render content.
- if (isParent) {
- // Because of the implementation about "traverse" in graphic hover style, we
- // can not set hover listener on the "group" of non-leaf node. Otherwise the
- // hover event from the descendents will be listenered.
- if (isHighDownDispatcher(group)) {
- setAsHighDownDispatcher(group, false);
- }
- if (bg) {
- setAsHighDownDispatcher(bg, !isDisabled);
- // Only for enabling highlight/downplay.
- data.setItemGraphicEl(thisNode.dataIndex, bg);
- enableHoverFocus(bg, focusOrIndices, blurScope);
- }
- } else {
- var content = giveGraphic('content', Rect, depth, Z2_CONTENT);
- content && renderContent(group, content);
- bg.disableMorphing = true;
- if (bg && isHighDownDispatcher(bg)) {
- setAsHighDownDispatcher(bg, false);
- }
- setAsHighDownDispatcher(group, !isDisabled);
- // Only for enabling highlight/downplay.
- data.setItemGraphicEl(thisNode.dataIndex, group);
- enableHoverFocus(group, focusOrIndices, blurScope);
- }
- return group;
- // ----------------------------
- // | Procedures in renderNode |
- // ----------------------------
- function renderBackground(group, bg, useUpperLabel) {
- var ecData = getECData(bg);
- // For tooltip.
- ecData.dataIndex = thisNode.dataIndex;
- ecData.seriesIndex = seriesModel.seriesIndex;
- bg.setShape({
- x: 0,
- y: 0,
- width: thisWidth,
- height: thisHeight,
- r: borderRadius
- });
- if (thisInvisible) {
- // If invisible, do not set visual, otherwise the element will
- // change immediately before animation. We think it is OK to
- // remain its origin color when moving out of the view window.
- processInvisible(bg);
- } else {
- bg.invisible = false;
- var style = thisNode.getVisual('style');
- var visualBorderColor = style.stroke;
- var normalStyle = getItemStyleNormal(itemStyleNormalModel);
- normalStyle.fill = visualBorderColor;
- var emphasisStyle = getStateItemStyle(itemStyleEmphasisModel);
- emphasisStyle.fill = itemStyleEmphasisModel.get('borderColor');
- var blurStyle = getStateItemStyle(itemStyleBlurModel);
- blurStyle.fill = itemStyleBlurModel.get('borderColor');
- var selectStyle = getStateItemStyle(itemStyleSelectModel);
- selectStyle.fill = itemStyleSelectModel.get('borderColor');
- if (useUpperLabel) {
- var upperLabelWidth = thisWidth - 2 * borderWidth;
- prepareText(
- // PENDING: convert ZRColor to ColorString for text.
- bg, visualBorderColor, style.opacity, {
- x: borderWidth,
- y: 0,
- width: upperLabelWidth,
- height: upperHeight
- });
- }
- // For old bg.
- else {
- bg.removeTextContent();
- }
- bg.setStyle(normalStyle);
- bg.ensureState('emphasis').style = emphasisStyle;
- bg.ensureState('blur').style = blurStyle;
- bg.ensureState('select').style = selectStyle;
- setDefaultStateProxy(bg);
- }
- group.add(bg);
- }
- function renderContent(group, content) {
- var ecData = getECData(content);
- // For tooltip.
- ecData.dataIndex = thisNode.dataIndex;
- ecData.seriesIndex = seriesModel.seriesIndex;
- var contentWidth = Math.max(thisWidth - 2 * borderWidth, 0);
- var contentHeight = Math.max(thisHeight - 2 * borderWidth, 0);
- content.culling = true;
- content.setShape({
- x: borderWidth,
- y: borderWidth,
- width: contentWidth,
- height: contentHeight,
- r: borderRadius
- });
- if (thisInvisible) {
- // If invisible, do not set visual, otherwise the element will
- // change immediately before animation. We think it is OK to
- // remain its origin color when moving out of the view window.
- processInvisible(content);
- } else {
- content.invisible = false;
- var nodeStyle = thisNode.getVisual('style');
- var visualColor = nodeStyle.fill;
- var normalStyle = getItemStyleNormal(itemStyleNormalModel);
- normalStyle.fill = visualColor;
- normalStyle.decal = nodeStyle.decal;
- var emphasisStyle = getStateItemStyle(itemStyleEmphasisModel);
- var blurStyle = getStateItemStyle(itemStyleBlurModel);
- var selectStyle = getStateItemStyle(itemStyleSelectModel);
- // PENDING: convert ZRColor to ColorString for text.
- prepareText(content, visualColor, nodeStyle.opacity, null);
- content.setStyle(normalStyle);
- content.ensureState('emphasis').style = emphasisStyle;
- content.ensureState('blur').style = blurStyle;
- content.ensureState('select').style = selectStyle;
- setDefaultStateProxy(content);
- }
- group.add(content);
- }
- function processInvisible(element) {
- // Delay invisible setting utill animation finished,
- // avoid element vanish suddenly before animation.
- !element.invisible && willInvisibleEls.push(element);
- }
- function prepareText(rectEl, visualColor, visualOpacity,
- // Can be null/undefined
- upperLabelRect) {
- var normalLabelModel = nodeModel.getModel(upperLabelRect ? PATH_UPPERLABEL_NORMAL : PATH_LABEL_NOAMAL);
- var defaultText = convertOptionIdName(nodeModel.get('name'), null);
- var isShow = normalLabelModel.getShallow('show');
- setLabelStyle(rectEl, getLabelStatesModels(nodeModel, upperLabelRect ? PATH_UPPERLABEL_NORMAL : PATH_LABEL_NOAMAL), {
- defaultText: isShow ? defaultText : null,
- inheritColor: visualColor,
- defaultOpacity: visualOpacity,
- labelFetcher: seriesModel,
- labelDataIndex: thisNode.dataIndex
- });
- var textEl = rectEl.getTextContent();
- if (!textEl) {
- return;
- }
- var textStyle = textEl.style;
- var textPadding = normalizeCssArray(textStyle.padding || 0);
- if (upperLabelRect) {
- rectEl.setTextConfig({
- layoutRect: upperLabelRect
- });
- textEl.disableLabelLayout = true;
- }
- textEl.beforeUpdate = function () {
- var width = Math.max((upperLabelRect ? upperLabelRect.width : rectEl.shape.width) - textPadding[1] - textPadding[3], 0);
- var height = Math.max((upperLabelRect ? upperLabelRect.height : rectEl.shape.height) - textPadding[0] - textPadding[2], 0);
- if (textStyle.width !== width || textStyle.height !== height) {
- textEl.setStyle({
- width: width,
- height: height
- });
- }
- };
- textStyle.truncateMinChar = 2;
- textStyle.lineOverflow = 'truncate';
- addDrillDownIcon(textStyle, upperLabelRect, thisLayout);
- var textEmphasisState = textEl.getState('emphasis');
- addDrillDownIcon(textEmphasisState ? textEmphasisState.style : null, upperLabelRect, thisLayout);
- }
- function addDrillDownIcon(style, upperLabelRect, thisLayout) {
- var text = style ? style.text : null;
- if (!upperLabelRect && thisLayout.isLeafRoot && text != null) {
- var iconChar = seriesModel.get('drillDownIcon', true);
- style.text = iconChar ? iconChar + ' ' + text : text;
- }
- }
- function giveGraphic(storageName, Ctor, depth, z) {
- var element = oldRawIndex != null && oldStorage[storageName][oldRawIndex];
- var lasts = lastsForAnimation[storageName];
- if (element) {
- // Remove from oldStorage
- oldStorage[storageName][oldRawIndex] = null;
- prepareAnimationWhenHasOld(lasts, element);
- }
- // If invisible and no old element, do not create new element (for optimizing).
- else if (!thisInvisible) {
- element = new Ctor();
- if (element instanceof Displayable) {
- element.z2 = calculateZ2(depth, z);
- }
- prepareAnimationWhenNoOld(lasts, element);
- }
- // Set to thisStorage
- return thisStorage[storageName][thisRawIndex] = element;
- }
- function prepareAnimationWhenHasOld(lasts, element) {
- var lastCfg = lasts[thisRawIndex] = {};
- if (element instanceof Group) {
- lastCfg.oldX = element.x;
- lastCfg.oldY = element.y;
- } else {
- lastCfg.oldShape = extend({}, element.shape);
- }
- }
- // If a element is new, we need to find the animation start point carefully,
- // otherwise it will looks strange when 'zoomToNode'.
- function prepareAnimationWhenNoOld(lasts, element) {
- var lastCfg = lasts[thisRawIndex] = {};
- var parentNode = thisNode.parentNode;
- var isGroup = element instanceof graphic.Group;
- if (parentNode && (!reRoot || reRoot.direction === 'drillDown')) {
- var parentOldX = 0;
- var parentOldY = 0;
- // New nodes appear from right-bottom corner in 'zoomToNode' animation.
- // For convenience, get old bounding rect from background.
- var parentOldBg = lastsForAnimation.background[parentNode.getRawIndex()];
- if (!reRoot && parentOldBg && parentOldBg.oldShape) {
- parentOldX = parentOldBg.oldShape.width;
- parentOldY = parentOldBg.oldShape.height;
- }
- // When no parent old shape found, its parent is new too,
- // so we can just use {x:0, y:0}.
- if (isGroup) {
- lastCfg.oldX = 0;
- lastCfg.oldY = parentOldY;
- } else {
- lastCfg.oldShape = {
- x: parentOldX,
- y: parentOldY,
- width: 0,
- height: 0
- };
- }
- }
- // Fade in, user can be aware that these nodes are new.
- lastCfg.fadein = !isGroup;
- }
- }
- // We cannot set all background with the same z, because the behaviour of
- // drill down and roll up differ background creation sequence from tree
- // hierarchy sequence, which cause lower background elements to overlap
- // upper ones. So we calculate z based on depth.
- // Moreover, we try to shrink down z interval to [0, 1] to avoid that
- // treemap with large z overlaps other components.
- function calculateZ2(depth, z2InLevel) {
- return depth * Z2_BASE + z2InLevel;
- }
- export default TreemapView;
|