| 
/* 
 | 
* 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); 
 | 
    var cursorStyle = nodeModel.getShallow('cursor'); 
 | 
    cursorStyle && content.attr('cursor', cursorStyle); 
 | 
    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; 
 |