123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941 |
- /*
- * 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 echarts = require("../../echarts");
- var zrUtil = require("zrender/lib/core/util");
- var graphic = require("../../util/graphic");
- var DataDiffer = require("../../data/DataDiffer");
- var helper = require("../helper/treeHelper");
- var Breadcrumb = require("./Breadcrumb");
- var RoamController = require("../../component/helper/RoamController");
- var BoundingRect = require("zrender/lib/core/BoundingRect");
- var matrix = require("zrender/lib/core/matrix");
- var animationUtil = require("../../util/animation");
- var makeStyleMapper = require("../../model/mixin/makeStyleMapper");
- var _format = require("../../util/format");
- var windowOpen = _format.windowOpen;
- /*
- * 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 bind = zrUtil.bind;
- var Group = graphic.Group;
- var Rect = graphic.Rect;
- var each = zrUtil.each;
- var DRAG_THRESHOLD = 3;
- var PATH_LABEL_NOAMAL = ['label'];
- var PATH_LABEL_EMPHASIS = ['emphasis', 'label'];
- var PATH_UPPERLABEL_NORMAL = ['upperLabel'];
- var PATH_UPPERLABEL_EMPHASIS = ['emphasis', 'upperLabel'];
- var Z_BASE = 10; // Should bigger than every z.
- var Z_BG = 1;
- var Z_CONTENT = 2;
- var getItemStyleEmphasis = 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']]);
- var getItemStyleNormal = function (model) {
- // Normal style props should include emphasis style props.
- var itemStyle = getItemStyleEmphasis(model); // Clear styles set by emphasis.
- itemStyle.stroke = itemStyle.fill = itemStyle.lineWidth = null;
- return itemStyle;
- };
- var _default = echarts.extendChartView({
- type: 'treemap',
- /**
- * @override
- */
- init: function (o, api) {
- /**
- * @private
- * @type {module:zrender/container/Group}
- */
- this._containerGroup;
- /**
- * @private
- * @type {Object.<string, Array.<module:zrender/container/Group>>}
- */
- this._storage = createStorage();
- /**
- * @private
- * @type {module:echarts/data/Tree}
- */
- this._oldTree;
- /**
- * @private
- * @type {module:echarts/chart/treemap/Breadcrumb}
- */
- this._breadcrumb;
- /**
- * @private
- * @type {module:echarts/component/helper/RoamController}
- */
- this._controller;
- /**
- * 'ready', 'animating'
- * @private
- */
- this._state = 'ready';
- },
- /**
- * @override
- */
- render: function (seriesModel, ecModel, api, payload) {
- var models = ecModel.findComponents({
- mainType: 'series',
- subType: 'treemap',
- query: payload
- });
- if (zrUtil.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 renderResult = this._doRender(containerGroup, seriesModel, reRoot);
- !isInit && (!payloadType || payloadType === 'treemapZoomToNode' || payloadType === 'treemapRootToNode') ? this._doAnimation(containerGroup, renderResult, seriesModel, reRoot) : renderResult.renderFinally();
- this._resetController(api);
- this._renderBreadcrumb(seriesModel, api, targetInfo);
- },
- /**
- * @private
- */
- _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.attr('position', [layoutInfo.x, layoutInfo.y]);
- return containerGroup;
- },
- /**
- * @private
- */
- _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 = [];
- var doRenderNode = zrUtil.curry(renderNode, seriesModel, thisStorage, oldStorage, reRoot, lastsForAnimation, willInvisibleEls); // Notice: when thisTree and oldTree are the same tree (see list.cloneShallow),
- // the oldTree is actually losted, so we can not find all of the old graphic
- // elements from tree. So we use this stragegy: 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;
- 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(zrUtil.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), el.__tmWillDelete = 1);
- });
- });
- 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();
- });
- }
- },
- /**
- * @private
- */
- _doAnimation: function (containerGroup, renderResult, seriesModel, reRoot) {
- if (!seriesModel.get('animation')) {
- return;
- }
- var duration = seriesModel.get('animationDurationUpdate');
- var easing = seriesModel.get('animationEasing');
- 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;
- 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: parent.__tmNodeWidth,
- height: parent.__tmNodeHeight
- },
- style: {
- opacity: 0
- } // Others.
- } : {
- style: {
- opacity: 0
- }
- };
- } else {
- var targetX = 0;
- var targetY = 0;
- if (!parent.__tmWillDelete) {
- // 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 = parent.__tmNodeWidth / 2;
- targetY = parent.__tmNodeHeight / 2;
- }
- target = storageName === 'nodeGroup' ? {
- position: [targetX, targetY],
- style: {
- opacity: 0
- }
- } : {
- shape: {
- x: targetX,
- y: targetY,
- width: 0,
- height: 0
- },
- style: {
- opacity: 0
- }
- };
- }
- target && animationWrap.add(el, target, duration, 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 (storageName === 'nodeGroup') {
- if (last.old) {
- target.position = el.position.slice();
- el.attr('position', last.old);
- }
- } else {
- if (last.old) {
- target.shape = zrUtil.extend({}, el.shape);
- el.setShape(last.old);
- }
- 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, easing);
- });
- }, this);
- this._state = 'animating';
- animationWrap.done(bind(function () {
- this._state = 'ready';
- renderResult.renderFinally();
- }, this)).start();
- },
- /**
- * @private
- */
- _resetController: function (api) {
- var controller = this._controller; // Init controller.
- if (!controller) {
- controller = this._controller = new RoamController(api.getZr());
- controller.enable(this.seriesModel.get('roam'));
- 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);
- });
- },
- /**
- * @private
- */
- _clearController: function () {
- var controller = this._controller;
- if (controller) {
- controller.dispose();
- controller = null;
- }
- },
- /**
- * @private
- */
- _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
- }
- });
- }
- },
- /**
- * @private
- */
- _onZoom: function (e) {
- var mouseX = e.originX;
- var mouseY = e.originY;
- 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);
- 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, [e.scale, e.scale]);
- 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
- }
- });
- }
- },
- /**
- * @private
- */
- _initEvents: function (containerGroup) {
- 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);
- },
- /**
- * @private
- */
- _renderBreadcrumb: function (seriesModel, api, targetInfo) {
- 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, bind(onSelect, this));
- function onSelect(node) {
- if (this._state !== 'animating') {
- helper.aboveViewRoot(seriesModel.getViewRoot(), node) ? this._rootToNode({
- node: node
- }) : this._zoomToNode({
- node: node
- });
- }
- }
- },
- /**
- * @override
- */
- remove: function () {
- this._clearController();
- this._containerGroup && this._containerGroup.removeAll();
- this._storage = createStorage();
- this._state = 'ready';
- this._breadcrumb && this._breadcrumb.remove();
- },
- dispose: function () {
- this._clearController();
- },
- /**
- * @private
- */
- _zoomToNode: function (targetInfo) {
- this.api.dispatchAction({
- type: 'treemapZoomToNode',
- from: this.uid,
- seriesId: this.seriesModel.id,
- targetNode: targetInfo.node
- });
- },
- /**
- * @private
- */
- _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.
- */
- 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, dont 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;
- }
- });
- /**
- * @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(); // 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 = thisNode.getModel('itemStyle');
- var itemStyleEmphasisModel = thisNode.getModel('emphasis.itemStyle'); // 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.attr('position', [thisLayout.x || 0, thisLayout.y || 0]);
- group.__tmNodeWidth = thisWidth;
- group.__tmNodeHeight = thisHeight;
- if (thisLayout.isAboveViewRoot) {
- return group;
- }
- var nodeModel = thisNode.getModel(); // Background
- var bg = giveGraphic('background', Rect, depth, Z_BG);
- bg && renderBackground(group, bg, isParent && thisLayout.upperLabelHeight); // 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 (graphic.isHighDownDispatcher(group)) {
- graphic.setAsHighDownDispatcher(group, false);
- }
- if (bg) {
- graphic.setAsHighDownDispatcher(bg, true); // Only for enabling highlight/downplay.
- data.setItemGraphicEl(thisNode.dataIndex, bg);
- }
- } else {
- var content = giveGraphic('content', Rect, depth, Z_CONTENT);
- content && renderContent(group, content);
- if (bg && graphic.isHighDownDispatcher(bg)) {
- graphic.setAsHighDownDispatcher(bg, false);
- }
- graphic.setAsHighDownDispatcher(group, true); // Only for enabling highlight/downplay.
- data.setItemGraphicEl(thisNode.dataIndex, group);
- }
- return group; // ----------------------------
- // | Procedures in renderNode |
- // ----------------------------
- function renderBackground(group, bg, useUpperLabel) {
- // For tooltip.
- bg.dataIndex = thisNode.dataIndex;
- bg.seriesIndex = seriesModel.seriesIndex;
- bg.setShape({
- x: 0,
- y: 0,
- width: thisWidth,
- height: thisHeight
- });
- 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 visualBorderColor = thisNode.getVisual('borderColor', true);
- var emphasisBorderColor = itemStyleEmphasisModel.get('borderColor');
- var normalStyle = getItemStyleNormal(itemStyleNormalModel);
- normalStyle.fill = visualBorderColor;
- var emphasisStyle = getItemStyleEmphasis(itemStyleEmphasisModel);
- emphasisStyle.fill = emphasisBorderColor;
- if (useUpperLabel) {
- var upperLabelWidth = thisWidth - 2 * borderWidth;
- prepareText(normalStyle, emphasisStyle, visualBorderColor, upperLabelWidth, upperHeight, {
- x: borderWidth,
- y: 0,
- width: upperLabelWidth,
- height: upperHeight
- });
- } // For old bg.
- else {
- normalStyle.text = emphasisStyle.text = null;
- }
- bg.setStyle(normalStyle);
- graphic.setElementHoverStyle(bg, emphasisStyle);
- }
- group.add(bg);
- }
- function renderContent(group, content) {
- // For tooltip.
- content.dataIndex = thisNode.dataIndex;
- content.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
- });
- 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 visualColor = thisNode.getVisual('color', true);
- var normalStyle = getItemStyleNormal(itemStyleNormalModel);
- normalStyle.fill = visualColor;
- var emphasisStyle = getItemStyleEmphasis(itemStyleEmphasisModel);
- prepareText(normalStyle, emphasisStyle, visualColor, contentWidth, contentHeight);
- content.setStyle(normalStyle);
- graphic.setElementHoverStyle(content, emphasisStyle);
- }
- 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(normalStyle, emphasisStyle, visualColor, width, height, upperLabelRect) {
- var defaultText = nodeModel.get('name');
- var normalLabelModel = nodeModel.getModel(upperLabelRect ? PATH_UPPERLABEL_NORMAL : PATH_LABEL_NOAMAL);
- var emphasisLabelModel = nodeModel.getModel(upperLabelRect ? PATH_UPPERLABEL_EMPHASIS : PATH_LABEL_EMPHASIS);
- var isShow = normalLabelModel.getShallow('show');
- graphic.setLabelStyle(normalStyle, emphasisStyle, normalLabelModel, emphasisLabelModel, {
- defaultText: isShow ? defaultText : null,
- autoColor: visualColor,
- isRectText: true,
- labelFetcher: seriesModel,
- labelDataIndex: thisNode.dataIndex,
- labelProp: upperLabelRect ? 'upperLabel' : 'label'
- });
- addDrillDownIcon(normalStyle, upperLabelRect, thisLayout);
- addDrillDownIcon(emphasisStyle, upperLabelRect, thisLayout);
- upperLabelRect && (normalStyle.textRect = zrUtil.clone(upperLabelRect));
- normalStyle.truncate = isShow && normalLabelModel.get('ellipsis') ? {
- outerWidth: width,
- outerHeight: height,
- minChar: 2
- } : null;
- }
- function addDrillDownIcon(style, upperLabelRect, thisLayout) {
- var text = style.text;
- 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, storageName);
- } // If invisible and no old element, do not create new element (for optimizing).
- else if (!thisInvisible) {
- element = new Ctor({
- z: calculateZ(depth, z)
- });
- element.__tmDepth = depth;
- element.__tmStorageName = storageName;
- prepareAnimationWhenNoOld(lasts, element, storageName);
- } // Set to thisStorage
- return thisStorage[storageName][thisRawIndex] = element;
- }
- function prepareAnimationWhenHasOld(lasts, element, storageName) {
- var lastCfg = lasts[thisRawIndex] = {};
- lastCfg.old = storageName === 'nodeGroup' ? element.position.slice() : zrUtil.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, storageName) {
- var lastCfg = lasts[thisRawIndex] = {};
- var parentNode = thisNode.parentNode;
- 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.old) {
- parentOldX = parentOldBg.old.width;
- parentOldY = parentOldBg.old.height;
- } // When no parent old shape found, its parent is new too,
- // so we can just use {x:0, y:0}.
- lastCfg.old = storageName === 'nodeGroup' ? [0, parentOldY] : {
- x: parentOldX,
- y: parentOldY,
- width: 0,
- height: 0
- };
- } // Fade in, user can be aware that these nodes are new.
- lastCfg.fadein = storageName !== 'nodeGroup';
- }
- } // We can not set all backgroud with the same z, Because the behaviour of
- // drill down and roll up differ background creation sequence from tree
- // hierarchy sequence, which cause that lowser background element 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 calculateZ(depth, zInLevel) {
- var zb = depth * Z_BASE + zInLevel;
- return (zb - 1) / zb;
- }
- module.exports = _default;
|