text: define('echarts/chart/tree', [
      'require',
      './base',
      'zrender/tool/area',
      'zrender/tool/vector',
      '../util/shape/Icon',
      'zrender/shape/Image',
      'zrender/shape/Line',
      'zrender/shape/BezierCurve',
      '../layout/Tree',
      '../data/Tree',
      '../config',
      '../util/ecData',
      'zrender/config',
      'zrender/tool/event',
      'zrender/tool/util',
      '../chart'
  ], function (require) {
      var ChartBase = require('./base');
      var GOLDEN_SECTION = 0.618;
      var toolArea = require('zrender/tool/area');
      var vec2 = require('zrender/tool/vector');
      var IconShape = require('../util/shape/Icon');
      var ImageShape = require('zrender/shape/Image');
      var LineShape = require('zrender/shape/Line');
      var BezierCurveShape = require('zrender/shape/BezierCurve');
      var TreeLayout = require('../layout/Tree');
      var TreeData = require('../data/Tree');
      var ecConfig = require('../config');
      ecConfig.tree = {
          zlevel: 1,
          z: 2,
          calculable: false,
          clickable: true,
          rootLocation: {},
          orient: 'vertical',
          symbol: 'circle',
          symbolSize: 20,
          nodePadding: 30,
          layerPadding: 100,
          itemStyle: {
              normal: {
                  label: { show: true },
                  lineStyle: {
                      width: 1,
                      color: '#777',
                      type: 'curve'
                  }
              },
              emphasis: {}
          }
      };
      var ecData = require('../util/ecData');
      var zrConfig = require('zrender/config');
      var zrEvent = require('zrender/tool/event');
      var zrUtil = require('zrender/tool/util');
      function Tree(ecTheme, messageCenter, zr, option, myChart) {
          ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
          this.refresh(option);
      }
      Tree.prototype = {
          type: ecConfig.CHART_TYPE_TREE,
          _buildShape: function (series, seriesIndex) {
              var data = series.data[0];
              this.tree = TreeData.fromOptionData(data.name, data.children);
              this.tree.root.data = data;
              this._setTreeShape(series);
              this.tree.traverse(function (treeNode) {
                  this._buildItem(treeNode, series, seriesIndex);
                  if (treeNode.children.length > 0) {
                      this._buildLink(treeNode, series);
                  }
              }, this);
              var panable = series.roam === true || series.roam === 'move';
              var zoomable = series.roam === true || series.roam === 'scale';
              this.zr.modLayer(this.getZlevelBase(), {
                  panable: panable,
                  zoomable: zoomable
              });
              if (this.query('markPoint.effect.show') || this.query('markLine.effect.show')) {
                  this.zr.modLayer(ecConfig.EFFECT_ZLEVEL, {
                      panable: panable,
                      zoomable: zoomable
                  });
              }
              this.addShapeList();
          },
          _buildItem: function (treeNode, serie, seriesIndex) {
              var queryTarget = [
                  treeNode.data,
                  serie
              ];
              var symbol = this.deepQuery(queryTarget, 'symbol');
              var normal = this.deepMerge(queryTarget, 'itemStyle.normal') || {};
              var emphasis = this.deepMerge(queryTarget, 'itemStyle.emphasis') || {};
              var normalColor = normal.color || this.zr.getColor();
              var emphasisColor = emphasis.color || this.zr.getColor();
              var angle = -treeNode.layout.angle || 0;
              if (treeNode.id === this.tree.root.id) {
                  angle = 0;
              }
              var textPosition = 'right';
              if (Math.abs(angle) >= Math.PI / 2 && Math.abs(angle) < Math.PI * 3 / 2) {
                  angle += Math.PI;
                  textPosition = 'left';
              }
              var rotation = [
                  angle,
                  treeNode.layout.position[0],
                  treeNode.layout.position[1]
              ];
              var shape = new IconShape({
                  zlevel: this.getZlevelBase(),
                  z: this.getZBase() + 1,
                  rotation: rotation,
                  style: {
                      x: treeNode.layout.position[0] - treeNode.layout.width * 0.5,
                      y: treeNode.layout.position[1] - treeNode.layout.height * 0.5,
                      width: treeNode.layout.width,
                      height: treeNode.layout.height,
                      iconType: symbol,
                      color: normalColor,
                      brushType: 'both',
                      lineWidth: normal.borderWidth,
                      strokeColor: normal.borderColor
                  },
                  highlightStyle: {
                      color: emphasisColor,
                      lineWidth: emphasis.borderWidth,
                      strokeColor: emphasis.borderColor
                  }
              });
              if (shape.style.iconType.match('image')) {
                  shape.style.image = shape.style.iconType.replace(new RegExp('^image:\\/\\/'), '');
                  shape = new ImageShape({
                      rotation: rotation,
                      style: shape.style,
                      highlightStyle: shape.highlightStyle,
                      clickable: shape.clickable,
                      zlevel: this.getZlevelBase(),
                      z: this.getZBase()
                  });
              }
              if (this.deepQuery(queryTarget, 'itemStyle.normal.label.show')) {
                  shape.style.text = treeNode.data.label == null ? treeNode.id : treeNode.data.label;
                  shape.style.textPosition = this.deepQuery(queryTarget, 'itemStyle.normal.label.position');
                  if (serie.orient === 'radial' && shape.style.textPosition !== 'inside') {
                      shape.style.textPosition = textPosition;
                  }
                  shape.style.textColor = this.deepQuery(queryTarget, 'itemStyle.normal.label.textStyle.color');
                  shape.style.textFont = this.getFont(this.deepQuery(queryTarget, 'itemStyle.normal.label.textStyle') || {});
              }
              if (this.deepQuery(queryTarget, 'itemStyle.emphasis.label.show')) {
                  shape.highlightStyle.textPosition = this.deepQuery(queryTarget, 'itemStyle.emphasis.label.position');
                  shape.highlightStyle.textColor = this.deepQuery(queryTarget, 'itemStyle.emphasis.label.textStyle.color');
                  shape.highlightStyle.textFont = this.getFont(this.deepQuery(queryTarget, 'itemStyle.emphasis.label.textStyle') || {});
              }
              ecData.pack(shape, serie, seriesIndex, treeNode.data, 0, treeNode.id);
              this.shapeList.push(shape);
          },
          _buildLink: function (parentNode, serie) {
              var lineStyle = serie.itemStyle.normal.lineStyle;
              if (lineStyle.type === 'broken') {
                  this._buildBrokenLine(parentNode, lineStyle, serie);
                  return;
              }
              for (var i = 0; i < parentNode.children.length; i++) {
                  var xStart = parentNode.layout.position[0];
                  var yStart = parentNode.layout.position[1];
                  var xEnd = parentNode.children[i].layout.position[0];
                  var yEnd = parentNode.children[i].layout.position[1];
                  switch (lineStyle.type) {
                  case 'curve':
                      this._buildBezierCurve(parentNode, parentNode.children[i], lineStyle, serie);
                      break;
                  case 'broken':
                      break;
                  default:
                      var shape = this._getLine(xStart, yStart, xEnd, yEnd, lineStyle);
                      this.shapeList.push(shape);
                  }
              }
          },
          _buildBrokenLine: function (parentNode, lineStyle, serie) {
              var solidLineStyle = zrUtil.clone(lineStyle);
              solidLineStyle.type = 'solid';
              var shapes = [];
              var xStart = parentNode.layout.position[0];
              var yStart = parentNode.layout.position[1];
              var orient = serie.orient;
              var yEnd = parentNode.children[0].layout.position[1];
              var xMiddle = xStart;
              var yMiddle = yStart + (yEnd - yStart) * (1 - GOLDEN_SECTION);
              var xMiddleStart = parentNode.children[0].layout.position[0];
              var yMiddleStart = yMiddle;
              var xMiddleEnd = parentNode.children[parentNode.children.length - 1].layout.position[0];
              var yMiddleEnd = yMiddle;
              if (orient === 'horizontal') {
                  var xEnd = parentNode.children[0].layout.position[0];
                  xMiddle = xStart + (xEnd - xStart) * (1 - GOLDEN_SECTION);
                  yMiddle = yStart;
                  xMiddleStart = xMiddle;
                  yMiddleStart = parentNode.children[0].layout.position[1];
                  xMiddleEnd = xMiddle;
                  yMiddleEnd = parentNode.children[parentNode.children.length - 1].layout.position[1];
              }
              shapes.push(this._getLine(xStart, yStart, xMiddle, yMiddle, solidLineStyle));
              shapes.push(this._getLine(xMiddleStart, yMiddleStart, xMiddleEnd, yMiddleEnd, solidLineStyle));
              for (var i = 0; i < parentNode.children.length; i++) {
                  xEnd = parentNode.children[i].layout.position[0];
                  yEnd = parentNode.children[i].layout.position[1];
                  if (orient === 'horizontal') {
                      yMiddleStart = yEnd;
                  } else {
                      xMiddleStart = xEnd;
                  }
                  shapes.push(this._getLine(xMiddleStart, yMiddleStart, xEnd, yEnd, solidLineStyle));
              }
              this.shapeList = this.shapeList.concat(shapes);
          },
          _getLine: function (xStart, yStart, xEnd, yEnd, lineStyle) {
              if (xStart === xEnd) {
                  xStart = xEnd = this.subPixelOptimize(xStart, lineStyle.width);
              }
              if (yStart === yEnd) {
                  yStart = yEnd = this.subPixelOptimize(yStart, lineStyle.width);
              }
              return new LineShape({
                  zlevel: this.getZlevelBase(),
                  hoverable: false,
                  style: zrUtil.merge({
                      xStart: xStart,
                      yStart: yStart,
                      xEnd: xEnd,
                      yEnd: yEnd,
                      lineType: lineStyle.type,
                      strokeColor: lineStyle.color,
                      lineWidth: lineStyle.width
                  }, lineStyle, true)
              });
          },
          _buildBezierCurve: function (parentNode, treeNode, lineStyle, serie) {
              var offsetRatio = GOLDEN_SECTION;
              var orient = serie.orient;
              var xStart = parentNode.layout.position[0];
              var yStart = parentNode.layout.position[1];
              var xEnd = treeNode.layout.position[0];
              var yEnd = treeNode.layout.position[1];
              var cpX1 = xStart;
              var cpY1 = (yEnd - yStart) * offsetRatio + yStart;
              var cpX2 = xEnd;
              var cpY2 = (yEnd - yStart) * (1 - offsetRatio) + yStart;
              if (orient === 'horizontal') {
                  cpX1 = (xEnd - xStart) * offsetRatio + xStart;
                  cpY1 = yStart;
                  cpX2 = (xEnd - xStart) * (1 - offsetRatio) + xStart;
                  cpY2 = yEnd;
              } else if (orient === 'radial') {
                  if (parentNode.id === this.tree.root.id) {
                      cpX1 = (xEnd - xStart) * offsetRatio + xStart;
                      cpY1 = (yEnd - yStart) * offsetRatio + yStart;
                      cpX2 = (xEnd - xStart) * (1 - offsetRatio) + xStart;
                      cpY2 = (yEnd - yStart) * (1 - offsetRatio) + yStart;
                  } else {
                      var xStartOrigin = parentNode.layout.originPosition[0];
                      var yStartOrigin = parentNode.layout.originPosition[1];
                      var xEndOrigin = treeNode.layout.originPosition[0];
                      var yEndOrigin = treeNode.layout.originPosition[1];
                      var rootX = this.tree.root.layout.position[0];
                      var rootY = this.tree.root.layout.position[1];
                      cpX1 = xStartOrigin;
                      cpY1 = (yEndOrigin - yStartOrigin) * offsetRatio + yStartOrigin;
                      cpX2 = xEndOrigin;
                      cpY2 = (yEndOrigin - yStartOrigin) * (1 - offsetRatio) + yStartOrigin;
                      var rad = (cpX1 - this.minX) / this.width * Math.PI * 2;
                      cpX1 = cpY1 * Math.cos(rad) + rootX;
                      cpY1 = cpY1 * Math.sin(rad) + rootY;
                      rad = (cpX2 - this.minX) / this.width * Math.PI * 2;
                      cpX2 = cpY2 * Math.cos(rad) + rootX;
                      cpY2 = cpY2 * Math.sin(rad) + rootY;
                  }
              }
              var shape = new BezierCurveShape({
                  zlevel: this.getZlevelBase(),
                  hoverable: false,
                  style: zrUtil.merge({
                      xStart: xStart,
                      yStart: yStart,
                      cpX1: cpX1,
                      cpY1: cpY1,
                      cpX2: cpX2,
                      cpY2: cpY2,
                      xEnd: xEnd,
                      yEnd: yEnd,
                      strokeColor: lineStyle.color,
                      lineWidth: lineStyle.width
                  }, lineStyle, true)
              });
              this.shapeList.push(shape);
          },
          _setTreeShape: function (serie) {
              var treeLayout = new TreeLayout({
                  nodePadding: serie.nodePadding,
                  layerPadding: serie.layerPadding
              });
              this.tree.traverse(function (treeNode) {
                  var queryTarget = [
                      treeNode.data,
                      serie
                  ];
                  var symbolSize = this.deepQuery(queryTarget, 'symbolSize');
                  if (typeof symbolSize === 'number') {
                      symbolSize = [
                          symbolSize,
                          symbolSize
                      ];
                  }
                  treeNode.layout = {
                      width: symbolSize[0],
                      height: symbolSize[1]
                  };
              }, this);
              treeLayout.run(this.tree);
              var orient = serie.orient;
              var rootX = serie.rootLocation.x;
              var rootY = serie.rootLocation.y;
              var zrWidth = this.zr.getWidth();
              var zrHeight = this.zr.getHeight();
              if (rootX === 'center') {
                  rootX = zrWidth * 0.5;
              } else {
                  rootX = this.parsePercent(rootX, zrWidth);
              }
              if (rootY === 'center') {
                  rootY = zrHeight * 0.5;
              } else {
                  rootY = this.parsePercent(rootY, zrHeight);
              }
              rootY = this.parsePercent(rootY, zrHeight);
              if (orient === 'horizontal') {
                  rootX = isNaN(rootX) ? 10 : rootX;
                  rootY = isNaN(rootY) ? zrHeight * 0.5 : rootY;
              }
              if (orient === 'radial') {
                  rootX = isNaN(rootX) ? zrWidth * 0.5 : rootX;
                  rootY = isNaN(rootY) ? zrHeight * 0.5 : rootY;
              } else {
                  rootX = isNaN(rootX) ? zrWidth * 0.5 : rootX;
                  rootY = isNaN(rootY) ? 10 : rootY;
              }
              var originRootX = this.tree.root.layout.position[0];
              if (orient === 'radial') {
                  var minX = Infinity;
                  var maxX = 0;
                  var maxWidth = 0;
                  this.tree.traverse(function (treeNode) {
                      maxX = Math.max(maxX, treeNode.layout.position[0]);
                      minX = Math.min(minX, treeNode.layout.position[0]);
                      maxWidth = Math.max(maxWidth, treeNode.layout.width);
                  });
                  this.width = maxX - minX + 2 * maxWidth;
                  this.minX = minX;
              }
              this.tree.traverse(function (treeNode) {
                  var x = treeNode.layout.position[0] - originRootX + rootX;
                  var y = treeNode.layout.position[1] + rootY;
                  if (orient === 'horizontal') {
                      y = treeNode.layout.position[0] - originRootX + rootY;
                      x = treeNode.layout.position[1] + rootX;
                  }
                  if (orient === 'radial') {
                      x = treeNode.layout.position[0];
                      y = treeNode.layout.position[1];
                      treeNode.layout.originPosition = [
                          x,
                          y
                      ];
                      var r = y;
                      var angle = (x - minX) / this.width * Math.PI * 2;
                      x = r * Math.cos(angle) + rootX;
                      y = r * Math.sin(angle) + rootY;
                      treeNode.layout.angle = angle;
                  }
                  treeNode.layout.position[0] = x;
                  treeNode.layout.position[1] = y;
              }, this);
          },
          refresh: function (newOption) {
              this.clear();
              if (newOption) {
                  this.option = newOption;
                  this.series = this.option.series;
              }
              var series = this.series;
              var legend = this.component.legend;
              for (var i = 0; i < series.length; i++) {
                  if (series[i].type === ecConfig.CHART_TYPE_TREE) {
                      series[i] = this.reformOption(series[i]);
                      var seriesName = series[i].name || '';
                      this.selectedMap[seriesName] = legend ? legend.isSelected(seriesName) : true;
                      if (!this.selectedMap[seriesName]) {
                          continue;
                      }
                      this._buildSeries(series[i], i);
                  }
              }
          },
          _buildSeries: function (series, seriesIndex) {
              this._buildShape(series, seriesIndex);
          }
      };
      zrUtil.inherits(Tree, ChartBase);
      require('../chart').define('tree', Tree);
      return Tree;
  });define('echarts/layout/Tree', [
      'require',
      'zrender/tool/vector'
  ], function (require) {
      var vec2 = require('zrender/tool/vector');
      function TreeLayout(opts) {
          opts = opts || {};
          this.nodePadding = opts.nodePadding || 30;
          this.layerPadding = opts.layerPadding || 100;
          this._layerOffsets = [];
          this._layers = [];
      }
      TreeLayout.prototype.run = function (tree) {
          this._layerOffsets.length = 0;
          for (var i = 0; i < tree.root.height + 1; i++) {
              this._layerOffsets[i] = 0;
              this._layers[i] = [];
          }
          this._updateNodeXPosition(tree.root);
          var root = tree.root;
          this._updateNodeYPosition(root, 0, root.layout.height);
      };
      TreeLayout.prototype._updateNodeXPosition = function (node) {
          var minX = Infinity;
          var maxX = -Infinity;
          node.layout.position = node.layout.position || vec2.create();
          for (var i = 0; i < node.children.length; i++) {
              var child = node.children[i];
              this._updateNodeXPosition(child);
              var x = child.layout.position[0];
              if (x < minX) {
                  minX = x;
              }
              if (x > maxX) {
                  maxX = x;
              }
          }
          if (node.children.length > 0) {
              node.layout.position[0] = (minX + maxX) / 2;
          } else {
              node.layout.position[0] = 0;
          }
          var off = this._layerOffsets[node.depth] || 0;
          if (off > node.layout.position[0]) {
              var shift = off - node.layout.position[0];
              this._shiftSubtree(node, shift);
              for (var i = node.depth + 1; i < node.height + node.depth; i++) {
                  this._layerOffsets[i] += shift;
              }
          }
          this._layerOffsets[node.depth] = node.layout.position[0] + node.layout.width + this.nodePadding;
          this._layers[node.depth].push(node);
      };
      TreeLayout.prototype._shiftSubtree = function (root, offset) {
          root.layout.position[0] += offset;
          for (var i = 0; i < root.children.length; i++) {
              this._shiftSubtree(root.children[i], offset);
          }
      };
      TreeLayout.prototype._updateNodeYPosition = function (node, y, prevLayerHeight) {
          node.layout.position[1] = y;
          var layerHeight = 0;
          for (var i = 0; i < node.children.length; i++) {
              layerHeight = Math.max(node.children[i].layout.height, layerHeight);
          }
          var layerPadding = this.layerPadding;
          if (typeof layerPadding === 'function') {
              layerPadding = layerPadding(node.depth);
          }
          for (var i = 0; i < node.children.length; i++) {
              this._updateNodeYPosition(node.children[i], y + layerPadding + prevLayerHeight, layerHeight);
          }
      };
      return TreeLayout;
  });define('echarts/data/Tree', [
      'require',
      'zrender/tool/util'
  ], function (require) {
      var zrUtil = require('zrender/tool/util');
      function TreeNode(id, data) {
          this.id = id;
          this.depth = 0;
          this.height = 0;
          this.children = [];
          this.parent = null;
          this.data = data || null;
      }
      TreeNode.prototype.add = function (child) {
          var children = this.children;
          if (child.parent === this) {
              return;
          }
          children.push(child);
          child.parent = this;
      };
      TreeNode.prototype.remove = function (child) {
          var children = this.children;
          var idx = zrUtil.indexOf(children, child);
          if (idx >= 0) {
              children.splice(idx, 1);
              child.parent = null;
          }
      };
      TreeNode.prototype.traverse = function (cb, context) {
          cb.call(context, this);
          for (var i = 0; i < this.children.length; i++) {
              this.children[i].traverse(cb, context);
          }
      };
      TreeNode.prototype.updateDepthAndHeight = function (depth) {
          var height = 0;
          this.depth = depth;
          for (var i = 0; i < this.children.length; i++) {
              var child = this.children[i];
              child.updateDepthAndHeight(depth + 1);
              if (child.height > height) {
                  height = child.height;
              }
          }
          this.height = height + 1;
      };
      TreeNode.prototype.getNodeById = function (id) {
          if (this.id === id) {
              return this;
          }
          for (var i = 0; i < this.children.length; i++) {
              var res = this.children[i].getNodeById(id);
              if (res) {
                  return res;
              }
          }
      };
      function Tree(id) {
          this.root = new TreeNode(id);
      }
      Tree.prototype.traverse = function (cb, context) {
          this.root.traverse(cb, context);
      };
      Tree.prototype.getSubTree = function (id) {
          var root = this.getNodeById(id);
          if (root) {
              var tree = new Tree(root.id);
              tree.root = root;
              return tree;
          }
      };
      Tree.prototype.getNodeById = function (id) {
          return this.root.getNodeById(id);
      };
      Tree.fromOptionData = function (id, data) {
          var tree = new Tree(id);
          var rootNode = tree.root;
          rootNode.data = {
              name: id,
              children: data
          };
          function buildHierarchy(dataNode, parentNode) {
              var node = new TreeNode(dataNode.name, dataNode);
              parentNode.add(node);
              var children = dataNode.children;
              if (children) {
                  for (var i = 0; i < children.length; i++) {
                      buildHierarchy(children[i], node);
                  }
              }
          }
          for (var i = 0; i < data.length; i++) {
              buildHierarchy(data[i], rootNode);
          }
          tree.root.updateDepthAndHeight(0);
          return tree;
      };
      Tree.fromGraph = function (graph) {
          function buildHierarchy(root) {
              var graphNode = graph.getNodeById(root.id);
              for (var i = 0; i < graphNode.outEdges.length; i++) {
                  var edge = graphNode.outEdges[i];
                  var childTreeNode = treeNodesMap[edge.node2.id];
                  root.children.push(childTreeNode);
                  buildHierarchy(childTreeNode);
              }
          }
          var treeMap = {};
          var treeNodesMap = {};
          for (var i = 0; i < graph.nodes.length; i++) {
              var node = graph.nodes[i];
              var treeNode;
              if (node.inDegree() === 0) {
                  treeMap[node.id] = new Tree(node.id);
                  treeNode = treeMap[node.id].root;
              } else {
                  treeNode = new TreeNode(node.id);
              }
              treeNode.data = node.data;
              treeNodesMap[node.id] = treeNode;
          }
          var treeList = [];
          for (var id in treeMap) {
              buildHierarchy(treeMap[id].root);
              treeMap[id].root.updateDepthAndHeight(0);
              treeList.push(treeMap[id]);
          }
          return treeList;
      };
      return Tree;
  });