function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }

var Util = require('../../util');

var _require = require('@antv/component/lib'),
    Legend = _require.Legend;

var Tail = require('../../component/legend/tail');

var Shape = require('../../geom/shape/shape');

var bboxOfBackPlot = require('../util/bbox-of-back-plot');

var plotRange2BBox = require('../util/plot-range2bbox');

var Global = require('../../global');

var FIELD_ORIGIN = '_origin';
var MARKER_SIZE = 4.5;
var requireAnimationFrameFn = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
var STROKE_MARKERS = ['cross', 'tick', 'plus', 'hyphen', 'line', 'hollowCircle', 'hollowSquare', 'hollowDiamond', 'hollowTriangle', 'hollowTriangleDown', 'hollowHexagon', 'hollowBowtie'];

function _snapEqual(v1, v2, scale) {
  var isEqual;

  if (Util.isNil(scale)) {
    return false;
  }

  v1 = scale.translate(v1);
  v2 = scale.translate(v2);

  if (scale.isCategory) {
    isEqual = v1 === v2;
  } else {
    isEqual = Math.abs(v1 - v2) <= 1;
  }

  return isEqual;
}

function findGeom(geoms, value) {
  var rst;
  Util.each(geoms, function (geom) {
    if (geom.get('visible')) {
      var yScale = geom.getYScale();

      if (yScale.field === value) {
        rst = geom;
        return;
      }
    }
  });
  return rst;
}

var LegendController = /*#__PURE__*/function () {
  function LegendController(cfg) {
    var self = this;
    self.options = {};
    Util.mix(self, cfg);
    self.clear();
    var chart = self.chart;
    self.container = chart.get('frontPlot');
    self.plotRange = chart.get('plotRange');
  }

  var _proto = LegendController.prototype;

  _proto.clear = function clear() {
    var legends = this.legends;
    this.backRange = null;
    Util.each(legends, function (legendItems) {
      Util.each(legendItems, function (legend) {
        legend.destroy();
      });
    });
    this.legends = {};
  } // 获取坐标轴等背景元素占的范围，防止遮挡坐标轴
  ;

  _proto.getBackRange = function getBackRange() {
    var backRange = this.backRange;

    if (!backRange) {
      var backPlot = this.chart.get('backPlot');
      backRange = bboxOfBackPlot(backPlot, plotRange2BBox(this.chart.get('plotRange')));
      var plotRange = this.plotRange;

      if (backRange.maxX - backRange.minX < plotRange.br.x - plotRange.tl.x && backRange.maxY - backRange.minY < plotRange.br.y - plotRange.tl.y) {
        // 如果背景小于则直接使用 plotRange
        backRange = {
          minX: plotRange.tl.x,
          minY: plotRange.tl.y,
          maxX: plotRange.br.x,
          maxY: plotRange.br.y
        };
      }

      this.backRange = backRange;
    }

    return backRange;
  };

  _proto._isFieldInView = function _isFieldInView(field, value, view) {
    var flag = false;
    var scales = view.get('scales');
    var fieldScale = scales[field];

    if (fieldScale && fieldScale.values) {
      flag = Util.inArray(fieldScale.values, value);
    }

    return flag;
  };

  _proto._bindClickEvent = function _bindClickEvent(legend, scale, filterVals) {
    var self = this;
    var chart = self.chart;
    var views = chart.get('views');
    var field = scale.field;
    var options = self.options;
    legend.on('itemclick', function (ev) {
      if (options.onClick && options.defaultClickHandlerEnabled !== true) {
        options.onClick(ev);
      } else {
        // if 'defaultClickHandlerEnabled' is true the default click behavior would be worked.
        var item = ev.item;
        var checked = ev.checked;
        var isSingleSelected = legend.get('selectedMode') === 'single'; // 图例的选中模式

        var clickedValue = item.dataValue; // import: 需要取该图例项原始的数值

        if (checked) {
          Util.Array.remove(filterVals, clickedValue);

          if (self._isFieldInView(field, clickedValue, chart)) {
            chart.filter(field, function (field) {
              return isSingleSelected ? field === clickedValue : !Util.inArray(filterVals, field);
            });
          }

          Util.each(views, function (view) {
            if (self._isFieldInView(field, clickedValue, view)) {
              view.filter(field, function (field) {
                return isSingleSelected ? field === clickedValue : !Util.inArray(filterVals, field);
              });
            }
          });
        } else if (!isSingleSelected) {
          filterVals.push(clickedValue);

          if (self._isFieldInView(field, clickedValue, chart)) {
            chart.filter(field, function (field) {
              return !Util.inArray(filterVals, field);
            });
          }

          Util.each(views, function (view) {
            if (self._isFieldInView(field, clickedValue, view)) {
              view.filter(field, function (field) {
                return !Util.inArray(filterVals, field);
              });
            }
          });
        }

        if (options.onClick) {
          options.onClick(ev);
        }

        chart.set('keepLegend', true); // 图例不重新渲染

        chart.set('keepPadding', true); // 边框不重新计算

        chart.repaint();
        chart.set('keepPadding', false);
        chart.set('keepLegend', false);
      }
    });
  };

  _proto._bindClickEventForMix = function _bindClickEventForMix(legend) {
    var self = this;
    var chart = self.chart;
    var geoms = chart.getAllGeoms();
    legend.on('itemclick', function (ev) {
      var itemField = ev.item.field;
      var checked = ev.checked;

      if (checked) {
        Util.each(geoms, function (geom) {
          var field = geom.getYScale().field;

          if (field === itemField) {
            geom.show();
          }
        });
      } else {
        Util.each(geoms, function (geom) {
          var field = geom.getYScale().field;

          if (field === itemField) {
            geom.hide();
          }
        });
      }
    });
  };

  _proto._filterLabels = function _filterLabels(shape, geom, visible) {
    if (shape.get('gLabel')) {
      shape.get('gLabel').set('visible', visible);
    } else {
      var labelCfg = geom.get('labelCfg');

      if (labelCfg && labelCfg.fields && labelCfg.fields.length > 0) {
        var xScale = geom.getXScale();
        var yScale = geom.getYScale();
        var xField = xScale.field;
        var yField = yScale.field;

        var shapeData = shape.get('origin')._origin;

        var labelContainer = geom.get('labelContainer');
        var labels = labelContainer.get('labelsGroup').get('children');
        Util.each(labels, function (label) {
          var labelData = label.get('origin') || [];

          if (labelData[xField] === shapeData[xField] && labelData[yField] === shapeData[yField]) {
            label.set('visible', visible);
            shape.set('gLabel', label);
          }
        });
      }
    }
  };

  _proto._bindFilterEvent = function _bindFilterEvent(legend, scale) {
    var self = this;
    var chart = this.chart;
    var field = scale.field;
    legend.on('itemfilter', function (ev) {
      var range = ev.range;
      chart.filterShape(function (obj, shape, geom) {
        // @2018-12-21 by blue.lb 由于数值0直接被类型转换为false，这里需要做更精确一点的判断
        if (!Util.isNil(obj[field])) {
          var filtered = obj[field] >= range[0] && obj[field] <= range[1]; // shape 带 label，则还需要隐藏 label

          self._filterLabels(shape, geom, filtered);

          return filtered;
        }

        return true;
      });
      var geoms = chart.getAllGeoms() || [];

      var _loop = function _loop(i) {
        var geom = geoms[i];

        if (geom.get('type') === 'heatmap') {
          requireAnimationFrameFn(function () {
            geom.drawWithRange(range);
          });
        }
      };

      for (var i = 0; i < geoms.length; i++) {
        _loop(i);
      }
    });
  };

  _proto._getShapeData = function _getShapeData(shape) {
    var originData = shape.get('origin');

    if (Util.isArray(originData)) {
      originData = originData[0];
    }

    return originData[FIELD_ORIGIN];
  };

  _proto._bindHoverEvent = function _bindHoverEvent(legend, field) {
    var self = this;
    var chart = self.chart;
    var geoms = chart.getAllGeoms();
    var options = self.options;
    var canvas = chart.get('canvas');
    legend.on('itemhover', function (ev) {
      var value = ev.item.value;
      var pre = self.pre;

      if (!pre) {
        Util.each(geoms, function (geom) {
          var shapeContainer = geom.get('shapeContainer');
          var shapes = geom.getShapes();
          var activeShapes = [];

          if (field) {
            var scale = geom.get('scales')[field];
            Util.each(shapes, function (shape) {
              var origin = self._getShapeData(shape);

              if (origin && _snapEqual(origin[field], value, scale)) {
                activeShapes.push(shape);
              }
            });
          } else if (geom.getYScale().field === value) {
            activeShapes = shapes;
          }

          if (!Util.isEmpty(activeShapes)) {
            ev.shapes = activeShapes;
            ev.geom = geom;

            if (options.onHover) {
              options.onHover(ev);
              shapeContainer.sort();
              canvas.draw();
            } else {
              geom.setShapesActived(activeShapes);
            }
          }
        });
        self.pre = value;
      } else if (pre === value) {
        return;
      }
    });
    legend.on('itemunhover', function (ev) {
      self.pre = null;

      if (options.onUnhover) {
        options.onUnhover(ev);
      }

      Util.each(geoms, function (geom) {
        if (geom.get('activeShapes')) {
          geom.clearActivedShapes();
          canvas.draw();
        }
      });
    });
  };

  _proto._isFiltered = function _isFiltered(scale, filterVals, scaleValue) {
    if (!scale.isCategory) {
      return true;
    }

    var rst = true;
    scaleValue = scale.invert(scaleValue);
    Util.each(filterVals, function (val) {
      if (scale.getText(val) === scale.getText(scaleValue)) {
        rst = false;
        return false;
      }
    });
    return rst;
  };

  _proto._alignLegend = function _alignLegend(legend, pre, region, position) {
    var self = this;
    var viewTheme = self.viewTheme;
    var container = self.container;
    var canvas = container.get('canvas');
    var width = canvas.get('width');
    var height = canvas.get('height');
    var totalRegion = self.totalRegion;
    var plotRange = self.plotRange;
    var backRange = self.getBackRange(); // 背景占得范围

    var offsetX = legend.get('offset')[0] || 0;
    var offsetY = legend.get('offset')[1] || 0; // const offset = Util.isNil(legend.get('offset')) ? MARGIN : legend.get('offset');

    var legendHeight = legend.getHeight();
    var legendWidth = legend.getWidth();
    var borderMargin = viewTheme.legend.margin;
    var innerMargin = viewTheme.legend.legendMargin;
    var legendNum = self.legends[position].length;
    var posArray = position.split('-');
    var x = 0;
    var y = 0;
    var tempoRegion = legendNum > 1 ? totalRegion : region;

    if (posArray[0] === 'left' || posArray[0] === 'right') {
      height = plotRange.br.y;
      x = self._getXAlign(posArray[0], width, region, backRange, legendWidth, borderMargin);

      if (pre) {
        // @2018-10-19 by blue.lb 由于legend中并不存在y属性，这里需要先获取group再获取y值
        // @2019-03-21 by blue.lb 由于内部实现问题，usehtml部分的实例可以直接获取x、y的
        y = (pre.get('y') || pre.get('group').get('y')) + pre.getHeight() + innerMargin;
      } else {
        y = self._getYAlignVertical(posArray[1], height, tempoRegion, backRange, 0, borderMargin, canvas.get('height'));
      }
    } else if (posArray[0] === 'top' || posArray[0] === 'bottom') {
      y = self._getYAlignHorizontal(posArray[0], height, region, backRange, legendHeight, borderMargin);

      if (pre) {
        var preWidth = pre.getWidth(); // @2018-10-19 by blue.lb 由于legend中并不存在x属性，这里需要先获取group再获取x值
        // @2019-03-21 by blue.lb 由于内部实现问题，usehtml部分的实例可以直接获取x、y的

        x = (pre.get('x') || pre.get('group').get('x')) + preWidth + innerMargin;
      } else {
        x = self._getXAlign(posArray[1], width, tempoRegion, backRange, 0, borderMargin);
        if (posArray[1] === 'right') x = plotRange.br.x - tempoRegion.totalWidth;
      }
    }

    legend.move(x + offsetX, y + offsetY);
  };

  _proto._getXAlign = function _getXAlign(pos, width, region, backRange, legendWidth, borderMargin) {
    var leftPos = backRange.minX - legendWidth - borderMargin[3] < 0 ? 0 : backRange.minX - legendWidth - borderMargin[3];
    var x = pos === 'left' ? leftPos : backRange.maxX + borderMargin[1];

    if (pos === 'center') {
      x = (width - region.totalWidth) / 2;
    }

    return x;
  };

  _proto._getYAlignHorizontal = function _getYAlignHorizontal(pos, height, region, backRange, legendHeight, borderMargin) {
    var y = pos === 'top' ? backRange.minY - legendHeight - borderMargin[0] : backRange.maxY + borderMargin[2];
    return y;
  };

  _proto._getYAlignVertical = function _getYAlignVertical(pos, height, region, backRange, legendHeight, borderMargin, canvasHeight) {
    var y = pos === 'top' ? backRange.minY - legendHeight - borderMargin[0] : height - region.totalHeight;

    if (pos === 'center') {
      y = (canvasHeight - region.totalHeight) / 2;
    }

    return y;
  };

  _proto._getSubRegion = function _getSubRegion(legends) {
    var maxWidth = 0;
    var maxHeight = 0;
    var totalWidth = 0;
    var totalHeight = 0;
    Util.each(legends, function (legend) {
      var width = legend.getWidth();
      var height = legend.getHeight();

      if (maxWidth < width) {
        maxWidth = width;
      }

      totalWidth += width;

      if (maxHeight < height) {
        maxHeight = height;
      }

      totalHeight += height;
    });
    return {
      maxWidth: maxWidth,
      totalWidth: totalWidth,
      maxHeight: maxHeight,
      totalHeight: totalHeight
    };
  };

  _proto._getRegion = function _getRegion() {
    var self = this;
    var viewTheme = self.viewTheme;
    var legends = self.legends;
    var innerMargin = viewTheme.legend.legendMargin;
    var subs = [];
    var totalWidth = 0;
    var totalHeight = 0;
    Util.each(legends, function (legendItems) {
      var subRegion = self._getSubRegion(legendItems);

      subs.push(subRegion);
      totalWidth += subRegion.totalWidth + innerMargin;
      totalHeight += subRegion.totalHeight + innerMargin;
    });
    return {
      totalWidth: totalWidth,
      totalHeight: totalHeight,
      subs: subs
    };
  };

  _proto._addCategoryLegend = function _addCategoryLegend(scale, attr, geom, filterVals, position) {
    var self = this;
    var field = scale.field;
    var legendOptions = self.options;
    var fieldOption = legendOptions[field];

    if (fieldOption) {
      legendOptions = fieldOption;
    }

    var legends = self.legends;
    legends[position] = legends[position] || [];
    var container = self.container;
    var items = [];
    var ticks = scale.getTicks();
    var isByAttr = true;
    var shapeType = geom.get('shapeType') || 'point';
    var shape = geom.getDefaultValue('shape') || 'circle';

    if (legendOptions[field] && legendOptions[field].marker) {
      // 用户为 field 对应的图例定义了 marker
      shape = legendOptions[field].marker;
      shapeType = 'point';
      isByAttr = false;
    } else if (legendOptions.marker) {
      shape = legendOptions.marker;
      shapeType = 'point';
      isByAttr = false;
    }

    var chart = self.chart;
    var viewTheme = self.viewTheme;
    var canvas = chart.get('canvas');
    var plotRange = self.plotRange;
    var posArray = position.split('-');
    var maxLength = posArray[0] === 'right' || posArray[0] === 'left' ? plotRange.bl.y - plotRange.tr.y : canvas.get('width');
    Util.each(ticks, function (tick) {
      var text = tick.text;
      var name = text;
      var scaleValue = tick.value;
      var value = scale.invert(scaleValue);
      var cfg = {
        isInCircle: geom.isInCircle()
      };
      var checked = filterVals ? self._isFiltered(scale, filterVals, scaleValue) : true;
      var colorAttr = geom.getAttr('color');
      var shapeAttr = geom.getAttr('shape');

      if (colorAttr) {
        // 存在颜色映射
        if (colorAttr.callback && colorAttr.callback.length > 1) {
          // 多参数映射，阻止程序报错
          var restArgs = Array(colorAttr.callback.length - 1).fill('');
          cfg.color = colorAttr.mapping.apply(colorAttr, [value].concat(restArgs)).join('') || viewTheme.defaultColor;
        } else {
          cfg.color = colorAttr.mapping(value).join('') || viewTheme.defaultColor;
        }
      }

      if (isByAttr && shapeAttr) {
        // 存在形状映射
        if (shapeAttr.callback && shapeAttr.callback.length > 1) {
          // 多参数映射，阻止程序报错
          var _restArgs = Array(shapeAttr.callback.length - 1).fill('');

          shape = shapeAttr.mapping.apply(shapeAttr, [value].concat(_restArgs)).join('');
        } else {
          shape = shapeAttr.mapping(value).join('');
        }
      }

      var shapeObject = Shape.getShapeFactory(shapeType);
      var marker = shapeObject.getMarkerCfg(shape, cfg);

      if (Global.legendMarkerRadius) {
        marker.radius = Global.legendMarkerRadius;
      }

      if (Util.isFunction(shape)) {
        marker.symbol = shape;
      }

      items.push({
        value: name,
        // 图例项显示文本的内容
        dataValue: value,
        // 图例项对应原始数据中的数值
        checked: checked,
        marker: marker
      });
    });
    var legendCfg = Util.deepMix({}, viewTheme.legend[posArray[0]], legendOptions[field] || legendOptions, {
      viewId: chart.get('_id'),
      maxLength: maxLength,
      items: items,
      container: container,
      position: [0, 0]
    });

    if (legendCfg.title) {
      Util.deepMix(legendCfg, {
        title: {
          text: scale.alias || scale.field
        }
      });
    }

    var legend;

    if (self._isTailLegend(legendOptions, geom)) {
      legendCfg.chart = self.chart;
      legendCfg.geom = geom;
      legend = new Tail(legendCfg);
    } else {
      if (legendOptions.useHtml) {
        var canvasEle = container.get('canvas').get('el');
        container = legendOptions.container;

        if (Util.isString(container) && /^\#/.test(container)) {
          // 如果传入 dom 节点的 id
          var id = container.replace('#', '');
          container = document.getElementById(id);
        }

        if (!container) {
          container = canvasEle.parentNode;
        }

        legendCfg.container = container;
        if (legendCfg.legendStyle === undefined) legendCfg.legendStyle = {};
        legendCfg.legendStyle.CONTAINER_CLASS = _extends({}, legendCfg.legendStyle.CONTAINER_CLASS, {
          position: 'absolute',
          overflow: 'auto',
          'z-index': canvasEle.style.zIndex === '' ? 1 : parseInt(canvasEle.style.zIndex, 10) + 1
        });

        if (legendOptions.flipPage) {
          legendCfg.legendStyle.CONTAINER_CLASS.height = posArray[0] === 'right' || posArray[0] === 'left' ? maxLength + 'px' : 'auto';
          legendCfg.legendStyle.CONTAINER_CLASS.width = !(posArray[0] === 'right' || posArray[0] === 'left') ? maxLength + 'px' : 'auto';
          legend = new Legend.CatPageHtml(legendCfg);
        } else {
          legend = new Legend.CatHtml(legendCfg);
        }
      } else {
        legend = new Legend.Category(legendCfg);
      }
    }

    self._bindClickEvent(legend, scale, filterVals);

    legends[position].push(legend);
    return legend;
  };

  _proto._bindChartMove = function _bindChartMove(scale) {
    var chart = this.chart;
    var legends = this.legends;
    chart.on('plotmove', function (ev) {
      var selected = false;

      if (ev.target) {
        var origin = ev.target.get('origin');

        if (origin) {
          var data = origin[FIELD_ORIGIN] || origin[0][FIELD_ORIGIN];
          var field = scale.field;

          if (data) {
            var value = data[field];
            Util.each(legends, function (legendItems) {
              Util.each(legendItems, function (legend) {
                selected = true;
                !legend.destroyed && legend.activate(value);
              });
            });
          }
        }
      }

      if (!selected) {
        Util.each(legends, function (legendItems) {
          Util.each(legendItems, function (legend) {
            !legend.destroyed && legend.deactivate();
          });
        });
      }
    });
  };

  _proto._addContinuousLegend = function _addContinuousLegend(scale, attr, position) {
    var self = this;
    var legends = self.legends;
    legends[position] = legends[position] || [];
    var container = self.container;
    var field = scale.field;
    var ticks = scale.getTicks();
    var items = [];
    var legend;
    var minValue;
    var maxValue;
    var viewTheme = self.viewTheme;
    Util.each(ticks, function (tick) {
      var scaleValue = tick.value;
      var invertValue = scale.invert(scaleValue);
      var attrValue = attr.mapping(invertValue).join('');
      items.push({
        value: tick.tickValue,
        // tick.text
        attrValue: attrValue,
        color: attrValue,
        scaleValue: scaleValue
      });

      if (scaleValue === 0) {
        minValue = true;
      }

      if (scaleValue === 1) {
        maxValue = true;
      }
    });

    if (!minValue) {
      items.push({
        value: scale.min,
        attrValue: attr.mapping(0).join(''),
        color: attr.mapping(0).join(''),
        scaleValue: 0
      });
    }

    if (!maxValue) {
      items.push({
        value: scale.max,
        attrValue: attr.mapping(1).join(''),
        color: attr.mapping(1).join(''),
        scaleValue: 1
      });
    }

    var options = self.options;
    var posArray = position.split('-');
    var defaultCfg = viewTheme.legend[posArray[0]];

    if (options && options.slidable === false || options[field] && options[field].slidable === false) {
      defaultCfg = Util.mix({}, defaultCfg, viewTheme.legend.gradient);
    }

    var legendCfg = Util.deepMix({}, defaultCfg, options[field] || options, {
      items: items,
      attr: attr,
      formatter: scale.formatter,
      container: container,
      position: [0, 0]
    });

    if (legendCfg.title) {
      Util.deepMix(legendCfg, {
        title: {
          text: scale.alias || scale.field
        }
      });
    }

    if (attr.type === 'color') {
      legend = new Legend.Color(legendCfg);
    } else if (attr.type === 'size') {
      if (options && options.sizeType === 'circle') legend = new Legend.CircleSize(legendCfg);else legend = new Legend.Size(legendCfg);
    } else {
      return;
    }

    self._bindFilterEvent(legend, scale);

    legends[position].push(legend);
    return legend;
  };

  _proto._isTailLegend = function _isTailLegend(opt, geom) {
    if (opt.hasOwnProperty('attachLast') && opt.attachLast) {
      var geomType = geom.get('type');
      if (geomType === 'line' || geomType === 'lineStack' || geomType === 'area' || geomType === 'areaStack') return true;
    }

    return false;
  };

  _proto._adjustPosition = function _adjustPosition(position, isTailLegend) {
    var pos;

    if (isTailLegend) {
      pos = 'right-top';
    } else if (Util.isArray(position)) {
      pos = String(position[0]) + '-' + String(position[1]);
    } else {
      var posArr = position.split('-');

      if (posArr.length === 1) {
        // 只用了left/right/bottom/top一个位置定位
        if (posArr[0] === 'left') pos = 'left-bottom';
        if (posArr[0] === 'right') pos = 'right-bottom';
        if (posArr[0] === 'top') pos = 'top-center';
        if (posArr[0] === 'bottom') pos = 'bottom-center';
      } else {
        pos = position;
      }
    }

    return pos;
  };

  _proto.addLegend = function addLegend(scale, attr, geom, filterVals) {
    var self = this;
    var legendOptions = self.options;
    var field = scale.field;
    var fieldOption = legendOptions[field];
    var viewTheme = self.viewTheme;

    if (fieldOption === false) {
      // 如果不显示此图例
      return null;
    }

    if (fieldOption && fieldOption.custom) {
      self.addCustomLegend(field);
    } else {
      var position = legendOptions.position || viewTheme.defaultLegendPosition;
      position = self._adjustPosition(position, self._isTailLegend(legendOptions, geom));

      if (fieldOption && fieldOption.position) {
        // 如果对某个图例单独设置 position，则对 position 重新赋值
        position = self._adjustPosition(fieldOption.position, self._isTailLegend(fieldOption, geom));
      }

      var legend;

      if (scale.isLinear) {
        legend = self._addContinuousLegend(scale, attr, position);
      } else {
        legend = self._addCategoryLegend(scale, attr, geom, filterVals, position);
      }

      if (legend) {
        self._bindHoverEvent(legend, field);

        legendOptions.reactive && self._bindChartMove(scale);
      }
    }
  }
  /**
   * 自定义图例
   * @param {string} field 自定义图例的数据字段名，可以为空
   * @return {object} legend 自定义图例实例
   */
  ;

  _proto.addCustomLegend = function addCustomLegend(field) {
    var self = this;
    var chart = self.chart;
    var viewTheme = self.viewTheme;
    var container = self.container;
    var legendOptions = self.options;

    if (field) {
      legendOptions = legendOptions[field];
    }

    var position = legendOptions.position || viewTheme.defaultLegendPosition;
    position = self._adjustPosition(position);
    var legends = self.legends;
    legends[position] = legends[position] || [];
    var items = legendOptions.items;

    if (!items) {
      return;
    }

    var geoms = chart.getAllGeoms();
    Util.each(items, function (item) {
      var geom = findGeom(geoms, item.value);

      if (!Util.isPlainObject(item.marker)) {
        // 直接传入字符串或者回调函数时转换为对象，如 item.marker = 'circle'
        item.marker = {
          symbol: item.marker || 'circle',
          radius: Global.legendMarkerRadius || MARKER_SIZE
        };

        if (Util.indexOf(STROKE_MARKERS, item.marker.symbol) !== -1) {
          item.marker.stroke = item.fill;
        } else {
          item.marker.fill = item.fill;
        }
      } else {
        // 用户传入对象 item.marker = { symbol: 'circle', fill: 'red', radius: 3 }
        item.marker.radius = item.marker.radius || Global.legendMarkerRadius || MARKER_SIZE;
      }

      var symbol = item.marker.symbol;

      if (Util.isString(symbol) && symbol.indexOf('hollow') !== -1) {
        item.marker.symbol = Util.lowerFirst(symbol.substr(6));
      }

      item.checked = Util.isNil(item.checked) ? true : item.checked;
      item.geom = geom;
    });
    var canvas = chart.get('canvas');
    var plotRange = self.plotRange;
    var posArray = position.split('-');
    var maxLength = posArray[0] === 'right' || posArray[0] === 'left' ? plotRange.bl.y - plotRange.tr.y : canvas.get('width');
    var legendCfg = Util.deepMix({}, viewTheme.legend[posArray[0]], legendOptions, {
      maxLength: maxLength,
      items: items,
      container: container,
      position: [0, 0]
    });
    var legend;

    if (legendOptions.useHtml) {
      var htmlContainer = legendOptions.container;

      if (/^\#/.test(container)) {
        // 如果传入 dom 节点的 id
        var id = htmlContainer.replace('#', '');
        htmlContainer = document.getElementById(id);
      } else if (!htmlContainer) {
        htmlContainer = container.get('canvas').get('el').parentNode;
      }

      legendCfg.container = htmlContainer;
      if (legendCfg.legendStyle === undefined) legendCfg.legendStyle = {};

      if (!legendCfg.legendStyle.CONTAINER_CLASS) {
        legendCfg.legendStyle.CONTAINER_CLASS = {
          height: posArray[0] === 'right' || posArray[0] === 'left' ? maxLength + 'px' : 'auto',
          width: !(posArray[0] === 'right' || posArray[0] === 'left') ? maxLength + 'px' : 'auto',
          position: 'absolute',
          overflow: 'auto'
        };
      }

      if (legendOptions.flipPage) legend = new Legend.CatPageHtml(legendCfg);else legend = new Legend.CatHtml(legendCfg);
    } else legend = new Legend.Category(legendCfg);

    legends[position].push(legend);
    legend.on('itemclick', function (ev) {
      if (legendOptions.onClick) {
        // 用户自定义了图例点击事件
        legendOptions.onClick(ev);
      }
    });

    self._bindHoverEvent(legend);

    return legend;
  };

  _proto.addMixedLegend = function addMixedLegend(scales, geoms) {
    var self = this;
    var legendOptions = self.options;
    var items = [];
    Util.each(scales, function (scale) {
      var value = scale.alias || scale.field;
      var fieldLegendOptions = legendOptions[scale.field];
      Util.each(geoms, function (geom) {
        if (geom.getYScale() === scale && scale.values && scale.values.length > 0 && fieldLegendOptions !== false) {
          var shapeType = geom.get('shapeType') || 'point';
          var shape = geom.getDefaultValue('shape') || 'circle';
          var shapeObject = Shape.getShapeFactory(shapeType);
          var cfg = {
            color: geom.getDefaultValue('color')
          };
          var marker = shapeObject.getMarkerCfg(shape, cfg);

          if (Global.legendMarkerRadius) {
            marker.radius = Global.legendMarkerRadius;
          }

          var item = {
            value: value,
            marker: marker,
            field: scale.field
          };
          items.push(item);
        }
      }); // end of geom loop
    }); // end of scale loop

    var options = {
      custom: true,
      items: items
    };
    self.options = Util.deepMix({}, options, self.options);
    var legend = self.addCustomLegend();

    self._bindClickEventForMix(legend);
  };

  _proto.alignLegends = function alignLegends() {
    var self = this;
    var legends = self.legends;

    var totalRegion = self._getRegion(legends);

    self.totalRegion = totalRegion;
    var i = 0;
    Util.each(legends, function (legendItems, position) {
      var region =
      /* self._getRegion(legendItems)*/
      totalRegion.subs[i];
      Util.each(legendItems, function (legend, index) {
        var pre = legendItems[index - 1];

        if (!(legend.get('useHtml') && !legend.get('autoPosition'))) {
          self._alignLegend(legend, pre, region, position);
        }
      });
      i++;
    });
    return this;
  };

  return LegendController;
}();

module.exports = LegendController;