/*
* 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 {bind, each, indexOf, curry, extend, normalizeCssArray, isFunction} from 'zrender/src/core/util';
import * as graphic from '../../util/graphic';
import {getECData} from '../../util/innerStore';
import {
    isHighDownDispatcher,
    setAsHighDownDispatcher,
    setDefaultStateProxy,
    enableHoverFocus,
    Z2_EMPHASIS_LIFT
} from '../../util/states';
import DataDiffer from '../../data/DataDiffer';
import * as helper from '../helper/treeHelper';
import Breadcrumb from './Breadcrumb';
import RoamController, { RoamEventParams } from '../../component/helper/RoamController';
import BoundingRect, { RectLike } from 'zrender/src/core/BoundingRect';
import * as matrix from 'zrender/src/core/matrix';
import * as animationUtil from '../../util/animation';
import makeStyleMapper from '../../model/mixin/makeStyleMapper';
import ChartView from '../../view/Chart';
import Tree, { TreeNode } from '../../data/Tree';
import TreemapSeriesModel, { TreemapSeriesNodeItemOption } from './TreemapSeries';
import GlobalModel from '../../model/Global';
import ExtensionAPI from '../../core/ExtensionAPI';
import Model from '../../model/Model';
import { LayoutRect } from '../../util/layout';
import { TreemapLayoutNode } from './treemapLayout';
import Element from 'zrender/src/Element';
import Displayable from 'zrender/src/graphic/Displayable';
import { makeInner, convertOptionIdName } from '../../util/model';
import { PathStyleProps, PathProps } from 'zrender/src/graphic/Path';
import { TreeSeriesNodeItemOption } from '../tree/TreeSeries';
import {
    TreemapRootToNodePayload,
    TreemapMovePayload,
    TreemapRenderPayload,
    TreemapZoomToNodePayload
} from './treemapAction';
import { ColorString, ECElement } from '../../util/types';
import { windowOpen } from '../../util/format';
import { TextStyleProps } from 'zrender/src/graphic/Text';
import { setLabelStyle, getLabelStatesModels } from '../../label/labelStyle';

const Group = graphic.Group;
const Rect = graphic.Rect;

const DRAG_THRESHOLD = 3;
const PATH_LABEL_NOAMAL = 'label';
const PATH_UPPERLABEL_NORMAL = 'upperLabel';
// Should larger than emphasis states lift z
const Z2_BASE = Z2_EMPHASIS_LIFT * 10; // Should bigger than every z2.
const Z2_BG = Z2_EMPHASIS_LIFT * 2;
const Z2_CONTENT = Z2_EMPHASIS_LIFT * 3;

const 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.
]);
const getItemStyleNormal = function (model: Model<TreemapSeriesNodeItemOption['itemStyle']>): PathStyleProps {
    // Normal style props should include emphasis style props.
    const itemStyle = getStateItemStyle(model) as PathStyleProps;
    // Clear styles set by emphasis.
    itemStyle.stroke = itemStyle.fill = itemStyle.lineWidth = null;
    return itemStyle;
};

interface RenderElementStorage {
    nodeGroup: graphic.Group[]
    background: graphic.Rect[]
    content: graphic.Rect[]
}

type LastCfgStorage = {
    [key in keyof RenderElementStorage]: LastCfg[]
    // nodeGroup: {
    //     old: Pick<graphic.Group, 'position'>[]
    //     fadein: boolean
    // }[]
    // background: {
    //     old: Pick<graphic.Rect, 'shape'>
    //     fadein: boolean
    // }[]
    // content: {
    //     old: Pick<graphic.Rect, 'shape'>
    //     fadein: boolean
    // }[]
};

interface FoundTargetInfo {
    node: TreeNode

    offsetX?: number
    offsetY?: number
}

interface RenderResult {
    lastsForAnimation: LastCfgStorage
    willInvisibleEls?: graphic.Rect[]
    willDeleteEls: RenderElementStorage
    renderFinally: () => void
}

interface ReRoot {
    rootNodeGroup: graphic.Group
    direction: 'drillDown' | 'rollUp'
}

interface LastCfg {
    oldX?: number
    oldY?: number
    oldShape?: graphic.Rect['shape']
    fadein: boolean
}

const inner = makeInner<{
    nodeWidth: number
    nodeHeight: number
    willDelete: boolean
}, Element>();

class TreemapView extends ChartView {

    static type = 'treemap';
    type = TreemapView.type;

    private _containerGroup: graphic.Group;
    private _breadcrumb: Breadcrumb;
    private _controller: RoamController;

    private _oldTree: Tree;

    private _state: 'ready' | 'animating' = 'ready';

    private _storage = createStorage() as RenderElementStorage;

    seriesModel: TreemapSeriesModel;
    api: ExtensionAPI;
    ecModel: GlobalModel;

    /**
     * @override
     */
    render(
        seriesModel: TreemapSeriesModel,
        ecModel: GlobalModel,
        api: ExtensionAPI,
        payload: TreemapZoomToNodePayload | TreemapRenderPayload | TreemapMovePayload | TreemapRootToNodePayload
    ) {

        const models = ecModel.findComponents({
            mainType: 'series', subType: 'treemap', query: payload
        });
        if (indexOf(models, seriesModel) < 0) {
            return;
        }

        this.seriesModel = seriesModel;
        this.api = api;
        this.ecModel = ecModel;

        const types = ['treemapZoomToNode', 'treemapRootToNode'];
        const targetInfo = helper
            .retrieveTargetInfo(payload, types, seriesModel);
        const payloadType = payload && payload.type;
        const layoutInfo = seriesModel.layoutInfo;
        const isInit = !this._oldTree;
        const thisStorage = this._storage;

        // Mark new root when action is treemapRootToNode.
        const reRoot = (payloadType === 'treemapRootToNode' && targetInfo && thisStorage)
            ? {
                rootNodeGroup: thisStorage.nodeGroup[targetInfo.node.getRawIndex()],
                direction: (payload as TreemapRootToNodePayload).direction
            }
            : null;

        const containerGroup = this._giveContainerGroup(layoutInfo);
        const hasAnimation = seriesModel.get('animation');

        const 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);
    }

    private _giveContainerGroup(layoutInfo: LayoutRect) {
        let 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;
    }

    private _doRender(containerGroup: graphic.Group, seriesModel: TreemapSeriesModel, reRoot: ReRoot): RenderResult {
        const thisTree = seriesModel.getData().tree;
        const oldTree = this._oldTree;

        // Clear last shape records.
        const lastsForAnimation = createStorage() as LastCfgStorage;
        const thisStorage = createStorage() as RenderElementStorage;
        const oldStorage = this._storage;
        const willInvisibleEls: RenderResult['willInvisibleEls'] = [];

        function doRenderNode(thisNode: TreeNode, oldNode: TreeNode, parentGroup: graphic.Group, depth: number) {
            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 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.
        const willDeleteEls = clearStorage(oldStorage) as RenderElementStorage;

        this._oldTree = thisTree;
        this._storage = thisStorage;

        return {
            lastsForAnimation,
            willDeleteEls,
            renderFinally
        };

        function dualTravel(
            thisViewChildren: TreemapLayoutNode[],
            oldViewChildren: TreemapLayoutNode[],
            parentGroup: graphic.Group,
            sameTree: boolean,
            depth: number
        ) {
            // 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: TreeNode) {
                // Identify by name or raw index.
                return node.getId();
            }

            function processNode(newIndex: number, oldIndex?: number) {
                const thisNode = newIndex != null ? thisViewChildren[newIndex] : null;
                const oldNode = oldIndex != null ? oldViewChildren[oldIndex] : null;

                const group = doRenderNode(thisNode, oldNode, parentGroup, depth);

                group && dualTravel(
                    thisNode && thisNode.viewChildren || [],
                    oldNode && oldNode.viewChildren || [],
                    group,
                    sameTree,
                    depth + 1
                );
            }
        }

        function clearStorage(storage: RenderElementStorage) {
            const willDeleteEls = createStorage() as RenderElementStorage;
            storage && each(storage, function (store, storageName) {
                const delEls = willDeleteEls[storageName];
                each(store, function (el) {
                    el && (delEls.push(el as any), 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();
            });
        }
    }

    private _doAnimation(
        containerGroup: graphic.Group,
        renderResult: RenderResult,
        seriesModel: TreemapSeriesModel,
        reRoot: ReRoot
    ) {
        const durationOption = seriesModel.get('animationDurationUpdate');
        const easingOption = seriesModel.get('animationEasing');
        // TODO: do not support function until necessary.
        const duration = (isFunction(durationOption) ? 0 : durationOption) || 0;
        const easing = (isFunction(easingOption) ? null : easingOption) || 'cubicOut';
        const animationWrap = animationUtil.createWrap();

        // Make delete animations.
        each(renderResult.willDeleteEls, function (store, storageName) {
            each(store, function (el, rawIndex) {
                if ((el as Displayable).invisible) {
                    return;
                }

                const parent = el.parent; // Always has parent, and parent is nodeGroup.
                let target: PathProps;
                const 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 {
                    let targetX = 0;
                    let 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) {
                const last = renderResult.lastsForAnimation[storageName][rawIndex];
                const target: PathProps = {};

                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();
    }

    private _resetController(api: ExtensionAPI) {
        let 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));
        }

        const rect = new BoundingRect(0, 0, api.getWidth(), api.getHeight());
        controller.setPointerChecker(function (e, x, y) {
            return rect.contain(x, y);
        });
    }

    private _clearController() {
        let controller = this._controller;
        if (controller) {
            controller.dispose();
            controller = null;
        }
    }

    private _onPan(e: RoamEventParams['pan']) {
        if (this._state !== 'animating'
            && (Math.abs(e.dx) > DRAG_THRESHOLD || Math.abs(e.dy) > DRAG_THRESHOLD)
        ) {
            // These param must not be cached.
            const root = this.seriesModel.getData().tree.root;

            if (!root) {
                return;
            }

            const 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
                }
            } as TreemapMovePayload);
        }
    }

    private _onZoom(e: RoamEventParams['zoom']) {
        let mouseX = e.originX;
        let mouseY = e.originY;

        if (this._state !== 'animating') {
            // These param must not be cached.
            const root = this.seriesModel.getData().tree.root;

            if (!root) {
                return;
            }

            const rootLayout = root.getLayout();

            if (!rootLayout) {
                return;
            }

            const rect = new BoundingRect(
                rootLayout.x, rootLayout.y, rootLayout.width, rootLayout.height
            );
            const layoutInfo = this.seriesModel.layoutInfo;

            // Transform mouse coord from global to containerGroup.
            mouseX -= layoutInfo.x;
            mouseY -= layoutInfo.y;

            // Scale root bounding rect.
            const 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
                }
            } as TreemapRenderPayload);
        }
    }

    private _initEvents(containerGroup: graphic.Group) {
        containerGroup.on('click', (e) => {
            if (this._state !== 'ready') {
                return;
            }

            const nodeClick = this.seriesModel.get('nodeClick', true);

            if (!nodeClick) {
                return;
            }

            const targetInfo = this.findTarget(e.offsetX, e.offsetY);

            if (!targetInfo) {
                return;
            }

            const node = targetInfo.node;
            if (node.getLayout().isLeafRoot) {
                this._rootToNode(targetInfo);
            }
            else {
                if (nodeClick === 'zoomToNode') {
                    this._zoomToNode(targetInfo);
                }
                else if (nodeClick === 'link') {
                    const itemModel = node.hostTree.data.getItemModel<TreeSeriesNodeItemOption>(node.dataIndex);
                    const link = itemModel.get('link', true);
                    const linkTarget = itemModel.get('target', true) || 'blank';
                    link && windowOpen(link, linkTarget);
                }
            }

        }, this);
    }

    private _renderBreadcrumb(seriesModel: TreemapSeriesModel, api: ExtensionAPI, targetInfo: FoundTargetInfo) {
        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, (node) => {
                if (this._state !== 'animating') {
                    helper.aboveViewRoot(seriesModel.getViewRoot(), node)
                        ? this._rootToNode({node: node})
                        : this._zoomToNode({node: node});
                }
            });
    }

    /**
     * @override
     */
    remove() {
        this._clearController();
        this._containerGroup && this._containerGroup.removeAll();
        this._storage = createStorage() as RenderElementStorage;
        this._state = 'ready';
        this._breadcrumb && this._breadcrumb.remove();
    }

    dispose() {
        this._clearController();
    }

    private _zoomToNode(targetInfo: FoundTargetInfo) {
        this.api.dispatchAction({
            type: 'treemapZoomToNode',
            from: this.uid,
            seriesId: this.seriesModel.id,
            targetNode: targetInfo.node
        });
    }

    private _rootToNode(targetInfo: FoundTargetInfo) {
        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(x: number, y: number): FoundTargetInfo {
        let targetInfo;
        const viewRoot = this.seriesModel.getViewRoot();

        viewRoot.eachNode({attr: 'viewChildren', order: 'preorder'}, function (node) {
            const bgEl = this._storage.background[node.getRawIndex()];
            // If invisible, there might be no element.
            if (bgEl) {
                const point = bgEl.transformCoordToLocal(x, y);
                const 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(): RenderElementStorage | LastCfgStorage {
    return {
        nodeGroup: [],
        background: [],
        content: []
    };
}

/**
 * @inner
 * @return Return undefined means do not travel further.
 */
function renderNode(
    seriesModel: TreemapSeriesModel,
    thisStorage: RenderElementStorage,
    oldStorage: RenderElementStorage,
    reRoot: ReRoot,
    lastsForAnimation: RenderResult['lastsForAnimation'],
    willInvisibleEls: RenderResult['willInvisibleEls'],
    thisNode: TreeNode,
    oldNode: TreeNode,
    parentGroup: graphic.Group,
    depth: number
) {
    // 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".

    const thisLayout = thisNode.getLayout();
    const data = seriesModel.getData();
    const nodeModel = thisNode.getModel<TreemapSeriesNodeItemOption>();

    // Only for enabling highlight/downplay. Clear firstly.
    // Because some node will not be rendered.
    data.setItemGraphicEl(thisNode.dataIndex, null);

    if (!thisLayout || !thisLayout.isInView) {
        return;
    }

    const thisWidth = thisLayout.width;
    const thisHeight = thisLayout.height;
    const borderWidth = thisLayout.borderWidth;
    const thisInvisible = thisLayout.invisible;

    const thisRawIndex = thisNode.getRawIndex();
    const oldRawIndex = oldNode && oldNode.getRawIndex();

    const thisViewChildren = thisNode.viewChildren;
    const upperHeight = thisLayout.upperHeight;
    const isParent = thisViewChildren && thisViewChildren.length;
    const itemStyleNormalModel = nodeModel.getModel('itemStyle');
    const itemStyleEmphasisModel = nodeModel.getModel(['emphasis', 'itemStyle']);
    const itemStyleBlurModel = nodeModel.getModel(['blur', 'itemStyle']);
    const itemStyleSelectModel = nodeModel.getModel(['select', 'itemStyle']);
    const borderRadius = itemStyleNormalModel.get('borderRadius') || 0;

    // End of closure ariables available in "Procedures in renderNode".
    // -----------------------------------------------------------------

    // Node group
    const 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
    const bg = giveGraphic('background', Rect, depth, Z2_BG);
    bg && renderBackground(group, bg, isParent && thisLayout.upperLabelHeight);

    const focus = nodeModel.get(['emphasis', 'focus']);
    const blurScope = nodeModel.get(['emphasis', 'blurScope']);

    const 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, true);
            // Only for enabling highlight/downplay.
            data.setItemGraphicEl(thisNode.dataIndex, bg);

            enableHoverFocus(bg, focusOrIndices, blurScope);
        }
    }
    else {
        const content = giveGraphic('content', Rect, depth, Z2_CONTENT);
        content && renderContent(group, content);

        (bg as ECElement).disableMorphing = true;

        if (bg && isHighDownDispatcher(bg)) {
            setAsHighDownDispatcher(bg, false);
        }
        setAsHighDownDispatcher(group, true);
        // Only for enabling highlight/downplay.
        data.setItemGraphicEl(thisNode.dataIndex, group);

        enableHoverFocus(group, focusOrIndices, blurScope);
    }

    return group;

    // ----------------------------
    // | Procedures in renderNode |
    // ----------------------------

    function renderBackground(group: graphic.Group, bg: graphic.Rect, useUpperLabel: boolean) {
        const 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;
            const style = thisNode.getVisual('style') as PathStyleProps;
            const visualBorderColor = style.stroke;
            const normalStyle = getItemStyleNormal(itemStyleNormalModel);
            normalStyle.fill = visualBorderColor;
            const emphasisStyle = getStateItemStyle(itemStyleEmphasisModel);
            emphasisStyle.fill = itemStyleEmphasisModel.get('borderColor');
            const blurStyle = getStateItemStyle(itemStyleBlurModel);
            blurStyle.fill = itemStyleBlurModel.get('borderColor');
            const selectStyle = getStateItemStyle(itemStyleSelectModel);
            selectStyle.fill = itemStyleSelectModel.get('borderColor');

            if (useUpperLabel) {
                const upperLabelWidth = thisWidth - 2 * borderWidth;

                prepareText(
                    // PENDING: convert ZRColor to ColorString for text.
                    bg, visualBorderColor as ColorString, 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: graphic.Group, content: graphic.Rect) {
        const ecData = getECData(content);
        // For tooltip.
        ecData.dataIndex = thisNode.dataIndex;
        ecData.seriesIndex = seriesModel.seriesIndex;

        const contentWidth = Math.max(thisWidth - 2 * borderWidth, 0);
        const 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;
            const nodeStyle = thisNode.getVisual('style') as PathStyleProps;
            const visualColor = nodeStyle.fill;
            const normalStyle = getItemStyleNormal(itemStyleNormalModel);
            normalStyle.fill = visualColor;
            normalStyle.decal = nodeStyle.decal;
            const emphasisStyle = getStateItemStyle(itemStyleEmphasisModel);
            const blurStyle = getStateItemStyle(itemStyleBlurModel);
            const selectStyle = getStateItemStyle(itemStyleSelectModel);

            // PENDING: convert ZRColor to ColorString for text.
            prepareText(content, visualColor as ColorString, 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: graphic.Rect) {
        // Delay invisible setting utill animation finished,
        // avoid element vanish suddenly before animation.
        !element.invisible && willInvisibleEls.push(element);
    }

    function prepareText(
        rectEl: graphic.Rect,
        visualColor: ColorString,
        visualOpacity: number,
        // Can be null/undefined
        upperLabelRect: RectLike
    ) {
        const normalLabelModel = nodeModel.getModel(
            upperLabelRect ? PATH_UPPERLABEL_NORMAL : PATH_LABEL_NOAMAL
        );

        const defaultText = convertOptionIdName(nodeModel.get('name'), null);

        const 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
            }
        );

        const textEl = rectEl.getTextContent();
        if (!textEl) {
            return;
        }
        const textStyle = textEl.style;
        const textPadding = normalizeCssArray(textStyle.padding || 0);

        if (upperLabelRect) {
            rectEl.setTextConfig({
                layoutRect: upperLabelRect
            });
            (textEl as ECElement).disableLabelLayout = true;
        }
        textEl.beforeUpdate = function () {
            const width = Math.max(
                (upperLabelRect ? upperLabelRect.width : rectEl.shape.width) - textPadding[1] - textPadding[3], 0
            );
            const height = Math.max(
                (upperLabelRect ? upperLabelRect.height : rectEl.shape.height) - textPadding[0] - textPadding[2], 0
            );
            if (textStyle.width !== width || textStyle.height !== height) {
                textEl.setStyle({
                    width,
                    height
                });
            }
        };

        textStyle.truncateMinChar = 2;
        textStyle.lineOverflow = 'truncate';

        addDrillDownIcon(textStyle, upperLabelRect, thisLayout);
        const textEmphasisState = textEl.getState('emphasis');
        addDrillDownIcon(textEmphasisState ? textEmphasisState.style : null, upperLabelRect, thisLayout);
    }

    function addDrillDownIcon(style: TextStyleProps, upperLabelRect: RectLike, thisLayout: any) {
        const text = style ? style.text : null;
        if (!upperLabelRect && thisLayout.isLeafRoot && text != null) {
            const iconChar = seriesModel.get('drillDownIcon', true);
            style.text = iconChar ? iconChar + ' ' + text : text;
        }
    }

    function giveGraphic<T extends graphic.Group | graphic.Rect>(
        storageName: keyof RenderElementStorage,
        Ctor: {new(): T},
        depth?: number,
        z?: number
    ): T {
        let element = oldRawIndex != null && oldStorage[storageName][oldRawIndex];
        const 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) as T;
    }

    function prepareAnimationWhenHasOld(lasts: LastCfg[], element: graphic.Group | graphic.Rect) {
        const lastCfg = lasts[thisRawIndex] = {} as LastCfg;
        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: LastCfg[], element: graphic.Group | graphic.Rect) {
        const lastCfg = lasts[thisRawIndex] = {} as LastCfg;
        const parentNode = thisNode.parentNode;
        const isGroup = element instanceof graphic.Group;

        if (parentNode && (!reRoot || reRoot.direction === 'drillDown')) {
            let parentOldX = 0;
            let parentOldY = 0;

            // New nodes appear from right-bottom corner in 'zoomToNode' animation.
            // For convenience, get old bounding rect from background.
            const 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 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 calculateZ2(depth: number, z2InLevel: number) {
    return depth * Z2_BASE + z2InLevel;
}

export default TreemapView;
