| 
/* 
 | 
* 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. 
 | 
*/ 
 | 
/* 
 | 
* A third-party license is embedded for some of the code in this file: 
 | 
* The treemap layout implementation was originally copied from 
 | 
* "d3.js" with some modifications made for this project. 
 | 
* (See more details in the comment of the method "squarify" below.) 
 | 
* The use of the source code of this file is also subject to the terms 
 | 
* and consitions of the license of "d3.js" (BSD-3Clause, see 
 | 
* </licenses/LICENSE-d3>). 
 | 
*/ 
 | 
import * as zrUtil from 'zrender/lib/core/util.js'; 
 | 
import BoundingRect from 'zrender/lib/core/BoundingRect.js'; 
 | 
import { parsePercent, MAX_SAFE_INTEGER } from '../../util/number.js'; 
 | 
import * as layout from '../../util/layout.js'; 
 | 
import * as helper from '../helper/treeHelper.js'; 
 | 
var mathMax = Math.max; 
 | 
var mathMin = Math.min; 
 | 
var retrieveValue = zrUtil.retrieve; 
 | 
var each = zrUtil.each; 
 | 
var PATH_BORDER_WIDTH = ['itemStyle', 'borderWidth']; 
 | 
var PATH_GAP_WIDTH = ['itemStyle', 'gapWidth']; 
 | 
var PATH_UPPER_LABEL_SHOW = ['upperLabel', 'show']; 
 | 
var PATH_UPPER_LABEL_HEIGHT = ['upperLabel', 'height']; 
 | 
; 
 | 
/** 
 | 
 * @public 
 | 
 */ 
 | 
export default { 
 | 
  seriesType: 'treemap', 
 | 
  reset: function (seriesModel, ecModel, api, payload) { 
 | 
    // Layout result in each node: 
 | 
    // {x, y, width, height, area, borderWidth} 
 | 
    var ecWidth = api.getWidth(); 
 | 
    var ecHeight = api.getHeight(); 
 | 
    var seriesOption = seriesModel.option; 
 | 
    var layoutInfo = layout.getLayoutRect(seriesModel.getBoxLayoutParams(), { 
 | 
      width: api.getWidth(), 
 | 
      height: api.getHeight() 
 | 
    }); 
 | 
    var size = seriesOption.size || []; // Compatible with ec2. 
 | 
    var containerWidth = parsePercent(retrieveValue(layoutInfo.width, size[0]), ecWidth); 
 | 
    var containerHeight = parsePercent(retrieveValue(layoutInfo.height, size[1]), ecHeight); 
 | 
    // Fetch payload info. 
 | 
    var payloadType = payload && payload.type; 
 | 
    var types = ['treemapZoomToNode', 'treemapRootToNode']; 
 | 
    var targetInfo = helper.retrieveTargetInfo(payload, types, seriesModel); 
 | 
    var rootRect = payloadType === 'treemapRender' || payloadType === 'treemapMove' ? payload.rootRect : null; 
 | 
    var viewRoot = seriesModel.getViewRoot(); 
 | 
    var viewAbovePath = helper.getPathToRoot(viewRoot); 
 | 
    if (payloadType !== 'treemapMove') { 
 | 
      var rootSize = payloadType === 'treemapZoomToNode' ? estimateRootSize(seriesModel, targetInfo, viewRoot, containerWidth, containerHeight) : rootRect ? [rootRect.width, rootRect.height] : [containerWidth, containerHeight]; 
 | 
      var sort_1 = seriesOption.sort; 
 | 
      if (sort_1 && sort_1 !== 'asc' && sort_1 !== 'desc') { 
 | 
        // Default to be desc order. 
 | 
        sort_1 = 'desc'; 
 | 
      } 
 | 
      var options = { 
 | 
        squareRatio: seriesOption.squareRatio, 
 | 
        sort: sort_1, 
 | 
        leafDepth: seriesOption.leafDepth 
 | 
      }; 
 | 
      // layout should be cleared because using updateView but not update. 
 | 
      viewRoot.hostTree.clearLayouts(); 
 | 
      // TODO 
 | 
      // optimize: if out of view clip, do not layout. 
 | 
      // But take care that if do not render node out of view clip, 
 | 
      // how to calculate start po 
 | 
      var viewRootLayout_1 = { 
 | 
        x: 0, 
 | 
        y: 0, 
 | 
        width: rootSize[0], 
 | 
        height: rootSize[1], 
 | 
        area: rootSize[0] * rootSize[1] 
 | 
      }; 
 | 
      viewRoot.setLayout(viewRootLayout_1); 
 | 
      squarify(viewRoot, options, false, 0); 
 | 
      // Supplement layout. 
 | 
      viewRootLayout_1 = viewRoot.getLayout(); 
 | 
      each(viewAbovePath, function (node, index) { 
 | 
        var childValue = (viewAbovePath[index + 1] || viewRoot).getValue(); 
 | 
        node.setLayout(zrUtil.extend({ 
 | 
          dataExtent: [childValue, childValue], 
 | 
          borderWidth: 0, 
 | 
          upperHeight: 0 
 | 
        }, viewRootLayout_1)); 
 | 
      }); 
 | 
    } 
 | 
    var treeRoot = seriesModel.getData().tree.root; 
 | 
    treeRoot.setLayout(calculateRootPosition(layoutInfo, rootRect, targetInfo), true); 
 | 
    seriesModel.setLayoutInfo(layoutInfo); 
 | 
    // FIXME 
 | 
    // 现在没有clip功能,暂时取ec高宽。 
 | 
    prunning(treeRoot, 
 | 
    // Transform to base element coordinate system. 
 | 
    new BoundingRect(-layoutInfo.x, -layoutInfo.y, ecWidth, ecHeight), viewAbovePath, viewRoot, 0); 
 | 
  } 
 | 
}; 
 | 
/** 
 | 
 * Layout treemap with squarify algorithm. 
 | 
 * The original presentation of this algorithm 
 | 
 * was made by Mark Bruls, Kees Huizing, and Jarke J. van Wijk 
 | 
 * <https://graphics.ethz.ch/teaching/scivis_common/Literature/squarifiedTreeMaps.pdf>. 
 | 
 * The implementation of this algorithm was originally copied from "d3.js" 
 | 
 * <https://github.com/d3/d3/blob/9cc9a875e636a1dcf36cc1e07bdf77e1ad6e2c74/src/layout/treemap.js> 
 | 
 * with some modifications made for this program. 
 | 
 * See the license statement at the head of this file. 
 | 
 * 
 | 
 * @protected 
 | 
 * @param {module:echarts/data/Tree~TreeNode} node 
 | 
 * @param {Object} options 
 | 
 * @param {string} options.sort 'asc' or 'desc' 
 | 
 * @param {number} options.squareRatio 
 | 
 * @param {boolean} hideChildren 
 | 
 * @param {number} depth 
 | 
 */ 
 | 
function squarify(node, options, hideChildren, depth) { 
 | 
  var width; 
 | 
  var height; 
 | 
  if (node.isRemoved()) { 
 | 
    return; 
 | 
  } 
 | 
  var thisLayout = node.getLayout(); 
 | 
  width = thisLayout.width; 
 | 
  height = thisLayout.height; 
 | 
  // Considering border and gap 
 | 
  var nodeModel = node.getModel(); 
 | 
  var borderWidth = nodeModel.get(PATH_BORDER_WIDTH); 
 | 
  var halfGapWidth = nodeModel.get(PATH_GAP_WIDTH) / 2; 
 | 
  var upperLabelHeight = getUpperLabelHeight(nodeModel); 
 | 
  var upperHeight = Math.max(borderWidth, upperLabelHeight); 
 | 
  var layoutOffset = borderWidth - halfGapWidth; 
 | 
  var layoutOffsetUpper = upperHeight - halfGapWidth; 
 | 
  node.setLayout({ 
 | 
    borderWidth: borderWidth, 
 | 
    upperHeight: upperHeight, 
 | 
    upperLabelHeight: upperLabelHeight 
 | 
  }, true); 
 | 
  width = mathMax(width - 2 * layoutOffset, 0); 
 | 
  height = mathMax(height - layoutOffset - layoutOffsetUpper, 0); 
 | 
  var totalArea = width * height; 
 | 
  var viewChildren = initChildren(node, nodeModel, totalArea, options, hideChildren, depth); 
 | 
  if (!viewChildren.length) { 
 | 
    return; 
 | 
  } 
 | 
  var rect = { 
 | 
    x: layoutOffset, 
 | 
    y: layoutOffsetUpper, 
 | 
    width: width, 
 | 
    height: height 
 | 
  }; 
 | 
  var rowFixedLength = mathMin(width, height); 
 | 
  var best = Infinity; // the best row score so far 
 | 
  var row = []; 
 | 
  row.area = 0; 
 | 
  for (var i = 0, len = viewChildren.length; i < len;) { 
 | 
    var child = viewChildren[i]; 
 | 
    row.push(child); 
 | 
    row.area += child.getLayout().area; 
 | 
    var score = worst(row, rowFixedLength, options.squareRatio); 
 | 
    // continue with this orientation 
 | 
    if (score <= best) { 
 | 
      i++; 
 | 
      best = score; 
 | 
    } 
 | 
    // abort, and try a different orientation 
 | 
    else { 
 | 
      row.area -= row.pop().getLayout().area; 
 | 
      position(row, rowFixedLength, rect, halfGapWidth, false); 
 | 
      rowFixedLength = mathMin(rect.width, rect.height); 
 | 
      row.length = row.area = 0; 
 | 
      best = Infinity; 
 | 
    } 
 | 
  } 
 | 
  if (row.length) { 
 | 
    position(row, rowFixedLength, rect, halfGapWidth, true); 
 | 
  } 
 | 
  if (!hideChildren) { 
 | 
    var childrenVisibleMin = nodeModel.get('childrenVisibleMin'); 
 | 
    if (childrenVisibleMin != null && totalArea < childrenVisibleMin) { 
 | 
      hideChildren = true; 
 | 
    } 
 | 
  } 
 | 
  for (var i = 0, len = viewChildren.length; i < len; i++) { 
 | 
    squarify(viewChildren[i], options, hideChildren, depth + 1); 
 | 
  } 
 | 
} 
 | 
/** 
 | 
 * Set area to each child, and calculate data extent for visual coding. 
 | 
 */ 
 | 
function initChildren(node, nodeModel, totalArea, options, hideChildren, depth) { 
 | 
  var viewChildren = node.children || []; 
 | 
  var orderBy = options.sort; 
 | 
  orderBy !== 'asc' && orderBy !== 'desc' && (orderBy = null); 
 | 
  var overLeafDepth = options.leafDepth != null && options.leafDepth <= depth; 
 | 
  // leafDepth has higher priority. 
 | 
  if (hideChildren && !overLeafDepth) { 
 | 
    return node.viewChildren = []; 
 | 
  } 
 | 
  // Sort children, order by desc. 
 | 
  viewChildren = zrUtil.filter(viewChildren, function (child) { 
 | 
    return !child.isRemoved(); 
 | 
  }); 
 | 
  sort(viewChildren, orderBy); 
 | 
  var info = statistic(nodeModel, viewChildren, orderBy); 
 | 
  if (info.sum === 0) { 
 | 
    return node.viewChildren = []; 
 | 
  } 
 | 
  info.sum = filterByThreshold(nodeModel, totalArea, info.sum, orderBy, viewChildren); 
 | 
  if (info.sum === 0) { 
 | 
    return node.viewChildren = []; 
 | 
  } 
 | 
  // Set area to each child. 
 | 
  for (var i = 0, len = viewChildren.length; i < len; i++) { 
 | 
    var area = viewChildren[i].getValue() / info.sum * totalArea; 
 | 
    // Do not use setLayout({...}, true), because it is needed to clear last layout. 
 | 
    viewChildren[i].setLayout({ 
 | 
      area: area 
 | 
    }); 
 | 
  } 
 | 
  if (overLeafDepth) { 
 | 
    viewChildren.length && node.setLayout({ 
 | 
      isLeafRoot: true 
 | 
    }, true); 
 | 
    viewChildren.length = 0; 
 | 
  } 
 | 
  node.viewChildren = viewChildren; 
 | 
  node.setLayout({ 
 | 
    dataExtent: info.dataExtent 
 | 
  }, true); 
 | 
  return viewChildren; 
 | 
} 
 | 
/** 
 | 
 * Consider 'visibleMin'. Modify viewChildren and get new sum. 
 | 
 */ 
 | 
function filterByThreshold(nodeModel, totalArea, sum, orderBy, orderedChildren) { 
 | 
  // visibleMin is not supported yet when no option.sort. 
 | 
  if (!orderBy) { 
 | 
    return sum; 
 | 
  } 
 | 
  var visibleMin = nodeModel.get('visibleMin'); 
 | 
  var len = orderedChildren.length; 
 | 
  var deletePoint = len; 
 | 
  // Always travel from little value to big value. 
 | 
  for (var i = len - 1; i >= 0; i--) { 
 | 
    var value = orderedChildren[orderBy === 'asc' ? len - i - 1 : i].getValue(); 
 | 
    if (value / sum * totalArea < visibleMin) { 
 | 
      deletePoint = i; 
 | 
      sum -= value; 
 | 
    } 
 | 
  } 
 | 
  orderBy === 'asc' ? orderedChildren.splice(0, len - deletePoint) : orderedChildren.splice(deletePoint, len - deletePoint); 
 | 
  return sum; 
 | 
} 
 | 
/** 
 | 
 * Sort 
 | 
 */ 
 | 
function sort(viewChildren, orderBy) { 
 | 
  if (orderBy) { 
 | 
    viewChildren.sort(function (a, b) { 
 | 
      var diff = orderBy === 'asc' ? a.getValue() - b.getValue() : b.getValue() - a.getValue(); 
 | 
      return diff === 0 ? orderBy === 'asc' ? a.dataIndex - b.dataIndex : b.dataIndex - a.dataIndex : diff; 
 | 
    }); 
 | 
  } 
 | 
  return viewChildren; 
 | 
} 
 | 
/** 
 | 
 * Statistic 
 | 
 */ 
 | 
function statistic(nodeModel, children, orderBy) { 
 | 
  // Calculate sum. 
 | 
  var sum = 0; 
 | 
  for (var i = 0, len = children.length; i < len; i++) { 
 | 
    sum += children[i].getValue(); 
 | 
  } 
 | 
  // Statistic data extent for latter visual coding. 
 | 
  // Notice: data extent should be calculate based on raw children 
 | 
  // but not filtered view children, otherwise visual mapping will not 
 | 
  // be stable when zoom (where children is filtered by visibleMin). 
 | 
  var dimension = nodeModel.get('visualDimension'); 
 | 
  var dataExtent; 
 | 
  // The same as area dimension. 
 | 
  if (!children || !children.length) { 
 | 
    dataExtent = [NaN, NaN]; 
 | 
  } else if (dimension === 'value' && orderBy) { 
 | 
    dataExtent = [children[children.length - 1].getValue(), children[0].getValue()]; 
 | 
    orderBy === 'asc' && dataExtent.reverse(); 
 | 
  } 
 | 
  // Other dimension. 
 | 
  else { 
 | 
    dataExtent = [Infinity, -Infinity]; 
 | 
    each(children, function (child) { 
 | 
      var value = child.getValue(dimension); 
 | 
      value < dataExtent[0] && (dataExtent[0] = value); 
 | 
      value > dataExtent[1] && (dataExtent[1] = value); 
 | 
    }); 
 | 
  } 
 | 
  return { 
 | 
    sum: sum, 
 | 
    dataExtent: dataExtent 
 | 
  }; 
 | 
} 
 | 
/** 
 | 
 * Computes the score for the specified row, 
 | 
 * as the worst aspect ratio. 
 | 
 */ 
 | 
function worst(row, rowFixedLength, ratio) { 
 | 
  var areaMax = 0; 
 | 
  var areaMin = Infinity; 
 | 
  for (var i = 0, area = void 0, len = row.length; i < len; i++) { 
 | 
    area = row[i].getLayout().area; 
 | 
    if (area) { 
 | 
      area < areaMin && (areaMin = area); 
 | 
      area > areaMax && (areaMax = area); 
 | 
    } 
 | 
  } 
 | 
  var squareArea = row.area * row.area; 
 | 
  var f = rowFixedLength * rowFixedLength * ratio; 
 | 
  return squareArea ? mathMax(f * areaMax / squareArea, squareArea / (f * areaMin)) : Infinity; 
 | 
} 
 | 
/** 
 | 
 * Positions the specified row of nodes. Modifies `rect`. 
 | 
 */ 
 | 
function position(row, rowFixedLength, rect, halfGapWidth, flush) { 
 | 
  // When rowFixedLength === rect.width, 
 | 
  // it is horizontal subdivision, 
 | 
  // rowFixedLength is the width of the subdivision, 
 | 
  // rowOtherLength is the height of the subdivision, 
 | 
  // and nodes will be positioned from left to right. 
 | 
  // wh[idx0WhenH] means: when horizontal, 
 | 
  //      wh[idx0WhenH] => wh[0] => 'width'. 
 | 
  //      xy[idx1WhenH] => xy[1] => 'y'. 
 | 
  var idx0WhenH = rowFixedLength === rect.width ? 0 : 1; 
 | 
  var idx1WhenH = 1 - idx0WhenH; 
 | 
  var xy = ['x', 'y']; 
 | 
  var wh = ['width', 'height']; 
 | 
  var last = rect[xy[idx0WhenH]]; 
 | 
  var rowOtherLength = rowFixedLength ? row.area / rowFixedLength : 0; 
 | 
  if (flush || rowOtherLength > rect[wh[idx1WhenH]]) { 
 | 
    rowOtherLength = rect[wh[idx1WhenH]]; // over+underflow 
 | 
  } 
 | 
  for (var i = 0, rowLen = row.length; i < rowLen; i++) { 
 | 
    var node = row[i]; 
 | 
    var nodeLayout = {}; 
 | 
    var step = rowOtherLength ? node.getLayout().area / rowOtherLength : 0; 
 | 
    var wh1 = nodeLayout[wh[idx1WhenH]] = mathMax(rowOtherLength - 2 * halfGapWidth, 0); 
 | 
    // We use Math.max/min to avoid negative width/height when considering gap width. 
 | 
    var remain = rect[xy[idx0WhenH]] + rect[wh[idx0WhenH]] - last; 
 | 
    var modWH = i === rowLen - 1 || remain < step ? remain : step; 
 | 
    var wh0 = nodeLayout[wh[idx0WhenH]] = mathMax(modWH - 2 * halfGapWidth, 0); 
 | 
    nodeLayout[xy[idx1WhenH]] = rect[xy[idx1WhenH]] + mathMin(halfGapWidth, wh1 / 2); 
 | 
    nodeLayout[xy[idx0WhenH]] = last + mathMin(halfGapWidth, wh0 / 2); 
 | 
    last += modWH; 
 | 
    node.setLayout(nodeLayout, true); 
 | 
  } 
 | 
  rect[xy[idx1WhenH]] += rowOtherLength; 
 | 
  rect[wh[idx1WhenH]] -= rowOtherLength; 
 | 
} 
 | 
// Return [containerWidth, containerHeight] as default. 
 | 
function estimateRootSize(seriesModel, targetInfo, viewRoot, containerWidth, containerHeight) { 
 | 
  // If targetInfo.node exists, we zoom to the node, 
 | 
  // so estimate whole width and height by target node. 
 | 
  var currNode = (targetInfo || {}).node; 
 | 
  var defaultSize = [containerWidth, containerHeight]; 
 | 
  if (!currNode || currNode === viewRoot) { 
 | 
    return defaultSize; 
 | 
  } 
 | 
  var parent; 
 | 
  var viewArea = containerWidth * containerHeight; 
 | 
  var area = viewArea * seriesModel.option.zoomToNodeRatio; 
 | 
  while (parent = currNode.parentNode) { 
 | 
    // jshint ignore:line 
 | 
    var sum = 0; 
 | 
    var siblings = parent.children; 
 | 
    for (var i = 0, len = siblings.length; i < len; i++) { 
 | 
      sum += siblings[i].getValue(); 
 | 
    } 
 | 
    var currNodeValue = currNode.getValue(); 
 | 
    if (currNodeValue === 0) { 
 | 
      return defaultSize; 
 | 
    } 
 | 
    area *= sum / currNodeValue; 
 | 
    // Considering border, suppose aspect ratio is 1. 
 | 
    var parentModel = parent.getModel(); 
 | 
    var borderWidth = parentModel.get(PATH_BORDER_WIDTH); 
 | 
    var upperHeight = Math.max(borderWidth, getUpperLabelHeight(parentModel)); 
 | 
    area += 4 * borderWidth * borderWidth + (3 * borderWidth + upperHeight) * Math.pow(area, 0.5); 
 | 
    area > MAX_SAFE_INTEGER && (area = MAX_SAFE_INTEGER); 
 | 
    currNode = parent; 
 | 
  } 
 | 
  area < viewArea && (area = viewArea); 
 | 
  var scale = Math.pow(area / viewArea, 0.5); 
 | 
  return [containerWidth * scale, containerHeight * scale]; 
 | 
} 
 | 
// Root position based on coord of containerGroup 
 | 
function calculateRootPosition(layoutInfo, rootRect, targetInfo) { 
 | 
  if (rootRect) { 
 | 
    return { 
 | 
      x: rootRect.x, 
 | 
      y: rootRect.y 
 | 
    }; 
 | 
  } 
 | 
  var defaultPosition = { 
 | 
    x: 0, 
 | 
    y: 0 
 | 
  }; 
 | 
  if (!targetInfo) { 
 | 
    return defaultPosition; 
 | 
  } 
 | 
  // If targetInfo is fetched by 'retrieveTargetInfo', 
 | 
  // old tree and new tree are the same tree, 
 | 
  // so the node still exists and we can visit it. 
 | 
  var targetNode = targetInfo.node; 
 | 
  var layout = targetNode.getLayout(); 
 | 
  if (!layout) { 
 | 
    return defaultPosition; 
 | 
  } 
 | 
  // Transform coord from local to container. 
 | 
  var targetCenter = [layout.width / 2, layout.height / 2]; 
 | 
  var node = targetNode; 
 | 
  while (node) { 
 | 
    var nodeLayout = node.getLayout(); 
 | 
    targetCenter[0] += nodeLayout.x; 
 | 
    targetCenter[1] += nodeLayout.y; 
 | 
    node = node.parentNode; 
 | 
  } 
 | 
  return { 
 | 
    x: layoutInfo.width / 2 - targetCenter[0], 
 | 
    y: layoutInfo.height / 2 - targetCenter[1] 
 | 
  }; 
 | 
} 
 | 
// Mark nodes visible for prunning when visual coding and rendering. 
 | 
// Prunning depends on layout and root position, so we have to do it after layout. 
 | 
function prunning(node, clipRect, viewAbovePath, viewRoot, depth) { 
 | 
  var nodeLayout = node.getLayout(); 
 | 
  var nodeInViewAbovePath = viewAbovePath[depth]; 
 | 
  var isAboveViewRoot = nodeInViewAbovePath && nodeInViewAbovePath === node; 
 | 
  if (nodeInViewAbovePath && !isAboveViewRoot || depth === viewAbovePath.length && node !== viewRoot) { 
 | 
    return; 
 | 
  } 
 | 
  node.setLayout({ 
 | 
    // isInView means: viewRoot sub tree + viewAbovePath 
 | 
    isInView: true, 
 | 
    // invisible only means: outside view clip so that the node can not 
 | 
    // see but still layout for animation preparation but not render. 
 | 
    invisible: !isAboveViewRoot && !clipRect.intersect(nodeLayout), 
 | 
    isAboveViewRoot: isAboveViewRoot 
 | 
  }, true); 
 | 
  // Transform to child coordinate. 
 | 
  var childClipRect = new BoundingRect(clipRect.x - nodeLayout.x, clipRect.y - nodeLayout.y, clipRect.width, clipRect.height); 
 | 
  each(node.viewChildren || [], function (child) { 
 | 
    prunning(child, childClipRect, viewAbovePath, viewRoot, depth + 1); 
 | 
  }); 
 | 
} 
 | 
function getUpperLabelHeight(model) { 
 | 
  return model.get(PATH_UPPER_LABEL_SHOW) ? model.get(PATH_UPPER_LABEL_HEIGHT) : 0; 
 | 
} 
 |