/**
 * echarts组件：时间轴组件
 *
 * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。
 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
 *
 */
module.exports = function (require) {
  var Base = require('./base'); // 图形依赖


  var RectangleShape = require('zrender/shape/Rectangle');

  var IconShape = require('../util/shape/Icon');

  var ChainShape = require('../util/shape/Chain');

  var ecConfig = require('../config');

  ecConfig.timeline = {
    zlevel: 0,
    // 一级层叠
    z: 4,
    // 二级层叠
    show: true,
    type: 'time',
    // 模式是时间类型，支持 number
    notMerge: false,
    realtime: true,
    x: 80,
    // y: {number},
    x2: 80,
    y2: 0,
    // width: {totalWidth} - x - x2,
    height: 50,
    backgroundColor: 'rgba(0,0,0,0)',
    // 时间轴背景颜色
    borderColor: '#ccc',
    // 时间轴边框颜色
    borderWidth: 0,
    // 时间轴边框线宽，单位px，默认为0（无边框）
    padding: 5,
    // 时间轴内边距，单位px，默认各方向内边距为5，
    controlPosition: 'left',
    // 'right' | 'none'
    autoPlay: false,
    loop: true,
    playInterval: 2000,
    // 播放时间间隔，单位ms
    lineStyle: {
      width: 1,
      color: '#666',
      type: 'dashed'
    },
    label: {
      // 文本标签
      show: true,
      interval: 'auto',
      rotate: 0,
      // formatter: null,
      textStyle: {
        // 其余属性默认使用全局文本样式，详见TEXTSTYLE
        color: '#333'
      }
    },
    checkpointStyle: {
      symbol: 'auto',
      symbolSize: 'auto',
      color: 'auto',
      borderColor: 'auto',
      borderWidth: 'auto',
      label: {
        // 文本标签
        show: false,
        textStyle: {
          // 其余属性默认使用全局文本样式，详见TEXTSTYLE
          color: 'auto'
        }
      }
    },
    controlStyle: {
      itemSize: 15,
      itemGap: 5,
      normal: {
        color: '#333'
      },
      emphasis: {
        color: '#1e90ff'
      }
    },
    symbol: 'emptyDiamond',
    symbolSize: 4,
    currentIndex: 0 // data: []

  };

  var zrUtil = require('zrender/tool/util');

  var zrArea = require('zrender/tool/area');

  var zrEvent = require('zrender/tool/event');
  /**
   * 构造函数
   * @param {Object} messageCenter echart消息中心
   * @param {ZRender} zr zrender实例
   * @param {Object} option 图表参数
   */


  function Timeline(ecTheme, messageCenter, zr, option, myChart) {
    Base.call(this, ecTheme, messageCenter, zr, option, myChart);
    var self = this;

    self._onclick = function (param) {
      return self.__onclick(param);
    };

    self._ondrift = function (dx, dy) {
      return self.__ondrift(this, dx, dy);
    };

    self._ondragend = function () {
      return self.__ondragend();
    };

    self._setCurrentOption = function () {
      var timelineOption = self.timelineOption;
      self.currentIndex %= timelineOption.data.length; // console.log(self.currentIndex);

      var curOption = self.options[self.currentIndex] || {};

      self.myChart._setOption(curOption, timelineOption.notMerge, true);

      self.messageCenter.dispatch(ecConfig.EVENT.TIMELINE_CHANGED, null, {
        currentIndex: self.currentIndex,
        data: timelineOption.data[self.currentIndex].name != null ? timelineOption.data[self.currentIndex].name : timelineOption.data[self.currentIndex]
      }, self.myChart);
    };

    self._onFrame = function () {
      self._setCurrentOption();

      self._syncHandleShape();

      if (self.timelineOption.autoPlay) {
        self.playTicket = setTimeout(function () {
          self.currentIndex += 1;

          if (!self.timelineOption.loop && self.currentIndex >= self.timelineOption.data.length) {
            self.currentIndex = self.timelineOption.data.length - 1;
            self.stop();
            return;
          }

          self._onFrame();
        }, self.timelineOption.playInterval);
      }
    };

    this.setTheme(false);
    this.options = this.option.options;
    this.currentIndex = this.timelineOption.currentIndex % this.timelineOption.data.length;

    if (!this.timelineOption.notMerge && this.currentIndex !== 0) {
      /*
      for (var i = 1, l = this.timelineOption.data.length; i < l; i++) {
          this.options[i] = zrUtil.merge(
              this.options[i], this.options[i - 1]
          );
      }
      */
      this.options[this.currentIndex] = zrUtil.merge(this.options[this.currentIndex], this.options[0]);
    }

    if (this.timelineOption.show) {
      this._buildShape();

      this._syncHandleShape();
    }

    this._setCurrentOption();

    if (this.timelineOption.autoPlay) {
      var self = this;
      this.playTicket = setTimeout(function () {
        self.play();
      }, this.ecTheme.animationDuration != null ? this.ecTheme.animationDuration : ecConfig.animationDuration);
    }
  }

  Timeline.prototype = {
    type: ecConfig.COMPONENT_TYPE_TIMELINE,
    _buildShape: function () {
      // 位置参数，通过计算所得x, y, width, height
      this._location = this._getLocation();

      this._buildBackground();

      this._buildControl();

      this._chainPoint = this._getChainPoint();

      if (this.timelineOption.label.show) {
        // 标签显示的挑选间隔
        var interval = this._getInterval();

        for (var i = 0, len = this._chainPoint.length; i < len; i += interval) {
          this._chainPoint[i].showLabel = true;
        }
      }

      this._buildChain();

      this._buildHandle();

      for (var i = 0, l = this.shapeList.length; i < l; i++) {
        this.zr.addShape(this.shapeList[i]);
      }
    },

    /**
     * 根据选项计算实体的位置坐标
     */
    _getLocation: function () {
      var timelineOption = this.timelineOption;
      var padding = this.reformCssArray(this.timelineOption.padding); // 水平布局

      var zrWidth = this.zr.getWidth();
      var x = this.parsePercent(timelineOption.x, zrWidth);
      var x2 = this.parsePercent(timelineOption.x2, zrWidth);
      var width;

      if (timelineOption.width == null) {
        width = zrWidth - x - x2;
        x2 = zrWidth - x2;
      } else {
        width = this.parsePercent(timelineOption.width, zrWidth);
        x2 = x + width;
      }

      var zrHeight = this.zr.getHeight();
      var height = this.parsePercent(timelineOption.height, zrHeight);
      var y;
      var y2;

      if (timelineOption.y != null) {
        y = this.parsePercent(timelineOption.y, zrHeight);
        y2 = y + height;
      } else {
        y2 = zrHeight - this.parsePercent(timelineOption.y2, zrHeight);
        y = y2 - height;
      }

      return {
        x: x + padding[3],
        y: y + padding[0],
        x2: x2 - padding[1],
        y2: y2 - padding[2],
        width: width - padding[1] - padding[3],
        height: height - padding[0] - padding[2]
      };
    },
    _getReformedLabel: function (idx) {
      var timelineOption = this.timelineOption;
      var data = timelineOption.data[idx].name != null ? timelineOption.data[idx].name : timelineOption.data[idx];
      var formatter = timelineOption.data[idx].formatter || timelineOption.label.formatter;

      if (formatter) {
        if (typeof formatter === 'function') {
          data = formatter.call(this.myChart, data);
        } else if (typeof formatter === 'string') {
          data = formatter.replace('{value}', data);
        }
      }

      return data;
    },

    /**
     * 计算标签显示挑选间隔
     */
    _getInterval: function () {
      var chainPoint = this._chainPoint;
      var timelineOption = this.timelineOption;
      var interval = timelineOption.label.interval;

      if (interval === 'auto') {
        // 麻烦的自适应计算
        var fontSize = timelineOption.label.textStyle.fontSize;
        var data = timelineOption.data;
        var dataLength = timelineOption.data.length; // 横向

        if (dataLength > 3) {
          var isEnough = false;
          var labelSpace;
          var labelSize;
          interval = 0;

          while (!isEnough && interval < dataLength) {
            interval++;
            isEnough = true;

            for (var i = interval; i < dataLength; i += interval) {
              labelSpace = chainPoint[i].x - chainPoint[i - interval].x;

              if (timelineOption.label.rotate !== 0) {
                // 有旋转
                labelSize = fontSize;
              } else if (data[i].textStyle) {
                labelSize = zrArea.getTextWidth(chainPoint[i].name, chainPoint[i].textFont);
              } else {
                // 不定义data级特殊文本样式，用fontSize优化getTextWidth
                var label = chainPoint[i].name + '';
                var wLen = (label.match(/\w/g) || '').length;
                var oLen = label.length - wLen;
                labelSize = wLen * fontSize * 2 / 3 + oLen * fontSize;
              }

              if (labelSpace < labelSize) {
                // 放不下，中断循环让interval++
                isEnough = false;
                break;
              }
            }
          }
        } else {
          // 少于3个则全部显示
          interval = 1;
        }
      } else {
        // 用户自定义间隔
        interval = interval - 0 + 1;
      }

      return interval;
    },

    /**
     * 根据选项计算时间链条上的坐标及symbolList
     */
    _getChainPoint: function () {
      var timelineOption = this.timelineOption;
      var symbol = timelineOption.symbol.toLowerCase();
      var symbolSize = timelineOption.symbolSize;
      var rotate = timelineOption.label.rotate;
      var textStyle = timelineOption.label.textStyle;
      var textFont = this.getFont(textStyle);
      var dataTextStyle;
      var data = timelineOption.data;
      var x = this._location.x;
      var y = this._location.y + this._location.height / 4 * 3;
      var width = this._location.x2 - this._location.x;
      var len = data.length;

      function _getName(i) {
        return data[i].name != null ? data[i].name : data[i] + '';
      }

      var xList = [];

      if (len > 1) {
        var boundaryGap = width / len;
        boundaryGap = boundaryGap > 50 ? 50 : boundaryGap < 20 ? 5 : boundaryGap;
        width -= boundaryGap * 2;

        if (timelineOption.type === 'number') {
          // 平均分布
          for (var i = 0; i < len; i++) {
            xList.push(x + boundaryGap + width / (len - 1) * i);
          }
        } else {
          // 时间比例
          xList[0] = new Date(_getName(0).replace(/-/g, '/'));
          xList[len - 1] = new Date(_getName(len - 1).replace(/-/g, '/')) - xList[0];

          for (var i = 1; i < len; i++) {
            xList[i] = x + boundaryGap + width * (new Date(_getName(i).replace(/-/g, '/')) - xList[0]) / xList[len - 1];
          }

          xList[0] = x + boundaryGap;
        }
      } else {
        xList.push(x + width / 2);
      }

      var list = [];
      var curSymbol;
      var n;
      var isEmpty;
      var textAlign;
      var rotation;

      for (var i = 0; i < len; i++) {
        x = xList[i];
        curSymbol = data[i].symbol && data[i].symbol.toLowerCase() || symbol;

        if (curSymbol.match('empty')) {
          curSymbol = curSymbol.replace('empty', '');
          isEmpty = true;
        } else {
          isEmpty = false;
        }

        if (curSymbol.match('star')) {
          n = curSymbol.replace('star', '') - 0 || 5;
          curSymbol = 'star';
        }

        dataTextStyle = data[i].textStyle ? zrUtil.merge(data[i].textStyle || {}, textStyle) : textStyle;
        textAlign = dataTextStyle.align || 'center';

        if (rotate) {
          textAlign = rotate > 0 ? 'right' : 'left';
          rotation = [rotate * Math.PI / 180, x, y - 5];
        } else {
          rotation = false;
        }

        list.push({
          x: x,
          n: n,
          isEmpty: isEmpty,
          symbol: curSymbol,
          symbolSize: data[i].symbolSize || symbolSize,
          color: data[i].color,
          borderColor: data[i].borderColor,
          borderWidth: data[i].borderWidth,
          name: this._getReformedLabel(i),
          textColor: dataTextStyle.color,
          textAlign: textAlign,
          textBaseline: dataTextStyle.baseline || 'middle',
          textX: x,
          textY: y - (rotate ? 5 : 0),
          textFont: data[i].textStyle ? this.getFont(dataTextStyle) : textFont,
          rotation: rotation,
          showLabel: false
        });
      }

      return list;
    },
    _buildBackground: function () {
      var timelineOption = this.timelineOption;
      var padding = this.reformCssArray(this.timelineOption.padding);
      var width = this._location.width;
      var height = this._location.height;

      if (timelineOption.borderWidth !== 0 || timelineOption.backgroundColor.replace(/\s/g, '') != 'rgba(0,0,0,0)') {
        // 背景
        this.shapeList.push(new RectangleShape({
          zlevel: this.getZlevelBase(),
          z: this.getZBase(),
          hoverable: false,
          style: {
            x: this._location.x - padding[3],
            y: this._location.y - padding[0],
            width: width + padding[1] + padding[3],
            height: height + padding[0] + padding[2],
            brushType: timelineOption.borderWidth === 0 ? 'fill' : 'both',
            color: timelineOption.backgroundColor,
            strokeColor: timelineOption.borderColor,
            lineWidth: timelineOption.borderWidth
          }
        }));
      }
    },
    _buildControl: function () {
      var self = this;
      var timelineOption = this.timelineOption;
      var lineStyle = timelineOption.lineStyle;
      var controlStyle = timelineOption.controlStyle;

      if (timelineOption.controlPosition === 'none') {
        return;
      }

      var iconSize = controlStyle.itemSize;
      var iconGap = controlStyle.itemGap;
      var x;

      if (timelineOption.controlPosition === 'left') {
        x = this._location.x;
        this._location.x += (iconSize + iconGap) * 3;
      } else {
        x = this._location.x2 - ((iconSize + iconGap) * 3 - iconGap);
        this._location.x2 -= (iconSize + iconGap) * 3;
      }

      var y = this._location.y;
      var iconStyle = {
        zlevel: this.getZlevelBase(),
        z: this.getZBase() + 1,
        style: {
          iconType: 'timelineControl',
          symbol: 'last',
          x: x,
          y: y,
          width: iconSize,
          height: iconSize,
          brushType: 'stroke',
          color: controlStyle.normal.color,
          strokeColor: controlStyle.normal.color,
          lineWidth: lineStyle.width
        },
        highlightStyle: {
          color: controlStyle.emphasis.color,
          strokeColor: controlStyle.emphasis.color,
          lineWidth: lineStyle.width + 1
        },
        clickable: true
      };
      this._ctrLastShape = new IconShape(iconStyle);

      this._ctrLastShape.onclick = function () {
        self.last();
      };

      this.shapeList.push(this._ctrLastShape);
      x += iconSize + iconGap;
      this._ctrPlayShape = new IconShape(zrUtil.clone(iconStyle));
      this._ctrPlayShape.style.brushType = 'fill';
      this._ctrPlayShape.style.symbol = 'play';
      this._ctrPlayShape.style.status = this.timelineOption.autoPlay ? 'playing' : 'stop';
      this._ctrPlayShape.style.x = x;

      this._ctrPlayShape.onclick = function () {
        if (self._ctrPlayShape.style.status === 'stop') {
          self.play();
        } else {
          self.stop();
        }
      };

      this.shapeList.push(this._ctrPlayShape);
      x += iconSize + iconGap;
      this._ctrNextShape = new IconShape(zrUtil.clone(iconStyle));
      this._ctrNextShape.style.symbol = 'next';
      this._ctrNextShape.style.x = x;

      this._ctrNextShape.onclick = function () {
        self.next();
      };

      this.shapeList.push(this._ctrNextShape);
    },

    /**
     * 构建时间轴
     */
    _buildChain: function () {
      var timelineOption = this.timelineOption;
      var lineStyle = timelineOption.lineStyle;
      this._timelineShae = {
        zlevel: this.getZlevelBase(),
        z: this.getZBase(),
        style: {
          x: this._location.x,
          y: this.subPixelOptimize(this._location.y, lineStyle.width),
          width: this._location.x2 - this._location.x,
          height: this._location.height,
          chainPoint: this._chainPoint,
          brushType: 'both',
          strokeColor: lineStyle.color,
          lineWidth: lineStyle.width,
          lineType: lineStyle.type
        },
        hoverable: false,
        clickable: true,
        onclick: this._onclick
      };
      this._timelineShae = new ChainShape(this._timelineShae);
      this.shapeList.push(this._timelineShae);
    },

    /**
     * 构建拖拽手柄
     */
    _buildHandle: function () {
      var curPoint = this._chainPoint[this.currentIndex];
      var symbolSize = curPoint.symbolSize + 1;
      symbolSize = symbolSize < 5 ? 5 : symbolSize;
      this._handleShape = {
        zlevel: this.getZlevelBase(),
        z: this.getZBase() + 1,
        hoverable: false,
        draggable: true,
        style: {
          iconType: 'diamond',
          n: curPoint.n,
          x: curPoint.x - symbolSize,
          y: this._location.y + this._location.height / 4 - symbolSize,
          width: symbolSize * 2,
          height: symbolSize * 2,
          brushType: 'both',
          textPosition: 'specific',
          textX: curPoint.x,
          textY: this._location.y - this._location.height / 4,
          textAlign: 'center',
          textBaseline: 'middle'
        },
        highlightStyle: {},
        ondrift: this._ondrift,
        ondragend: this._ondragend
      };
      this._handleShape = new IconShape(this._handleShape);
      this.shapeList.push(this._handleShape);
    },

    /**
     * 同步拖拽图形样式 
     */
    _syncHandleShape: function () {
      if (!this.timelineOption.show) {
        return;
      }

      var timelineOption = this.timelineOption;
      var cpStyle = timelineOption.checkpointStyle;
      var curPoint = this._chainPoint[this.currentIndex];
      this._handleShape.style.text = cpStyle.label.show ? curPoint.name : '';
      this._handleShape.style.textFont = curPoint.textFont;
      this._handleShape.style.n = curPoint.n;

      if (cpStyle.symbol === 'auto') {
        this._handleShape.style.iconType = curPoint.symbol != 'none' ? curPoint.symbol : 'diamond';
      } else {
        this._handleShape.style.iconType = cpStyle.symbol;

        if (cpStyle.symbol.match('star')) {
          this._handleShape.style.n = cpStyle.symbol.replace('star', '') - 0 || 5;
          this._handleShape.style.iconType = 'star';
        }
      }

      var symbolSize;

      if (cpStyle.symbolSize === 'auto') {
        symbolSize = curPoint.symbolSize + 2;
        symbolSize = symbolSize < 5 ? 5 : symbolSize;
      } else {
        symbolSize = cpStyle.symbolSize - 0;
      }

      this._handleShape.style.color = cpStyle.color === 'auto' ? curPoint.color ? curPoint.color : timelineOption.controlStyle.emphasis.color : cpStyle.color;
      this._handleShape.style.textColor = cpStyle.label.textStyle.color === 'auto' ? this._handleShape.style.color : cpStyle.label.textStyle.color;
      this._handleShape.highlightStyle.strokeColor = this._handleShape.style.strokeColor = cpStyle.borderColor === 'auto' ? curPoint.borderColor ? curPoint.borderColor : '#fff' : cpStyle.borderColor;
      this._handleShape.style.lineWidth = cpStyle.borderWidth === 'auto' ? curPoint.borderWidth ? curPoint.borderWidth : 0 : cpStyle.borderWidth - 0;
      this._handleShape.highlightStyle.lineWidth = this._handleShape.style.lineWidth + 1;
      this.zr.animate(this._handleShape.id, 'style').when(500, {
        x: curPoint.x - symbolSize,
        textX: curPoint.x,
        y: this._location.y + this._location.height / 4 - symbolSize,
        width: symbolSize * 2,
        height: symbolSize * 2
      }).start('ExponentialOut');
    },
    _findChainIndex: function (x) {
      var chainPoint = this._chainPoint;
      var len = chainPoint.length;

      if (x <= chainPoint[0].x) {
        return 0;
      } else if (x >= chainPoint[len - 1].x) {
        return len - 1;
      }

      for (var i = 0; i < len - 1; i++) {
        if (x >= chainPoint[i].x && x <= chainPoint[i + 1].x) {
          // catch you！
          return Math.abs(x - chainPoint[i].x) < Math.abs(x - chainPoint[i + 1].x) ? i : i + 1;
        }
      }
    },
    __onclick: function (param) {
      var x = zrEvent.getX(param.event);

      var newIndex = this._findChainIndex(x);

      if (newIndex === this.currentIndex) {
        return true; // 啥事都没发生
      }

      this.currentIndex = newIndex;
      this.timelineOption.autoPlay && this.stop(); // 停止自动播放

      clearTimeout(this.playTicket);

      this._onFrame();
    },

    /**
     * 拖拽范围控制
     */
    __ondrift: function (shape, dx) {
      this.timelineOption.autoPlay && this.stop(); // 停止自动播放

      var chainPoint = this._chainPoint;
      var len = chainPoint.length;
      var newIndex;

      if (shape.style.x + dx <= chainPoint[0].x - chainPoint[0].symbolSize) {
        shape.style.x = chainPoint[0].x - chainPoint[0].symbolSize;
        newIndex = 0;
      } else if (shape.style.x + dx >= chainPoint[len - 1].x - chainPoint[len - 1].symbolSize) {
        shape.style.x = chainPoint[len - 1].x - chainPoint[len - 1].symbolSize;
        newIndex = len - 1;
      } else {
        shape.style.x += dx;
        newIndex = this._findChainIndex(shape.style.x);
      }

      var curPoint = chainPoint[newIndex];
      var symbolSize = curPoint.symbolSize + 2;
      shape.style.iconType = curPoint.symbol;
      shape.style.n = curPoint.n;
      shape.style.textX = shape.style.x + symbolSize / 2;
      shape.style.y = this._location.y + this._location.height / 4 - symbolSize;
      shape.style.width = symbolSize * 2;
      shape.style.height = symbolSize * 2;
      shape.style.text = curPoint.name; //console.log(newIndex)

      if (newIndex === this.currentIndex) {
        return true; // 啥事都没发生
      }

      this.currentIndex = newIndex;

      if (this.timelineOption.realtime) {
        clearTimeout(this.playTicket);
        var self = this;
        this.playTicket = setTimeout(function () {
          self._setCurrentOption();
        }, 200);
      }

      return true;
    },
    __ondragend: function () {
      this.isDragend = true;
    },

    /**
     * 数据项被拖拽出去
     */
    ondragend: function (param, status) {
      if (!this.isDragend || !param.target) {
        // 没有在当前实例上发生拖拽行为则直接返回
        return;
      }

      !this.timelineOption.realtime && this._setCurrentOption(); // 别status = {}赋值啊！！

      status.dragOut = true;
      status.dragIn = true;
      status.needRefresh = false; // 会有消息触发fresh，不用再刷一遍
      // 处理完拖拽事件后复位

      this.isDragend = false;

      this._syncHandleShape();

      return;
    },
    last: function () {
      this.timelineOption.autoPlay && this.stop(); // 停止自动播放

      this.currentIndex -= 1;

      if (this.currentIndex < 0) {
        this.currentIndex = this.timelineOption.data.length - 1;
      }

      this._onFrame();

      return this.currentIndex;
    },
    next: function () {
      this.timelineOption.autoPlay && this.stop(); // 停止自动播放

      this.currentIndex += 1;

      if (this.currentIndex >= this.timelineOption.data.length) {
        this.currentIndex = 0;
      }

      this._onFrame();

      return this.currentIndex;
    },
    play: function (targetIndex, autoPlay) {
      if (this._ctrPlayShape && this._ctrPlayShape.style.status != 'playing') {
        this._ctrPlayShape.style.status = 'playing';
        this.zr.modShape(this._ctrPlayShape.id);
        this.zr.refreshNextFrame();
      }

      this.timelineOption.autoPlay = autoPlay != null ? autoPlay : true;

      if (!this.timelineOption.autoPlay) {
        clearTimeout(this.playTicket);
      }

      this.currentIndex = targetIndex != null ? targetIndex : this.currentIndex + 1;

      if (this.currentIndex >= this.timelineOption.data.length) {
        this.currentIndex = 0;
      }

      this._onFrame();

      return this.currentIndex;
    },
    stop: function () {
      if (this._ctrPlayShape && this._ctrPlayShape.style.status != 'stop') {
        this._ctrPlayShape.style.status = 'stop';
        this.zr.modShape(this._ctrPlayShape.id);
        this.zr.refreshNextFrame();
      }

      this.timelineOption.autoPlay = false;
      clearTimeout(this.playTicket);
      return this.currentIndex;
    },

    /**
     * 避免dataZoom带来两次refresh，不设refresh接口，resize重复一下buildshape逻辑 
     */
    resize: function () {
      if (this.timelineOption.show) {
        this.clear();

        this._buildShape();

        this._syncHandleShape();
      }
    },
    setTheme: function (needRefresh) {
      this.timelineOption = this.reformOption(zrUtil.clone(this.option.timeline)); // 通用字体设置

      this.timelineOption.label.textStyle = this.getTextStyle(this.timelineOption.label.textStyle);
      this.timelineOption.checkpointStyle.label.textStyle = this.getTextStyle(this.timelineOption.checkpointStyle.label.textStyle);

      if (!this.myChart.canvasSupported) {
        // 不支持Canvas的强制关闭实时动画
        this.timelineOption.realtime = false;
      }

      if (this.timelineOption.show && needRefresh) {
        this.clear();

        this._buildShape();

        this._syncHandleShape();
      }
    },

    /**
     * 释放后实例不可用，重载基类方法
     */
    onbeforDispose: function () {
      clearTimeout(this.playTicket);
    }
  };

  function timelineControl(ctx, style) {
    var lineWidth = 2; //style.lineWidth;

    var x = style.x + lineWidth;
    var y = style.y + lineWidth + 2;
    var width = style.width - lineWidth;
    var height = style.height - lineWidth;
    var symbol = style.symbol;

    if (symbol === 'last') {
      ctx.moveTo(x + width - 2, y + height / 3);
      ctx.lineTo(x + width - 2, y);
      ctx.lineTo(x + 2, y + height / 2);
      ctx.lineTo(x + width - 2, y + height);
      ctx.lineTo(x + width - 2, y + height / 3 * 2);
      ctx.moveTo(x, y);
      ctx.lineTo(x, y);
    } else if (symbol === 'next') {
      ctx.moveTo(x + 2, y + height / 3);
      ctx.lineTo(x + 2, y);
      ctx.lineTo(x + width - 2, y + height / 2);
      ctx.lineTo(x + 2, y + height);
      ctx.lineTo(x + 2, y + height / 3 * 2);
      ctx.moveTo(x, y);
      ctx.lineTo(x, y);
    } else if (symbol === 'play') {
      if (style.status === 'stop') {
        ctx.moveTo(x + 2, y);
        ctx.lineTo(x + width - 2, y + height / 2);
        ctx.lineTo(x + 2, y + height);
        ctx.lineTo(x + 2, y);
      } else {
        var delta = style.brushType === 'both' ? 2 : 3;
        ctx.rect(x + 2, y, delta, height);
        ctx.rect(x + width - delta - 2, y, delta, height);
      }
    } else if (symbol.match('image')) {
      var imageLocation = '';
      imageLocation = symbol.replace(new RegExp('^image:\\/\\/'), '');
      symbol = IconShape.prototype.iconLibrary.image;
      symbol(ctx, {
        x: x,
        y: y,
        width: width,
        height: height,
        image: imageLocation
      });
    }
  }

  IconShape.prototype.iconLibrary['timelineControl'] = timelineControl;
  zrUtil.inherits(Timeline, Base);

  require('../component').define('timeline', Timeline);

  return Timeline;
}(require);