|   | 
| /* | 
| * 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 * as zrUtil from 'zrender/lib/core/util.js'; | 
| import * as graphic from '../../util/graphic.js'; | 
| import { getECData } from '../../util/innerStore.js'; | 
| import SymbolClz from '../helper/Symbol.js'; | 
| import { radialCoordinate } from './layoutHelper.js'; | 
| import * as bbox from 'zrender/lib/core/bbox.js'; | 
| import View from '../../coord/View.js'; | 
| import * as roamHelper from '../../component/helper/roamHelper.js'; | 
| import RoamController from '../../component/helper/RoamController.js'; | 
| import { onIrrelevantElement } from '../../component/helper/cursorHelper.js'; | 
| import { parsePercent } from '../../util/number.js'; | 
| import ChartView from '../../view/Chart.js'; | 
| import Path from 'zrender/lib/graphic/Path.js'; | 
| import { setStatesStylesFromModel, setStatesFlag, setDefaultStateProxy, HOVER_STATE_BLUR } from '../../util/states.js'; | 
| var TreeEdgeShape = /** @class */function () { | 
|   function TreeEdgeShape() { | 
|     this.parentPoint = []; | 
|     this.childPoints = []; | 
|   } | 
|   return TreeEdgeShape; | 
| }(); | 
| var TreePath = /** @class */function (_super) { | 
|   __extends(TreePath, _super); | 
|   function TreePath(opts) { | 
|     return _super.call(this, opts) || this; | 
|   } | 
|   TreePath.prototype.getDefaultStyle = function () { | 
|     return { | 
|       stroke: '#000', | 
|       fill: null | 
|     }; | 
|   }; | 
|   TreePath.prototype.getDefaultShape = function () { | 
|     return new TreeEdgeShape(); | 
|   }; | 
|   TreePath.prototype.buildPath = function (ctx, shape) { | 
|     var childPoints = shape.childPoints; | 
|     var childLen = childPoints.length; | 
|     var parentPoint = shape.parentPoint; | 
|     var firstChildPos = childPoints[0]; | 
|     var lastChildPos = childPoints[childLen - 1]; | 
|     if (childLen === 1) { | 
|       ctx.moveTo(parentPoint[0], parentPoint[1]); | 
|       ctx.lineTo(firstChildPos[0], firstChildPos[1]); | 
|       return; | 
|     } | 
|     var orient = shape.orient; | 
|     var forkDim = orient === 'TB' || orient === 'BT' ? 0 : 1; | 
|     var otherDim = 1 - forkDim; | 
|     var forkPosition = parsePercent(shape.forkPosition, 1); | 
|     var tmpPoint = []; | 
|     tmpPoint[forkDim] = parentPoint[forkDim]; | 
|     tmpPoint[otherDim] = parentPoint[otherDim] + (lastChildPos[otherDim] - parentPoint[otherDim]) * forkPosition; | 
|     ctx.moveTo(parentPoint[0], parentPoint[1]); | 
|     ctx.lineTo(tmpPoint[0], tmpPoint[1]); | 
|     ctx.moveTo(firstChildPos[0], firstChildPos[1]); | 
|     tmpPoint[forkDim] = firstChildPos[forkDim]; | 
|     ctx.lineTo(tmpPoint[0], tmpPoint[1]); | 
|     tmpPoint[forkDim] = lastChildPos[forkDim]; | 
|     ctx.lineTo(tmpPoint[0], tmpPoint[1]); | 
|     ctx.lineTo(lastChildPos[0], lastChildPos[1]); | 
|     for (var i = 1; i < childLen - 1; i++) { | 
|       var point = childPoints[i]; | 
|       ctx.moveTo(point[0], point[1]); | 
|       tmpPoint[forkDim] = point[forkDim]; | 
|       ctx.lineTo(tmpPoint[0], tmpPoint[1]); | 
|     } | 
|   }; | 
|   return TreePath; | 
| }(Path); | 
| var TreeView = /** @class */function (_super) { | 
|   __extends(TreeView, _super); | 
|   function TreeView() { | 
|     var _this = _super !== null && _super.apply(this, arguments) || this; | 
|     _this.type = TreeView.type; | 
|     _this._mainGroup = new graphic.Group(); | 
|     return _this; | 
|   } | 
|   TreeView.prototype.init = function (ecModel, api) { | 
|     this._controller = new RoamController(api.getZr()); | 
|     this._controllerHost = { | 
|       target: this.group | 
|     }; | 
|     this.group.add(this._mainGroup); | 
|   }; | 
|   TreeView.prototype.render = function (seriesModel, ecModel, api) { | 
|     var data = seriesModel.getData(); | 
|     var layoutInfo = seriesModel.layoutInfo; | 
|     var group = this._mainGroup; | 
|     var layout = seriesModel.get('layout'); | 
|     if (layout === 'radial') { | 
|       group.x = layoutInfo.x + layoutInfo.width / 2; | 
|       group.y = layoutInfo.y + layoutInfo.height / 2; | 
|     } else { | 
|       group.x = layoutInfo.x; | 
|       group.y = layoutInfo.y; | 
|     } | 
|     this._updateViewCoordSys(seriesModel, api); | 
|     this._updateController(seriesModel, ecModel, api); | 
|     var oldData = this._data; | 
|     data.diff(oldData).add(function (newIdx) { | 
|       if (symbolNeedsDraw(data, newIdx)) { | 
|         // Create node and edge | 
|         updateNode(data, newIdx, null, group, seriesModel); | 
|       } | 
|     }).update(function (newIdx, oldIdx) { | 
|       var symbolEl = oldData.getItemGraphicEl(oldIdx); | 
|       if (!symbolNeedsDraw(data, newIdx)) { | 
|         symbolEl && removeNode(oldData, oldIdx, symbolEl, group, seriesModel); | 
|         return; | 
|       } | 
|       // Update node and edge | 
|       updateNode(data, newIdx, symbolEl, group, seriesModel); | 
|     }).remove(function (oldIdx) { | 
|       var symbolEl = oldData.getItemGraphicEl(oldIdx); | 
|       // When remove a collapsed node of subtree, since the collapsed | 
|       // node haven't been initialized with a symbol element, | 
|       // you can't found it's symbol element through index. | 
|       // so if we want to remove the symbol element we should insure | 
|       // that the symbol element is not null. | 
|       if (symbolEl) { | 
|         removeNode(oldData, oldIdx, symbolEl, group, seriesModel); | 
|       } | 
|     }).execute(); | 
|     this._nodeScaleRatio = seriesModel.get('nodeScaleRatio'); | 
|     this._updateNodeAndLinkScale(seriesModel); | 
|     if (seriesModel.get('expandAndCollapse') === true) { | 
|       data.eachItemGraphicEl(function (el, dataIndex) { | 
|         el.off('click').on('click', function () { | 
|           api.dispatchAction({ | 
|             type: 'treeExpandAndCollapse', | 
|             seriesId: seriesModel.id, | 
|             dataIndex: dataIndex | 
|           }); | 
|         }); | 
|       }); | 
|     } | 
|     this._data = data; | 
|   }; | 
|   TreeView.prototype._updateViewCoordSys = function (seriesModel, api) { | 
|     var data = seriesModel.getData(); | 
|     var points = []; | 
|     data.each(function (idx) { | 
|       var layout = data.getItemLayout(idx); | 
|       if (layout && !isNaN(layout.x) && !isNaN(layout.y)) { | 
|         points.push([+layout.x, +layout.y]); | 
|       } | 
|     }); | 
|     var min = []; | 
|     var max = []; | 
|     bbox.fromPoints(points, min, max); | 
|     // If don't Store min max when collapse the root node after roam, | 
|     // the root node will disappear. | 
|     var oldMin = this._min; | 
|     var oldMax = this._max; | 
|     // If width or height is 0 | 
|     if (max[0] - min[0] === 0) { | 
|       min[0] = oldMin ? oldMin[0] : min[0] - 1; | 
|       max[0] = oldMax ? oldMax[0] : max[0] + 1; | 
|     } | 
|     if (max[1] - min[1] === 0) { | 
|       min[1] = oldMin ? oldMin[1] : min[1] - 1; | 
|       max[1] = oldMax ? oldMax[1] : max[1] + 1; | 
|     } | 
|     var viewCoordSys = seriesModel.coordinateSystem = new View(); | 
|     viewCoordSys.zoomLimit = seriesModel.get('scaleLimit'); | 
|     viewCoordSys.setBoundingRect(min[0], min[1], max[0] - min[0], max[1] - min[1]); | 
|     viewCoordSys.setCenter(seriesModel.get('center'), api); | 
|     viewCoordSys.setZoom(seriesModel.get('zoom')); | 
|     // Here we use viewCoordSys just for computing the 'position' and 'scale' of the group | 
|     this.group.attr({ | 
|       x: viewCoordSys.x, | 
|       y: viewCoordSys.y, | 
|       scaleX: viewCoordSys.scaleX, | 
|       scaleY: viewCoordSys.scaleY | 
|     }); | 
|     this._min = min; | 
|     this._max = max; | 
|   }; | 
|   TreeView.prototype._updateController = function (seriesModel, ecModel, api) { | 
|     var _this = this; | 
|     var controller = this._controller; | 
|     var controllerHost = this._controllerHost; | 
|     var group = this.group; | 
|     controller.setPointerChecker(function (e, x, y) { | 
|       var rect = group.getBoundingRect(); | 
|       rect.applyTransform(group.transform); | 
|       return rect.contain(x, y) && !onIrrelevantElement(e, api, seriesModel); | 
|     }); | 
|     controller.enable(seriesModel.get('roam')); | 
|     controllerHost.zoomLimit = seriesModel.get('scaleLimit'); | 
|     controllerHost.zoom = seriesModel.coordinateSystem.getZoom(); | 
|     controller.off('pan').off('zoom').on('pan', function (e) { | 
|       roamHelper.updateViewOnPan(controllerHost, e.dx, e.dy); | 
|       api.dispatchAction({ | 
|         seriesId: seriesModel.id, | 
|         type: 'treeRoam', | 
|         dx: e.dx, | 
|         dy: e.dy | 
|       }); | 
|     }).on('zoom', function (e) { | 
|       roamHelper.updateViewOnZoom(controllerHost, e.scale, e.originX, e.originY); | 
|       api.dispatchAction({ | 
|         seriesId: seriesModel.id, | 
|         type: 'treeRoam', | 
|         zoom: e.scale, | 
|         originX: e.originX, | 
|         originY: e.originY | 
|       }); | 
|       _this._updateNodeAndLinkScale(seriesModel); | 
|       // Only update label layout on zoom | 
|       api.updateLabelLayout(); | 
|     }); | 
|   }; | 
|   TreeView.prototype._updateNodeAndLinkScale = function (seriesModel) { | 
|     var data = seriesModel.getData(); | 
|     var nodeScale = this._getNodeGlobalScale(seriesModel); | 
|     data.eachItemGraphicEl(function (el, idx) { | 
|       el.setSymbolScale(nodeScale); | 
|     }); | 
|   }; | 
|   TreeView.prototype._getNodeGlobalScale = function (seriesModel) { | 
|     var coordSys = seriesModel.coordinateSystem; | 
|     if (coordSys.type !== 'view') { | 
|       return 1; | 
|     } | 
|     var nodeScaleRatio = this._nodeScaleRatio; | 
|     var groupZoom = coordSys.scaleX || 1; | 
|     // Scale node when zoom changes | 
|     var roamZoom = coordSys.getZoom(); | 
|     var nodeScale = (roamZoom - 1) * nodeScaleRatio + 1; | 
|     return nodeScale / groupZoom; | 
|   }; | 
|   TreeView.prototype.dispose = function () { | 
|     this._controller && this._controller.dispose(); | 
|     this._controllerHost = null; | 
|   }; | 
|   TreeView.prototype.remove = function () { | 
|     this._mainGroup.removeAll(); | 
|     this._data = null; | 
|   }; | 
|   TreeView.type = 'tree'; | 
|   return TreeView; | 
| }(ChartView); | 
| function symbolNeedsDraw(data, dataIndex) { | 
|   var layout = data.getItemLayout(dataIndex); | 
|   return layout && !isNaN(layout.x) && !isNaN(layout.y); | 
| } | 
| function updateNode(data, dataIndex, symbolEl, group, seriesModel) { | 
|   var isInit = !symbolEl; | 
|   var node = data.tree.getNodeByDataIndex(dataIndex); | 
|   var itemModel = node.getModel(); | 
|   var visualColor = node.getVisual('style').fill; | 
|   var symbolInnerColor = node.isExpand === false && node.children.length !== 0 ? visualColor : '#fff'; | 
|   var virtualRoot = data.tree.root; | 
|   var source = node.parentNode === virtualRoot ? node : node.parentNode || node; | 
|   var sourceSymbolEl = data.getItemGraphicEl(source.dataIndex); | 
|   var sourceLayout = source.getLayout(); | 
|   var sourceOldLayout = sourceSymbolEl ? { | 
|     x: sourceSymbolEl.__oldX, | 
|     y: sourceSymbolEl.__oldY, | 
|     rawX: sourceSymbolEl.__radialOldRawX, | 
|     rawY: sourceSymbolEl.__radialOldRawY | 
|   } : sourceLayout; | 
|   var targetLayout = node.getLayout(); | 
|   if (isInit) { | 
|     symbolEl = new SymbolClz(data, dataIndex, null, { | 
|       symbolInnerColor: symbolInnerColor, | 
|       useNameLabel: true | 
|     }); | 
|     symbolEl.x = sourceOldLayout.x; | 
|     symbolEl.y = sourceOldLayout.y; | 
|   } else { | 
|     symbolEl.updateData(data, dataIndex, null, { | 
|       symbolInnerColor: symbolInnerColor, | 
|       useNameLabel: true | 
|     }); | 
|   } | 
|   symbolEl.__radialOldRawX = symbolEl.__radialRawX; | 
|   symbolEl.__radialOldRawY = symbolEl.__radialRawY; | 
|   symbolEl.__radialRawX = targetLayout.rawX; | 
|   symbolEl.__radialRawY = targetLayout.rawY; | 
|   group.add(symbolEl); | 
|   data.setItemGraphicEl(dataIndex, symbolEl); | 
|   symbolEl.__oldX = symbolEl.x; | 
|   symbolEl.__oldY = symbolEl.y; | 
|   graphic.updateProps(symbolEl, { | 
|     x: targetLayout.x, | 
|     y: targetLayout.y | 
|   }, seriesModel); | 
|   var symbolPath = symbolEl.getSymbolPath(); | 
|   if (seriesModel.get('layout') === 'radial') { | 
|     var realRoot = virtualRoot.children[0]; | 
|     var rootLayout = realRoot.getLayout(); | 
|     var length_1 = realRoot.children.length; | 
|     var rad = void 0; | 
|     var isLeft = void 0; | 
|     if (targetLayout.x === rootLayout.x && node.isExpand === true && realRoot.children.length) { | 
|       var center = { | 
|         x: (realRoot.children[0].getLayout().x + realRoot.children[length_1 - 1].getLayout().x) / 2, | 
|         y: (realRoot.children[0].getLayout().y + realRoot.children[length_1 - 1].getLayout().y) / 2 | 
|       }; | 
|       rad = Math.atan2(center.y - rootLayout.y, center.x - rootLayout.x); | 
|       if (rad < 0) { | 
|         rad = Math.PI * 2 + rad; | 
|       } | 
|       isLeft = center.x < rootLayout.x; | 
|       if (isLeft) { | 
|         rad = rad - Math.PI; | 
|       } | 
|     } else { | 
|       rad = Math.atan2(targetLayout.y - rootLayout.y, targetLayout.x - rootLayout.x); | 
|       if (rad < 0) { | 
|         rad = Math.PI * 2 + rad; | 
|       } | 
|       if (node.children.length === 0 || node.children.length !== 0 && node.isExpand === false) { | 
|         isLeft = targetLayout.x < rootLayout.x; | 
|         if (isLeft) { | 
|           rad = rad - Math.PI; | 
|         } | 
|       } else { | 
|         isLeft = targetLayout.x > rootLayout.x; | 
|         if (!isLeft) { | 
|           rad = rad - Math.PI; | 
|         } | 
|       } | 
|     } | 
|     var textPosition = isLeft ? 'left' : 'right'; | 
|     var normalLabelModel = itemModel.getModel('label'); | 
|     var rotate = normalLabelModel.get('rotate'); | 
|     var labelRotateRadian = rotate * (Math.PI / 180); | 
|     var textContent = symbolPath.getTextContent(); | 
|     if (textContent) { | 
|       symbolPath.setTextConfig({ | 
|         position: normalLabelModel.get('position') || textPosition, | 
|         rotation: rotate == null ? -rad : labelRotateRadian, | 
|         origin: 'center' | 
|       }); | 
|       textContent.setStyle('verticalAlign', 'middle'); | 
|     } | 
|   } | 
|   // Handle status | 
|   var focus = itemModel.get(['emphasis', 'focus']); | 
|   var focusDataIndices = focus === 'relative' ? zrUtil.concatArray(node.getAncestorsIndices(), node.getDescendantIndices()) : focus === 'ancestor' ? node.getAncestorsIndices() : focus === 'descendant' ? node.getDescendantIndices() : null; | 
|   if (focusDataIndices) { | 
|     // Modify the focus to data indices. | 
|     getECData(symbolEl).focus = focusDataIndices; | 
|   } | 
|   drawEdge(seriesModel, node, virtualRoot, symbolEl, sourceOldLayout, sourceLayout, targetLayout, group); | 
|   if (symbolEl.__edge) { | 
|     symbolEl.onHoverStateChange = function (toState) { | 
|       if (toState !== 'blur') { | 
|         // NOTE: Ensure the parent elements will been blurred firstly. | 
|         // According to the return of getAncestorsIndices and getDescendantIndices | 
|         // TODO: A bit tricky. | 
|         var parentEl = node.parentNode && data.getItemGraphicEl(node.parentNode.dataIndex); | 
|         if (!(parentEl && parentEl.hoverState === HOVER_STATE_BLUR)) { | 
|           setStatesFlag(symbolEl.__edge, toState); | 
|         } | 
|       } | 
|     }; | 
|   } | 
| } | 
| function drawEdge(seriesModel, node, virtualRoot, symbolEl, sourceOldLayout, sourceLayout, targetLayout, group) { | 
|   var itemModel = node.getModel(); | 
|   var edgeShape = seriesModel.get('edgeShape'); | 
|   var layout = seriesModel.get('layout'); | 
|   var orient = seriesModel.getOrient(); | 
|   var curvature = seriesModel.get(['lineStyle', 'curveness']); | 
|   var edgeForkPosition = seriesModel.get('edgeForkPosition'); | 
|   var lineStyle = itemModel.getModel('lineStyle').getLineStyle(); | 
|   var edge = symbolEl.__edge; | 
|   // curve edge from node -> parent | 
|   // polyline edge from node -> children | 
|   if (edgeShape === 'curve') { | 
|     if (node.parentNode && node.parentNode !== virtualRoot) { | 
|       if (!edge) { | 
|         edge = symbolEl.__edge = new graphic.BezierCurve({ | 
|           shape: getEdgeShape(layout, orient, curvature, sourceOldLayout, sourceOldLayout) | 
|         }); | 
|       } | 
|       graphic.updateProps(edge, { | 
|         shape: getEdgeShape(layout, orient, curvature, sourceLayout, targetLayout) | 
|       }, seriesModel); | 
|     } | 
|   } else if (edgeShape === 'polyline') { | 
|     if (layout === 'orthogonal') { | 
|       if (node !== virtualRoot && node.children && node.children.length !== 0 && node.isExpand === true) { | 
|         var children = node.children; | 
|         var childPoints = []; | 
|         for (var i = 0; i < children.length; i++) { | 
|           var childLayout = children[i].getLayout(); | 
|           childPoints.push([childLayout.x, childLayout.y]); | 
|         } | 
|         if (!edge) { | 
|           edge = symbolEl.__edge = new TreePath({ | 
|             shape: { | 
|               parentPoint: [targetLayout.x, targetLayout.y], | 
|               childPoints: [[targetLayout.x, targetLayout.y]], | 
|               orient: orient, | 
|               forkPosition: edgeForkPosition | 
|             } | 
|           }); | 
|         } | 
|         graphic.updateProps(edge, { | 
|           shape: { | 
|             parentPoint: [targetLayout.x, targetLayout.y], | 
|             childPoints: childPoints | 
|           } | 
|         }, seriesModel); | 
|       } | 
|     } else { | 
|       if (process.env.NODE_ENV !== 'production') { | 
|         throw new Error('The polyline edgeShape can only be used in orthogonal layout'); | 
|       } | 
|     } | 
|   } | 
|   // show all edge when edgeShape is 'curve', filter node `isExpand` is false when edgeShape is 'polyline' | 
|   if (edge && !(edgeShape === 'polyline' && !node.isExpand)) { | 
|     edge.useStyle(zrUtil.defaults({ | 
|       strokeNoScale: true, | 
|       fill: null | 
|     }, lineStyle)); | 
|     setStatesStylesFromModel(edge, itemModel, 'lineStyle'); | 
|     setDefaultStateProxy(edge); | 
|     group.add(edge); | 
|   } | 
| } | 
| function removeNodeEdge(node, data, group, seriesModel, removeAnimationOpt) { | 
|   var virtualRoot = data.tree.root; | 
|   var _a = getSourceNode(virtualRoot, node), | 
|     source = _a.source, | 
|     sourceLayout = _a.sourceLayout; | 
|   var symbolEl = data.getItemGraphicEl(node.dataIndex); | 
|   if (!symbolEl) { | 
|     return; | 
|   } | 
|   var sourceSymbolEl = data.getItemGraphicEl(source.dataIndex); | 
|   var sourceEdge = sourceSymbolEl.__edge; | 
|   // 1. when expand the sub tree, delete the children node should delete the edge of | 
|   // the source at the same time. because the polyline edge shape is only owned by the source. | 
|   // 2.when the node is the only children of the source, delete the node should delete the edge of | 
|   // the source at the same time. the same reason as above. | 
|   var edge = symbolEl.__edge || (source.isExpand === false || source.children.length === 1 ? sourceEdge : undefined); | 
|   var edgeShape = seriesModel.get('edgeShape'); | 
|   var layoutOpt = seriesModel.get('layout'); | 
|   var orient = seriesModel.get('orient'); | 
|   var curvature = seriesModel.get(['lineStyle', 'curveness']); | 
|   if (edge) { | 
|     if (edgeShape === 'curve') { | 
|       graphic.removeElement(edge, { | 
|         shape: getEdgeShape(layoutOpt, orient, curvature, sourceLayout, sourceLayout), | 
|         style: { | 
|           opacity: 0 | 
|         } | 
|       }, seriesModel, { | 
|         cb: function () { | 
|           group.remove(edge); | 
|         }, | 
|         removeOpt: removeAnimationOpt | 
|       }); | 
|     } else if (edgeShape === 'polyline' && seriesModel.get('layout') === 'orthogonal') { | 
|       graphic.removeElement(edge, { | 
|         shape: { | 
|           parentPoint: [sourceLayout.x, sourceLayout.y], | 
|           childPoints: [[sourceLayout.x, sourceLayout.y]] | 
|         }, | 
|         style: { | 
|           opacity: 0 | 
|         } | 
|       }, seriesModel, { | 
|         cb: function () { | 
|           group.remove(edge); | 
|         }, | 
|         removeOpt: removeAnimationOpt | 
|       }); | 
|     } | 
|   } | 
| } | 
| function getSourceNode(virtualRoot, node) { | 
|   var source = node.parentNode === virtualRoot ? node : node.parentNode || node; | 
|   var sourceLayout; | 
|   while (sourceLayout = source.getLayout(), sourceLayout == null) { | 
|     source = source.parentNode === virtualRoot ? source : source.parentNode || source; | 
|   } | 
|   return { | 
|     source: source, | 
|     sourceLayout: sourceLayout | 
|   }; | 
| } | 
| function removeNode(data, dataIndex, symbolEl, group, seriesModel) { | 
|   var node = data.tree.getNodeByDataIndex(dataIndex); | 
|   var virtualRoot = data.tree.root; | 
|   var sourceLayout = getSourceNode(virtualRoot, node).sourceLayout; | 
|   // Use same duration and easing with update to have more consistent animation. | 
|   var removeAnimationOpt = { | 
|     duration: seriesModel.get('animationDurationUpdate'), | 
|     easing: seriesModel.get('animationEasingUpdate') | 
|   }; | 
|   graphic.removeElement(symbolEl, { | 
|     x: sourceLayout.x + 1, | 
|     y: sourceLayout.y + 1 | 
|   }, seriesModel, { | 
|     cb: function () { | 
|       group.remove(symbolEl); | 
|       data.setItemGraphicEl(dataIndex, null); | 
|     }, | 
|     removeOpt: removeAnimationOpt | 
|   }); | 
|   symbolEl.fadeOut(null, data.hostModel, { | 
|     fadeLabel: true, | 
|     animation: removeAnimationOpt | 
|   }); | 
|   // remove edge as parent node | 
|   node.children.forEach(function (childNode) { | 
|     removeNodeEdge(childNode, data, group, seriesModel, removeAnimationOpt); | 
|   }); | 
|   // remove edge as child node | 
|   removeNodeEdge(node, data, group, seriesModel, removeAnimationOpt); | 
| } | 
| function getEdgeShape(layoutOpt, orient, curvature, sourceLayout, targetLayout) { | 
|   var cpx1; | 
|   var cpy1; | 
|   var cpx2; | 
|   var cpy2; | 
|   var x1; | 
|   var x2; | 
|   var y1; | 
|   var y2; | 
|   if (layoutOpt === 'radial') { | 
|     x1 = sourceLayout.rawX; | 
|     y1 = sourceLayout.rawY; | 
|     x2 = targetLayout.rawX; | 
|     y2 = targetLayout.rawY; | 
|     var radialCoor1 = radialCoordinate(x1, y1); | 
|     var radialCoor2 = radialCoordinate(x1, y1 + (y2 - y1) * curvature); | 
|     var radialCoor3 = radialCoordinate(x2, y2 + (y1 - y2) * curvature); | 
|     var radialCoor4 = radialCoordinate(x2, y2); | 
|     return { | 
|       x1: radialCoor1.x || 0, | 
|       y1: radialCoor1.y || 0, | 
|       x2: radialCoor4.x || 0, | 
|       y2: radialCoor4.y || 0, | 
|       cpx1: radialCoor2.x || 0, | 
|       cpy1: radialCoor2.y || 0, | 
|       cpx2: radialCoor3.x || 0, | 
|       cpy2: radialCoor3.y || 0 | 
|     }; | 
|   } else { | 
|     x1 = sourceLayout.x; | 
|     y1 = sourceLayout.y; | 
|     x2 = targetLayout.x; | 
|     y2 = targetLayout.y; | 
|     if (orient === 'LR' || orient === 'RL') { | 
|       cpx1 = x1 + (x2 - x1) * curvature; | 
|       cpy1 = y1; | 
|       cpx2 = x2 + (x1 - x2) * curvature; | 
|       cpy2 = y2; | 
|     } | 
|     if (orient === 'TB' || orient === 'BT') { | 
|       cpx1 = x1; | 
|       cpy1 = y1 + (y2 - y1) * curvature; | 
|       cpx2 = x2; | 
|       cpy2 = y2 + (y1 - y2) * curvature; | 
|     } | 
|   } | 
|   return { | 
|     x1: x1, | 
|     y1: y1, | 
|     x2: x2, | 
|     y2: y2, | 
|     cpx1: cpx1, | 
|     cpy1: cpy1, | 
|     cpx2: cpx2, | 
|     cpy2: cpy2 | 
|   }; | 
| } | 
| export default TreeView; |