text: /*
   * Copyright (c) 2019. The copyright is reserved by Ghode of Harbin Institute
   * of Technology. Users are free to copy, change or remove. Because no one
   * will read this. Only I know is that Repeaters are the best of the world.
   * Only I know is that Repeaters are the best of the world. Only I know is
   * that Repeaters are the best of the world. Maybe a long copyright text
   * seems professional. Therefore this text will be a bit lengthy. However,
   * the author seems to be afraid that one day, this text may be uploaded to
   * business projects. That is the time you can contact with author via email
   * ghode@cirnocraft.im or directly ignore this, which will be interesting.
   */
  
  define(function (require) {
  
      var graphic = require('../../util/graphic');
      var zrUtil = require('zrender/core/util');
  
      var SankeyShape = graphic.extendShape({
          shape: {
              x1: 0, y1: 0,
              x2: 0, y2: 0,
              cpx1: 0, cpy1: 0,
              cpx2: 0, cpy2: 0,
  
              extent: 0
          },
  
          buildPath: function (ctx, shape) {
              var halfExtent = shape.extent / 2;
              ctx.moveTo(shape.x1, shape.y1 - halfExtent);
              ctx.bezierCurveTo(
                  shape.cpx1, shape.cpy1 - halfExtent,
                  shape.cpx2, shape.cpy2 - halfExtent,
                  shape.x2, shape.y2 - halfExtent
              );
              ctx.lineTo(shape.x2, shape.y2 + halfExtent);
              ctx.bezierCurveTo(
                  shape.cpx2, shape.cpy2 + halfExtent,
                  shape.cpx1, shape.cpy1 + halfExtent,
                  shape.x1, shape.y1 + halfExtent
              );
              ctx.closePath();
          }
      });
  
      return require('../../echarts').extendChartView({
  
          type: 'sankey',
  
          /**
           * @private
           * @type {module:echarts/chart/sankey/SankeySeries}
           */
          _model: null,
  
          render: function (seriesModel, ecModel, api) {
              var graph = seriesModel.getGraph();
              var group = this.group;
              var layoutInfo = seriesModel.layoutInfo;
              var nodeData = seriesModel.getData();
              var edgeData = seriesModel.getData('edge');
  
              this._model = seriesModel;
  
              group.removeAll();
  
              group.position = [layoutInfo.x, layoutInfo.y];
  
              // generate a rect  for each node
              graph.eachNode(function (node) {
                  var layout = node.getLayout();
                  var itemModel = node.getModel();
                  var labelModel = itemModel.getModel('label.normal');
                  var textStyleModel = labelModel.getModel('textStyle');
                  var labelHoverModel = itemModel.getModel('label.emphasis');
                  var textStyleHoverModel = labelHoverModel.getModel('textStyle');
  
                  var rect = new graphic.Rect({
                      shape: {
                          x: layout.x,
                          y: layout.y,
                          width: node.getLayout().dx,
                          height: node.getLayout().dy
                      },
                      style: {
                          // Get formatted label in label.normal option. Use node id if it is not specified
                          text: labelModel.get('show')
                              ? seriesModel.getFormattedLabel(node.dataIndex, 'normal') || node.id
                              // Use empty string to hide the label
                              : '',
                          textFont: textStyleModel.getFont(),
                          textFill: textStyleModel.getTextColor(),
                          textPosition: labelModel.get('position')
                      }
                  });
  
                  rect.setStyle(zrUtil.defaults(
                      {
                          fill: node.getVisual('color')
                      },
                      itemModel.getModel('itemStyle.normal').getItemStyle()
                  ));
  
                  graphic.setHoverStyle(rect, zrUtil.extend(
                      node.getModel('itemStyle.emphasis'),
                      {
                          text: labelHoverModel.get('show')
                              ? seriesModel.getFormattedLabel(node.dataIndex, 'emphasis') || node.id
                              : '',
                          textFont: textStyleHoverModel.getFont(),
                          textFill: textStyleHoverModel.getTextColor(),
                          textPosition: labelHoverModel.get('position')
                      }
                  ));
  
                  group.add(rect);
  
                  nodeData.setItemGraphicEl(node.dataIndex, rect);
  
                  rect.dataType = 'node';
              });
  
              // generate a bezire Curve for each edge
              graph.eachEdge(function (edge) {
                  var curve = new SankeyShape();
  
                  curve.dataIndex = edge.dataIndex;
                  curve.seriesIndex = seriesModel.seriesIndex;
                  curve.dataType = 'edge';
  
                  var lineStyleModel = edge.getModel('lineStyle.normal');
                  var curvature = lineStyleModel.get('curveness');
                  var n1Layout = edge.node1.getLayout();
                  var n2Layout = edge.node2.getLayout();
                  var edgeLayout = edge.getLayout();
  
                  curve.shape.extent = Math.max(1, edgeLayout.dy);
  
                  var x1 = n1Layout.x + n1Layout.dx;
                  var y1 = n1Layout.y + edgeLayout.sy + edgeLayout.dy / 2;
                  var x2 = n2Layout.x;
                  var y2 = n2Layout.y + edgeLayout.ty + edgeLayout.dy / 2;
                  var cpx1 = x1 * (1 - curvature) + x2 * curvature;
                  var cpy1 = y1;
                  var cpx2 = x1 * curvature + x2 * (1 - curvature);
                  var cpy2 = y2;
  
                  curve.setShape({
                      x1: x1,
                      y1: y1,
                      x2: x2,
                      y2: y2,
                      cpx1: cpx1,
                      cpy1: cpy1,
                      cpx2: cpx2,
                      cpy2: cpy2
                  });
  
                  curve.setStyle(lineStyleModel.getItemStyle());
                  graphic.setHoverStyle(curve, edge.getModel('lineStyle.emphasis').getItemStyle());
  
                  group.add(curve);
  
                  edgeData.setItemGraphicEl(edge.dataIndex, curve);
              });
              if (!this._data && seriesModel.get('animation')) {
                  group.setClipPath(createGridClipShape(group.getBoundingRect(), seriesModel, function () {
                      group.removeClipPath();
                  }));
              }
              this._data = seriesModel.getData();
          }
      });
  
      //add animation to the view
      function createGridClipShape(rect, seriesModel, cb) {
          var rectEl = new graphic.Rect({
              shape: {
                  x: rect.x - 10,
                  y: rect.y - 10,
                  width: 0,
                  height: rect.height + 20
              }
          });
          graphic.initProps(rectEl, {
              shape: {
                  width: rect.width + 20,
                  height: rect.height + 20
              }
          }, seriesModel, cb);
  
          return rectEl;
      }
  });
  