
/*
* 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 BoundingRect from 'zrender/lib/core/BoundingRect.js';
import * as matrix from 'zrender/lib/core/matrix.js';
import * as graphic from '../../util/graphic.js';
import { createTextStyle } from '../../label/labelStyle.js';
import * as layout from '../../util/layout.js';
import TimelineView from './TimelineView.js';
import TimelineAxis from './TimelineAxis.js';
import { createSymbol, normalizeSymbolOffset, normalizeSymbolSize } from '../../util/symbol.js';
import * as numberUtil from '../../util/number.js';
import { merge, each, extend, isString, bind, defaults, retrieve2 } from 'zrender/lib/core/util.js';
import OrdinalScale from '../../scale/Ordinal.js';
import TimeScale from '../../scale/Time.js';
import IntervalScale from '../../scale/Interval.js';
import { parsePercent } from 'zrender/lib/contain/text.js';
import { makeInner } from '../../util/model.js';
import { getECData } from '../../util/innerStore.js';
import { enableHoverEmphasis } from '../../util/states.js';
import { createTooltipMarkup } from '../tooltip/tooltipMarkup.js';
var PI = Math.PI;
var labelDataIndexStore = makeInner();

var SliderTimelineView =
/** @class */
function (_super) {
  __extends(SliderTimelineView, _super);

  function SliderTimelineView() {
    var _this = _super !== null && _super.apply(this, arguments) || this;

    _this.type = SliderTimelineView.type;
    return _this;
  }

  SliderTimelineView.prototype.init = function (ecModel, api) {
    this.api = api;
  };
  /**
   * @override
   */


  SliderTimelineView.prototype.render = function (timelineModel, ecModel, api) {
    this.model = timelineModel;
    this.api = api;
    this.ecModel = ecModel;
    this.group.removeAll();

    if (timelineModel.get('show', true)) {
      var layoutInfo_1 = this._layout(timelineModel, api);

      var mainGroup_1 = this._createGroup('_mainGroup');

      var labelGroup = this._createGroup('_labelGroup');

      var axis_1 = this._axis = this._createAxis(layoutInfo_1, timelineModel);

      timelineModel.formatTooltip = function (dataIndex) {
        var name = axis_1.scale.getLabel({
          value: dataIndex
        });
        return createTooltipMarkup('nameValue', {
          noName: true,
          value: name
        });
      };

      each(['AxisLine', 'AxisTick', 'Control', 'CurrentPointer'], function (name) {
        this['_render' + name](layoutInfo_1, mainGroup_1, axis_1, timelineModel);
      }, this);

      this._renderAxisLabel(layoutInfo_1, labelGroup, axis_1, timelineModel);

      this._position(layoutInfo_1, timelineModel);
    }

    this._doPlayStop();

    this._updateTicksStatus();
  };
  /**
   * @override
   */


  SliderTimelineView.prototype.remove = function () {
    this._clearTimer();

    this.group.removeAll();
  };
  /**
   * @override
   */


  SliderTimelineView.prototype.dispose = function () {
    this._clearTimer();
  };

  SliderTimelineView.prototype._layout = function (timelineModel, api) {
    var labelPosOpt = timelineModel.get(['label', 'position']);
    var orient = timelineModel.get('orient');
    var viewRect = getViewRect(timelineModel, api);
    var parsedLabelPos; // Auto label offset.

    if (labelPosOpt == null || labelPosOpt === 'auto') {
      parsedLabelPos = orient === 'horizontal' ? viewRect.y + viewRect.height / 2 < api.getHeight() / 2 ? '-' : '+' : viewRect.x + viewRect.width / 2 < api.getWidth() / 2 ? '+' : '-';
    } else if (isString(labelPosOpt)) {
      parsedLabelPos = {
        horizontal: {
          top: '-',
          bottom: '+'
        },
        vertical: {
          left: '-',
          right: '+'
        }
      }[orient][labelPosOpt];
    } else {
      // is number
      parsedLabelPos = labelPosOpt;
    }

    var labelAlignMap = {
      horizontal: 'center',
      vertical: parsedLabelPos >= 0 || parsedLabelPos === '+' ? 'left' : 'right'
    };
    var labelBaselineMap = {
      horizontal: parsedLabelPos >= 0 || parsedLabelPos === '+' ? 'top' : 'bottom',
      vertical: 'middle'
    };
    var rotationMap = {
      horizontal: 0,
      vertical: PI / 2
    }; // Position

    var mainLength = orient === 'vertical' ? viewRect.height : viewRect.width;
    var controlModel = timelineModel.getModel('controlStyle');
    var showControl = controlModel.get('show', true);
    var controlSize = showControl ? controlModel.get('itemSize') : 0;
    var controlGap = showControl ? controlModel.get('itemGap') : 0;
    var sizePlusGap = controlSize + controlGap; // Special label rotate.

    var labelRotation = timelineModel.get(['label', 'rotate']) || 0;
    labelRotation = labelRotation * PI / 180; // To radian.

    var playPosition;
    var prevBtnPosition;
    var nextBtnPosition;
    var controlPosition = controlModel.get('position', true);
    var showPlayBtn = showControl && controlModel.get('showPlayBtn', true);
    var showPrevBtn = showControl && controlModel.get('showPrevBtn', true);
    var showNextBtn = showControl && controlModel.get('showNextBtn', true);
    var xLeft = 0;
    var xRight = mainLength; // position[0] means left, position[1] means middle.

    if (controlPosition === 'left' || controlPosition === 'bottom') {
      showPlayBtn && (playPosition = [0, 0], xLeft += sizePlusGap);
      showPrevBtn && (prevBtnPosition = [xLeft, 0], xLeft += sizePlusGap);
      showNextBtn && (nextBtnPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);
    } else {
      // 'top' 'right'
      showPlayBtn && (playPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);
      showPrevBtn && (prevBtnPosition = [0, 0], xLeft += sizePlusGap);
      showNextBtn && (nextBtnPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);
    }

    var axisExtent = [xLeft, xRight];

    if (timelineModel.get('inverse')) {
      axisExtent.reverse();
    }

    return {
      viewRect: viewRect,
      mainLength: mainLength,
      orient: orient,
      rotation: rotationMap[orient],
      labelRotation: labelRotation,
      labelPosOpt: parsedLabelPos,
      labelAlign: timelineModel.get(['label', 'align']) || labelAlignMap[orient],
      labelBaseline: timelineModel.get(['label', 'verticalAlign']) || timelineModel.get(['label', 'baseline']) || labelBaselineMap[orient],
      // Based on mainGroup.
      playPosition: playPosition,
      prevBtnPosition: prevBtnPosition,
      nextBtnPosition: nextBtnPosition,
      axisExtent: axisExtent,
      controlSize: controlSize,
      controlGap: controlGap
    };
  };

  SliderTimelineView.prototype._position = function (layoutInfo, timelineModel) {
    // Position is be called finally, because bounding rect is needed for
    // adapt content to fill viewRect (auto adapt offset).
    // Timeline may be not all in the viewRect when 'offset' is specified
    // as a number, because it is more appropriate that label aligns at
    // 'offset' but not the other edge defined by viewRect.
    var mainGroup = this._mainGroup;
    var labelGroup = this._labelGroup;
    var viewRect = layoutInfo.viewRect;

    if (layoutInfo.orient === 'vertical') {
      // transform to horizontal, inverse rotate by left-top point.
      var m = matrix.create();
      var rotateOriginX = viewRect.x;
      var rotateOriginY = viewRect.y + viewRect.height;
      matrix.translate(m, m, [-rotateOriginX, -rotateOriginY]);
      matrix.rotate(m, m, -PI / 2);
      matrix.translate(m, m, [rotateOriginX, rotateOriginY]);
      viewRect = viewRect.clone();
      viewRect.applyTransform(m);
    }

    var viewBound = getBound(viewRect);
    var mainBound = getBound(mainGroup.getBoundingRect());
    var labelBound = getBound(labelGroup.getBoundingRect());
    var mainPosition = [mainGroup.x, mainGroup.y];
    var labelsPosition = [labelGroup.x, labelGroup.y];
    labelsPosition[0] = mainPosition[0] = viewBound[0][0];
    var labelPosOpt = layoutInfo.labelPosOpt;

    if (labelPosOpt == null || isString(labelPosOpt)) {
      // '+' or '-'
      var mainBoundIdx = labelPosOpt === '+' ? 0 : 1;
      toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx);
      toBound(labelsPosition, labelBound, viewBound, 1, 1 - mainBoundIdx);
    } else {
      var mainBoundIdx = labelPosOpt >= 0 ? 0 : 1;
      toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx);
      labelsPosition[1] = mainPosition[1] + labelPosOpt;
    }

    mainGroup.setPosition(mainPosition);
    labelGroup.setPosition(labelsPosition);
    mainGroup.rotation = labelGroup.rotation = layoutInfo.rotation;
    setOrigin(mainGroup);
    setOrigin(labelGroup);

    function setOrigin(targetGroup) {
      targetGroup.originX = viewBound[0][0] - targetGroup.x;
      targetGroup.originY = viewBound[1][0] - targetGroup.y;
    }

    function getBound(rect) {
      // [[xmin, xmax], [ymin, ymax]]
      return [[rect.x, rect.x + rect.width], [rect.y, rect.y + rect.height]];
    }

    function toBound(fromPos, from, to, dimIdx, boundIdx) {
      fromPos[dimIdx] += to[dimIdx][boundIdx] - from[dimIdx][boundIdx];
    }
  };

  SliderTimelineView.prototype._createAxis = function (layoutInfo, timelineModel) {
    var data = timelineModel.getData();
    var axisType = timelineModel.get('axisType');
    var scale = createScaleByModel(timelineModel, axisType); // Customize scale. The `tickValue` is `dataIndex`.

    scale.getTicks = function () {
      return data.mapArray(['value'], function (value) {
        return {
          value: value
        };
      });
    };

    var dataExtent = data.getDataExtent('value');
    scale.setExtent(dataExtent[0], dataExtent[1]);
    scale.calcNiceTicks();
    var axis = new TimelineAxis('value', scale, layoutInfo.axisExtent, axisType);
    axis.model = timelineModel;
    return axis;
  };

  SliderTimelineView.prototype._createGroup = function (key) {
    var newGroup = this[key] = new graphic.Group();
    this.group.add(newGroup);
    return newGroup;
  };

  SliderTimelineView.prototype._renderAxisLine = function (layoutInfo, group, axis, timelineModel) {
    var axisExtent = axis.getExtent();

    if (!timelineModel.get(['lineStyle', 'show'])) {
      return;
    }

    var line = new graphic.Line({
      shape: {
        x1: axisExtent[0],
        y1: 0,
        x2: axisExtent[1],
        y2: 0
      },
      style: extend({
        lineCap: 'round'
      }, timelineModel.getModel('lineStyle').getLineStyle()),
      silent: true,
      z2: 1
    });
    group.add(line);
    var progressLine = this._progressLine = new graphic.Line({
      shape: {
        x1: axisExtent[0],
        x2: this._currentPointer ? this._currentPointer.x : axisExtent[0],
        y1: 0,
        y2: 0
      },
      style: defaults({
        lineCap: 'round',
        lineWidth: line.style.lineWidth
      }, timelineModel.getModel(['progress', 'lineStyle']).getLineStyle()),
      silent: true,
      z2: 1
    });
    group.add(progressLine);
  };

  SliderTimelineView.prototype._renderAxisTick = function (layoutInfo, group, axis, timelineModel) {
    var _this = this;

    var data = timelineModel.getData(); // Show all ticks, despite ignoring strategy.

    var ticks = axis.scale.getTicks();
    this._tickSymbols = []; // The value is dataIndex, see the customized scale.

    each(ticks, function (tick) {
      var tickCoord = axis.dataToCoord(tick.value);
      var itemModel = data.getItemModel(tick.value);
      var itemStyleModel = itemModel.getModel('itemStyle');
      var hoverStyleModel = itemModel.getModel(['emphasis', 'itemStyle']);
      var progressStyleModel = itemModel.getModel(['progress', 'itemStyle']);
      var symbolOpt = {
        x: tickCoord,
        y: 0,
        onclick: bind(_this._changeTimeline, _this, tick.value)
      };
      var el = giveSymbol(itemModel, itemStyleModel, group, symbolOpt);
      el.ensureState('emphasis').style = hoverStyleModel.getItemStyle();
      el.ensureState('progress').style = progressStyleModel.getItemStyle();
      enableHoverEmphasis(el);
      var ecData = getECData(el);

      if (itemModel.get('tooltip')) {
        ecData.dataIndex = tick.value;
        ecData.dataModel = timelineModel;
      } else {
        ecData.dataIndex = ecData.dataModel = null;
      }

      _this._tickSymbols.push(el);
    });
  };

  SliderTimelineView.prototype._renderAxisLabel = function (layoutInfo, group, axis, timelineModel) {
    var _this = this;

    var labelModel = axis.getLabelModel();

    if (!labelModel.get('show')) {
      return;
    }

    var data = timelineModel.getData();
    var labels = axis.getViewLabels();
    this._tickLabels = [];
    each(labels, function (labelItem) {
      // The tickValue is dataIndex, see the customized scale.
      var dataIndex = labelItem.tickValue;
      var itemModel = data.getItemModel(dataIndex);
      var normalLabelModel = itemModel.getModel('label');
      var hoverLabelModel = itemModel.getModel(['emphasis', 'label']);
      var progressLabelModel = itemModel.getModel(['progress', 'label']);
      var tickCoord = axis.dataToCoord(labelItem.tickValue);
      var textEl = new graphic.Text({
        x: tickCoord,
        y: 0,
        rotation: layoutInfo.labelRotation - layoutInfo.rotation,
        onclick: bind(_this._changeTimeline, _this, dataIndex),
        silent: false,
        style: createTextStyle(normalLabelModel, {
          text: labelItem.formattedLabel,
          align: layoutInfo.labelAlign,
          verticalAlign: layoutInfo.labelBaseline
        })
      });
      textEl.ensureState('emphasis').style = createTextStyle(hoverLabelModel);
      textEl.ensureState('progress').style = createTextStyle(progressLabelModel);
      group.add(textEl);
      enableHoverEmphasis(textEl);
      labelDataIndexStore(textEl).dataIndex = dataIndex;

      _this._tickLabels.push(textEl);
    });
  };

  SliderTimelineView.prototype._renderControl = function (layoutInfo, group, axis, timelineModel) {
    var controlSize = layoutInfo.controlSize;
    var rotation = layoutInfo.rotation;
    var itemStyle = timelineModel.getModel('controlStyle').getItemStyle();
    var hoverStyle = timelineModel.getModel(['emphasis', 'controlStyle']).getItemStyle();
    var playState = timelineModel.getPlayState();
    var inverse = timelineModel.get('inverse', true);
    makeBtn(layoutInfo.nextBtnPosition, 'next', bind(this._changeTimeline, this, inverse ? '-' : '+'));
    makeBtn(layoutInfo.prevBtnPosition, 'prev', bind(this._changeTimeline, this, inverse ? '+' : '-'));
    makeBtn(layoutInfo.playPosition, playState ? 'stop' : 'play', bind(this._handlePlayClick, this, !playState), true);

    function makeBtn(position, iconName, onclick, willRotate) {
      if (!position) {
        return;
      }

      var iconSize = parsePercent(retrieve2(timelineModel.get(['controlStyle', iconName + 'BtnSize']), controlSize), controlSize);
      var rect = [0, -iconSize / 2, iconSize, iconSize];
      var btn = makeControlIcon(timelineModel, iconName + 'Icon', rect, {
        x: position[0],
        y: position[1],
        originX: controlSize / 2,
        originY: 0,
        rotation: willRotate ? -rotation : 0,
        rectHover: true,
        style: itemStyle,
        onclick: onclick
      });
      btn.ensureState('emphasis').style = hoverStyle;
      group.add(btn);
      enableHoverEmphasis(btn);
    }
  };

  SliderTimelineView.prototype._renderCurrentPointer = function (layoutInfo, group, axis, timelineModel) {
    var data = timelineModel.getData();
    var currentIndex = timelineModel.getCurrentIndex();
    var pointerModel = data.getItemModel(currentIndex).getModel('checkpointStyle');
    var me = this;
    var callback = {
      onCreate: function (pointer) {
        pointer.draggable = true;
        pointer.drift = bind(me._handlePointerDrag, me);
        pointer.ondragend = bind(me._handlePointerDragend, me);
        pointerMoveTo(pointer, me._progressLine, currentIndex, axis, timelineModel, true);
      },
      onUpdate: function (pointer) {
        pointerMoveTo(pointer, me._progressLine, currentIndex, axis, timelineModel);
      }
    }; // Reuse when exists, for animation and drag.

    this._currentPointer = giveSymbol(pointerModel, pointerModel, this._mainGroup, {}, this._currentPointer, callback);
  };

  SliderTimelineView.prototype._handlePlayClick = function (nextState) {
    this._clearTimer();

    this.api.dispatchAction({
      type: 'timelinePlayChange',
      playState: nextState,
      from: this.uid
    });
  };

  SliderTimelineView.prototype._handlePointerDrag = function (dx, dy, e) {
    this._clearTimer();

    this._pointerChangeTimeline([e.offsetX, e.offsetY]);
  };

  SliderTimelineView.prototype._handlePointerDragend = function (e) {
    this._pointerChangeTimeline([e.offsetX, e.offsetY], true);
  };

  SliderTimelineView.prototype._pointerChangeTimeline = function (mousePos, trigger) {
    var toCoord = this._toAxisCoord(mousePos)[0];

    var axis = this._axis;
    var axisExtent = numberUtil.asc(axis.getExtent().slice());
    toCoord > axisExtent[1] && (toCoord = axisExtent[1]);
    toCoord < axisExtent[0] && (toCoord = axisExtent[0]);
    this._currentPointer.x = toCoord;

    this._currentPointer.markRedraw();

    var progressLine = this._progressLine;

    if (progressLine) {
      progressLine.shape.x2 = toCoord;
      progressLine.dirty();
    }

    var targetDataIndex = this._findNearestTick(toCoord);

    var timelineModel = this.model;

    if (trigger || targetDataIndex !== timelineModel.getCurrentIndex() && timelineModel.get('realtime')) {
      this._changeTimeline(targetDataIndex);
    }
  };

  SliderTimelineView.prototype._doPlayStop = function () {
    var _this = this;

    this._clearTimer();

    if (this.model.getPlayState()) {
      this._timer = setTimeout(function () {
        // Do not cache
        var timelineModel = _this.model;

        _this._changeTimeline(timelineModel.getCurrentIndex() + (timelineModel.get('rewind', true) ? -1 : 1));
      }, this.model.get('playInterval'));
    }
  };

  SliderTimelineView.prototype._toAxisCoord = function (vertex) {
    var trans = this._mainGroup.getLocalTransform();

    return graphic.applyTransform(vertex, trans, true);
  };

  SliderTimelineView.prototype._findNearestTick = function (axisCoord) {
    var data = this.model.getData();
    var dist = Infinity;
    var targetDataIndex;
    var axis = this._axis;
    data.each(['value'], function (value, dataIndex) {
      var coord = axis.dataToCoord(value);
      var d = Math.abs(coord - axisCoord);

      if (d < dist) {
        dist = d;
        targetDataIndex = dataIndex;
      }
    });
    return targetDataIndex;
  };

  SliderTimelineView.prototype._clearTimer = function () {
    if (this._timer) {
      clearTimeout(this._timer);
      this._timer = null;
    }
  };

  SliderTimelineView.prototype._changeTimeline = function (nextIndex) {
    var currentIndex = this.model.getCurrentIndex();

    if (nextIndex === '+') {
      nextIndex = currentIndex + 1;
    } else if (nextIndex === '-') {
      nextIndex = currentIndex - 1;
    }

    this.api.dispatchAction({
      type: 'timelineChange',
      currentIndex: nextIndex,
      from: this.uid
    });
  };

  SliderTimelineView.prototype._updateTicksStatus = function () {
    var currentIndex = this.model.getCurrentIndex();
    var tickSymbols = this._tickSymbols;
    var tickLabels = this._tickLabels;

    if (tickSymbols) {
      for (var i = 0; i < tickSymbols.length; i++) {
        tickSymbols && tickSymbols[i] && tickSymbols[i].toggleState('progress', i < currentIndex);
      }
    }

    if (tickLabels) {
      for (var i = 0; i < tickLabels.length; i++) {
        tickLabels && tickLabels[i] && tickLabels[i].toggleState('progress', labelDataIndexStore(tickLabels[i]).dataIndex <= currentIndex);
      }
    }
  };

  SliderTimelineView.type = 'timeline.slider';
  return SliderTimelineView;
}(TimelineView);

function createScaleByModel(model, axisType) {
  axisType = axisType || model.get('type');

  if (axisType) {
    switch (axisType) {
      // Buildin scale
      case 'category':
        return new OrdinalScale({
          ordinalMeta: model.getCategories(),
          extent: [Infinity, -Infinity]
        });

      case 'time':
        return new TimeScale({
          locale: model.ecModel.getLocaleModel(),
          useUTC: model.ecModel.get('useUTC')
        });

      default:
        // default to be value
        return new IntervalScale();
    }
  }
}

function getViewRect(model, api) {
  return layout.getLayoutRect(model.getBoxLayoutParams(), {
    width: api.getWidth(),
    height: api.getHeight()
  }, model.get('padding'));
}

function makeControlIcon(timelineModel, objPath, rect, opts) {
  var style = opts.style;
  var icon = graphic.createIcon(timelineModel.get(['controlStyle', objPath]), opts || {}, new BoundingRect(rect[0], rect[1], rect[2], rect[3])); // TODO createIcon won't use style in opt.

  if (style) {
    icon.setStyle(style);
  }

  return icon;
}
/**
 * Create symbol or update symbol
 * opt: basic position and event handlers
 */


function giveSymbol(hostModel, itemStyleModel, group, opt, symbol, callback) {
  var color = itemStyleModel.get('color');

  if (!symbol) {
    var symbolType = hostModel.get('symbol');
    symbol = createSymbol(symbolType, -1, -1, 2, 2, color);
    symbol.setStyle('strokeNoScale', true);
    group.add(symbol);
    callback && callback.onCreate(symbol);
  } else {
    symbol.setColor(color);
    group.add(symbol); // Group may be new, also need to add.

    callback && callback.onUpdate(symbol);
  } // Style


  var itemStyle = itemStyleModel.getItemStyle(['color']);
  symbol.setStyle(itemStyle); // Transform and events.

  opt = merge({
    rectHover: true,
    z2: 100
  }, opt, true);
  var symbolSize = normalizeSymbolSize(hostModel.get('symbolSize'));
  opt.scaleX = symbolSize[0] / 2;
  opt.scaleY = symbolSize[1] / 2;
  var symbolOffset = normalizeSymbolOffset(hostModel.get('symbolOffset'), symbolSize);

  if (symbolOffset) {
    opt.x = (opt.x || 0) + symbolOffset[0];
    opt.y = (opt.y || 0) + symbolOffset[1];
  }

  var symbolRotate = hostModel.get('symbolRotate');
  opt.rotation = (symbolRotate || 0) * Math.PI / 180 || 0;
  symbol.attr(opt); // FIXME
  // (1) When symbol.style.strokeNoScale is true and updateTransform is not performed,
  // getBoundingRect will return wrong result.
  // (This is supposed to be resolved in zrender, but it is a little difficult to
  // leverage performance and auto updateTransform)
  // (2) All of ancesters of symbol do not scale, so we can just updateTransform symbol.

  symbol.updateTransform();
  return symbol;
}

function pointerMoveTo(pointer, progressLine, dataIndex, axis, timelineModel, noAnimation) {
  if (pointer.dragging) {
    return;
  }

  var pointerModel = timelineModel.getModel('checkpointStyle');
  var toCoord = axis.dataToCoord(timelineModel.getData().get('value', dataIndex));

  if (noAnimation || !pointerModel.get('animation', true)) {
    pointer.attr({
      x: toCoord,
      y: 0
    });
    progressLine && progressLine.attr({
      shape: {
        x2: toCoord
      }
    });
  } else {
    var animationCfg = {
      duration: pointerModel.get('animationDuration', true),
      easing: pointerModel.get('animationEasing', true)
    };
    pointer.stopAnimation(null, true);
    pointer.animateTo({
      x: toCoord,
      y: 0
    }, animationCfg);
    progressLine && progressLine.animateTo({
      shape: {
        x2: toCoord
      }
    }, animationCfg);
  }
}

export default SliderTimelineView;