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

    // 图形依赖
    var TextShape = require('zrender/shape/Text');
    var LineShape = require('zrender/shape/Line');
    var RectangleShape = require('zrender/shape/Rectangle');

    var ecConfig = require('../config');
    // 数值型坐标轴默认参数
    ecConfig.valueAxis = {
        zlevel: 0,                  // 一级层叠
        z: 0,                       // 二级层叠
        show: true,
        position: 'left',      // 位置
        name: '',              // 坐标轴名字，默认为空
        nameLocation: 'end',   // 坐标轴名字位置，支持'start' | 'end'
        nameTextStyle: {},     // 坐标轴文字样式，默认取全局样式
        boundaryGap: [0, 0],   // 数值起始和结束两端空白策略
        // min: null,          // 最小值
        // max: null,          // 最大值
        // scale: false,       // 脱离0值比例，放大聚焦到最终_min，_max区间
        // splitNumber: 5,        // 分割段数，默认为5
        axisLine: {            // 坐标轴线
            show: true,        // 默认显示，属性show控制显示与否
            onZero: true,
            lineStyle: {       // 属性lineStyle控制线条样式
                color: '#48b',
                width: 2,
                type: 'solid'
            }
        },
        axisTick: {            // 坐标轴小标记
            show: false,       // 属性show控制显示与否，默认不显示
            inside: false,     // 控制小标记是否在grid里
            length :5,         // 属性length控制线长
            lineStyle: {       // 属性lineStyle控制线条样式
                color: '#333',
                width: 1
            }
        },
        axisLabel: {           // 坐标轴文本标签，详见axis.axisLabel
            show: true,
            rotate: 0,
            margin: 8,
            // clickable: false,
            // formatter: null,
            textStyle: {       // 其余属性默认使用全局文本样式，详见TEXTSTYLE
                color: '#333'
            }
        },
        splitLine: {           // 分隔线
            show: true,        // 默认显示，属性show控制显示与否
            lineStyle: {       // 属性lineStyle（详见lineStyle）控制线条样式
                color: ['#ccc'],
                width: 1,
                type: 'solid'
            }
        },
        splitArea: {           // 分隔区域
            show: false,       // 默认不显示，属性show控制显示与否
            areaStyle: {       // 属性areaStyle（详见areaStyle）控制区域样式
                color: ['rgba(250,250,250,0.3)','rgba(200,200,200,0.3)']
            }
        }
    };

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

    /**
     * 构造函数
     * @param {Object} messageCenter echart消息中心
     * @param {ZRender} zr zrender实例
     * @param {Object} option 类目轴参数
     * @param {Object} component 组件
     * @param {Array} series 数据对象
     */
    function ValueAxis(ecTheme, messageCenter, zr, option, myChart, axisBase, series) {
        if (!series || series.length === 0) {
            console.err('option.series.length == 0.');
            return;
        }

        Base.call(this, ecTheme, messageCenter, zr, option, myChart);

        this.series = series;
        this.grid = this.component.grid;

        for (var method in axisBase) {
            this[method] = axisBase[method];
        }

        this.refresh(option, series);
    }

    ValueAxis.prototype = {
        type: ecConfig.COMPONENT_TYPE_AXIS_VALUE,

        _buildShape: function () {
            this._hasData = false;
            this._calculateValue();
            if (!this._hasData || !this.option.show) {
                return;
            }

            this.option.splitArea.show && this._buildSplitArea();
            this.option.splitLine.show && this._buildSplitLine();
            this.option.axisLine.show && this._buildAxisLine();
            this.option.axisTick.show && this._buildAxisTick();
            this.option.axisLabel.show && this._buildAxisLabel();

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

        // 小标记
        _buildAxisTick: function () {
            var axShape;
            var data       = this._valueList;
            var dataLength = this._valueList.length;
            var tickOption = this.option.axisTick;
            var length     = tickOption.length;
            var color      = tickOption.lineStyle.color;
            var lineWidth  = tickOption.lineStyle.width;

            if (this.isHorizontal()) {
                // 横向
                var yPosition = this.option.position === 'bottom'
                        ? (tickOption.inside
                           ? (this.grid.getYend() - length - 1) : (this.grid.getYend()) + 1)
                        : (tickOption.inside
                           ? (this.grid.getY() + 1) : (this.grid.getY() - length - 1));
                var x;
                for (var i = 0; i < dataLength; i++) {
                    // 亚像素优化
                    x = this.subPixelOptimize(this.getCoord(data[i]), lineWidth);
                    axShape = {
                        _axisShape: 'axisTick',
                        zlevel: this.getZlevelBase(),
                        z: this.getZBase(),
                        hoverable: false,
                        style: {
                            xStart: x,
                            yStart: yPosition,
                            xEnd: x,
                            yEnd: yPosition + length,
                            strokeColor: color,
                            lineWidth: lineWidth
                        }
                    };
                    this.shapeList.push(new LineShape(axShape));
                }
            }
            else {
                // 纵向
                var xPosition = this.option.position === 'left'
                    ? (tickOption.inside
                       ? (this.grid.getX() + 1) : (this.grid.getX() - length - 1))
                    : (tickOption.inside
                       ? (this.grid.getXend() - length - 1) : (this.grid.getXend() + 1));

                var y;
                for (var i = 0; i < dataLength; i++) {
                    // 亚像素优化
                    y = this.subPixelOptimize(this.getCoord(data[i]), lineWidth);
                    axShape = {
                        _axisShape: 'axisTick',
                        zlevel: this.getZlevelBase(),
                        z: this.getZBase(),
                        hoverable: false,
                        style: {
                            xStart: xPosition,
                            yStart: y,
                            xEnd: xPosition + length,
                            yEnd: y,
                            strokeColor: color,
                            lineWidth: lineWidth
                        }
                    };
                    this.shapeList.push(new LineShape(axShape));
                }
            }
        },

        // 坐标轴文本
        _buildAxisLabel: function () {
            var axShape;
            var data       = this._valueList;
            var dataLength = this._valueList.length;
            var rotate     = this.option.axisLabel.rotate;
            var margin     = this.option.axisLabel.margin;
            var clickable  = this.option.axisLabel.clickable;
            var textStyle  = this.option.axisLabel.textStyle;

            if (this.isHorizontal()) {
                // 横向
                var yPosition;
                var baseLine;
                if (this.option.position === 'bottom') {
                    yPosition = this.grid.getYend() + margin;
                    baseLine = 'top';
                }
                else {
                    yPosition = this.grid.getY() - margin;
                    baseLine = 'bottom';
                }

                for (var i = 0; i < dataLength; i++) {
                    axShape = {
                        zlevel: this.getZlevelBase(),
                        z: this.getZBase() +3,
                        hoverable: false,
                        style: {
                            x: this.getCoord(data[i]),
                            y: yPosition,
                            color: typeof textStyle.color === 'function'
                                   ? textStyle.color(data[i]) : textStyle.color,
                            text: this._valueLabel[i],
                            textFont: this.getFont(textStyle),
                            textAlign: textStyle.align || 'center',
                            textBaseline: textStyle.baseline || baseLine
                        }
                    };
                    if (rotate) {
                        axShape.style.textAlign = rotate > 0
                                                  ? (this.option.position === 'bottom'
                                                    ? 'right' : 'left')
                                                  : (this.option.position === 'bottom'
                                                    ? 'left' : 'right');
                        axShape.rotation = [
                            rotate * Math.PI / 180,
                            axShape.style.x,
                            axShape.style.y
                        ];
                    }
                    this.shapeList.push(new TextShape(
                        this._axisLabelClickable(clickable, axShape)
                    ));
                }
            }
            else {
                // 纵向
                var xPosition;
                var align;
                if (this.option.position === 'left') {
                    xPosition = this.grid.getX() - margin;
                    align = 'right';
                }
                else {
                    xPosition = this.grid.getXend() + margin;
                    align = 'left';
                }

                for (var i = 0; i < dataLength; i++) {
                    axShape = {
                        zlevel: this.getZlevelBase(),
                        z: this.getZBase() + 3,
                        hoverable: false,
                        style: {
                            x: xPosition,
                            y: this.getCoord(data[i]),
                            color: typeof textStyle.color === 'function'
                                   ? textStyle.color(data[i]) : textStyle.color,
                            text: this._valueLabel[i],
                            textFont: this.getFont(textStyle),
                            textAlign: textStyle.align || align,
                            textBaseline: textStyle.baseline
                                          || (
                                              (i === 0 && this.option.name !== '')
                                              ? 'bottom'
                                                : (i === dataLength - 1 && this.option.name !== '') ? 'top' : 'middle'
                                          )
                        }
                    };

                    if (rotate) {
                        axShape.rotation = [
                            rotate * Math.PI / 180,
                            axShape.style.x,
                            axShape.style.y
                        ];
                    }
                    this.shapeList.push(new TextShape(
                        this._axisLabelClickable(clickable, axShape)
                    ));
                }
            }
        },

        _buildSplitLine: function () {
            var axShape;
            var data        = this._valueList;
            var dataLength  = this._valueList.length;
            var sLineOption = this.option.splitLine;
            var lineType    = sLineOption.lineStyle.type;
            var lineWidth   = sLineOption.lineStyle.width;
            var color       = sLineOption.lineStyle.color;
            color = color instanceof Array ? color : [color];
            var colorLength = color.length;

            if (this.isHorizontal()) {
                // 横向
                var sy = this.grid.getY();
                var ey = this.grid.getYend();
                var x;

                for (var i = 0; i < dataLength; i++) {
                    // 亚像素优化
                    x = this.subPixelOptimize(this.getCoord(data[i]), lineWidth);
                    axShape = {
                        zlevel: this.getZlevelBase(),
                        z: this.getZBase(),
                        hoverable: false,
                        style: {
                            xStart: x,
                            yStart: sy,
                            xEnd: x,
                            yEnd: ey,
                            strokeColor: color[i % colorLength],
                            lineType: lineType,
                            lineWidth: lineWidth
                        }
                    };
                    this.shapeList.push(new LineShape(axShape));
                }

            }
            else {
                // 纵向
                var sx = this.grid.getX();
                var ex = this.grid.getXend();
                var y;

                for (var i = 0; i < dataLength; i++) {
                    // 亚像素优化
                    y = this.subPixelOptimize(this.getCoord(data[i]), lineWidth);
                    axShape = {
                        zlevel: this.getZlevelBase(),
                        z: this.getZBase(),
                        hoverable: false,
                        style: {
                            xStart: sx,
                            yStart: y,
                            xEnd: ex,
                            yEnd: y,
                            strokeColor: color[i % colorLength],
                            lineType: lineType,
                            lineWidth: lineWidth
                        }
                    };
                    this.shapeList.push(new LineShape(axShape));
                }
            }
        },

        _buildSplitArea: function () {
            var axShape;
            var color = this.option.splitArea.areaStyle.color;

            if (!(color instanceof Array)) {
                // 非数组一律认为是单一颜色的字符串，单一颜色则用一个背景，颜色错误不负责啊！！！
                axShape = {
                    zlevel: this.getZlevelBase(),
                    z: this.getZBase(),
                    hoverable: false,
                    style: {
                        x: this.grid.getX(),
                        y: this.grid.getY(),
                        width: this.grid.getWidth(),
                        height: this.grid.getHeight(),
                        color: color
                        // type: this.option.splitArea.areaStyle.type,
                    }
                };
                this.shapeList.push(new RectangleShape(axShape));
            }
            else {
                // 多颜色
                var colorLength = color.length;
                var data        = this._valueList;
                var dataLength  = this._valueList.length;

                if (this.isHorizontal()) {
                    // 横向
                    var y = this.grid.getY();
                    var height = this.grid.getHeight();
                    var lastX = this.grid.getX();
                    var curX;

                    for (var i = 0; i <= dataLength; i++) {
                        curX = i < dataLength
                               ? this.getCoord(data[i])
                               : this.grid.getXend();
                        axShape = {
                            zlevel: this.getZlevelBase(),
                            z: this.getZBase(),
                            hoverable: false,
                            style: {
                                x: lastX,
                                y: y,
                                width: curX - lastX,
                                height: height,
                                color: color[i % colorLength]
                                // type: this.option.splitArea.areaStyle.type,
                            }
                        };
                        this.shapeList.push(new RectangleShape(axShape));
                        lastX = curX;
                    }
                }
                else {
                    // 纵向
                    var x = this.grid.getX();
                    var width = this.grid.getWidth();
                    var lastYend = this.grid.getYend();
                    var curY;

                    for (var i = 0; i <= dataLength; i++) {
                        curY = i < dataLength
                               ? this.getCoord(data[i])
                               : this.grid.getY();
                        axShape = {
                            zlevel: this.getZlevelBase(),
                            z: this.getZBase(),
                            hoverable: false,
                            style: {
                                x: x,
                                y: curY,
                                width: width,
                                height: lastYend - curY,
                                color: color[i % colorLength]
                                // type: this.option.splitArea.areaStyle.type
                            }
                        };
                        this.shapeList.push(new RectangleShape(axShape));
                        lastYend = curY;
                    }
                }
            }
        },

        /**
         * 极值计算
         */
        _calculateValue: function () {
            if (isNaN(this.option.min - 0) || isNaN(this.option.max - 0)) {
                // 有一个没指定都得算
                // 数据整形
                var data = {};          // 整形后数据抽取
                var xIdx;
                var yIdx;
                var legend = this.component.legend;
                for (var i = 0, l = this.series.length; i < l; i++) {
                    if (this.series[i].type != ecConfig.CHART_TYPE_LINE
                        && this.series[i].type != ecConfig.CHART_TYPE_BAR
                        && this.series[i].type != ecConfig.CHART_TYPE_SCATTER
                        && this.series[i].type != ecConfig.CHART_TYPE_K
                        && this.series[i].type != ecConfig.CHART_TYPE_EVENTRIVER
                    ) {
                        // 非坐标轴支持的不算极值
                        continue;
                    }
                    // 请允许我写开，跟上面一个不是一样东西
                    if (legend && !legend.isSelected(this.series[i].name)){
                        continue;
                    }

                    // 不指定默认为第一轴线
                    xIdx = this.series[i].xAxisIndex || 0;
                    yIdx = this.series[i].yAxisIndex || 0;
                    if ((this.option.xAxisIndex != xIdx)
                        && (this.option.yAxisIndex != yIdx)
                    ) {
                        // 不是自己的数据不计算极值
                        continue;
                    }

                    this._calculSum(data, i);
                }

                // 找极值
                var oriData;            // 原始数据
                for (var i in data){
                    oriData = data[i];
                    for (var j = 0, k = oriData.length; j < k; j++) {
                        if (!isNaN(oriData[j])){
                            this._hasData = true;
                            this._min = oriData[j];
                            this._max = oriData[j];
                            break;
                        }
                    }
                    if (this._hasData) {
                        break;
                    }
                }
                for (var i in data){
                    oriData = data[i];
                    for (var j = 0, k = oriData.length; j < k; j++) {
                        if (!isNaN(oriData[j])){
                            this._min = Math.min(this._min, oriData[j]);
                            this._max = Math.max(this._max, oriData[j]);
                        }
                    }
                }

                // console.log(this._min,this._max,'vvvvv111111',this.option.type)
                // log情况暂时禁用boundaryGap。
                var boundaryGap = this.option.type !== 'log' ? this.option.boundaryGap : [0, 0];
                var gap = Math.abs(this._max - this._min);
                this._min = isNaN(this.option.min - 0)
                       ? (this._min - Math.abs(gap * boundaryGap[0]))
                       : (this.option.min - 0);    // 指定min忽略boundaryGay[0]

                this._max = isNaN(this.option.max - 0)
                       ? (this._max + Math.abs(gap * boundaryGap[1]))
                       : (this.option.max - 0);    // 指定max忽略boundaryGay[1]
                if (this._min === this._max) {
                    if (this._max === 0) {
                        // 修复全0数据
                        this._max = 1;
                    }
                    // 修复最大值==最小值时数据整形
                    else if (this._max > 0) {
                        this._min = this._max / this.option.splitNumber != null ? this.option.splitNumber : 5;
                    }
                    else { // this._max < 0
                        this._max = this._max / this.option.splitNumber != null ? this.option.splitNumber : 5;
                    }
                }

                if (this.option.type === 'time') {
                    this._reformTimeValue();
                }
                else if (this.option.type === 'log') {
                    this._reformLogValue();
                }
                else {
                    this._reformValue(this.option.scale);
                }
            }
            else {
                this._hasData = true;
                // 用户指定min max就不多管闲事了
                this._min = this.option.min - 0;    // 指定min忽略boundaryGay[0]
                this._max = this.option.max - 0;    // 指定max忽略boundaryGay[1]

                if (this.option.type === 'time') {
                    this._reformTimeValue();
                }
                else if (this.option.type === 'log') {
                    this._reformLogValue();
                }
                else {
                    this._customerValue();
                }
            }
        },

        /**
         * 内部使用，计算某系列下的堆叠和
         */
        _calculSum: function (data, i) {
            var key = this.series[i].name || 'kener';
            var value;
            var oriData;
            if (!this.series[i].stack) {
                data[key] = data[key] || [];
                if (this.series[i].type != ecConfig.CHART_TYPE_EVENTRIVER) {
                    oriData = this.series[i].data;
                    for (var j = 0, k = oriData.length; j < k; j++) {
                        value = this.getDataFromOption(oriData[j]);
                        if (this.series[i].type === ecConfig.CHART_TYPE_K) {
                            data[key].push(value[0]);
                            data[key].push(value[1]);
                            data[key].push(value[2]);
                            data[key].push(value[3]);
                        }
                        else if (value instanceof Array) {
                            // scatter 、 不等距 line bar
                            if (this.option.xAxisIndex != -1) {
                                data[key].push(
                                    this.option.type != 'time'
                                    ? value[0] : ecDate.getNewDate(value[0])
                                );
                            }
                            if (this.option.yAxisIndex != -1) {
                                data[key].push(
                                    this.option.type != 'time'
                                    ? value[1] : ecDate.getNewDate(value[1])
                                );
                            }
                        }
                        else {
                            data[key].push(value);
                        }
                    }
                }
                else {
                    // eventRiver
                    oriData = this.series[i].data;
                    for (var j = 0, k = oriData.length; j < k; j++) {
                        var evolution = oriData[j].evolution;
                        for (var m = 0, n = evolution.length; m < n; m++) {
                            data[key].push(ecDate.getNewDate(evolution[m].time));
                        }
                    }
                }
            }
            else {
                // 堆积数据，需要区分正负向堆积
                var keyP = '__Magic_Key_Positive__' + this.series[i].stack;
                var keyN = '__Magic_Key_Negative__' + this.series[i].stack;
                data[keyP] = data[keyP] || [];
                data[keyN] = data[keyN] || [];
                data[key] = data[key] || [];  // scale下还需要记录每一个量
                oriData = this.series[i].data;
                for (var j = 0, k = oriData.length; j < k; j++) {
                    value = this.getDataFromOption(oriData[j]);
                    if (value === '-') {
                        continue;
                    }
                    value = value - 0;
                    if (value >= 0) {
                        if (data[keyP][j] != null) {
                            data[keyP][j] += value;
                        }
                        else {
                            data[keyP][j] = value;
                        }
                    }
                    else {
                        if (data[keyN][j] != null) {
                            data[keyN][j] += value;
                        }
                        else {
                            data[keyN][j] = value;
                        }
                    }
                    if (this.option.scale) {
                        data[key].push(value);
                    }
                }
            }
        },

        /**
         * 找到原始数据的极值后根据选项整形最终 this._min / this._max / this._valueList
         * 如果你不知道这个“整形”的用义，请不要试图去理解和修改这个方法！找我也没用，我相信我已经记不起来！
         * 如果你有更简洁的数学推导欢迎重写，后果自负~
         *
         * by kener.linfeng@gmail.com 2013-1-8
         * --------
         * 感谢谢世威(https://github.com/i6ma)，终于有人改这个方法了
         * by Kener 2014-11-6
         */
        _reformValue: function (scale) {
            var smartSteps = require('../util/smartSteps');
            var splitNumber = this.option.splitNumber;

            // 非scale下双正，修正最小值为0
            if (!scale && this._min >= 0 && this._max >= 0) {
                this._min = 0;
            }
            // 非scale下双负，修正最大值为0
            if (!scale && this._min <= 0 && this._max <= 0) {
                this._max = 0;
            }

            var stepOpt = smartSteps(this._min, this._max, splitNumber);
            splitNumber = splitNumber != null ? splitNumber : stepOpt.secs;
            //this.option.splitNumber = splitNumber;
            this._min = stepOpt.min;
            this._max = stepOpt.max;
            this._valueList = stepOpt.pnts;
            this._reformLabelData();
        },

        /**
         * 格式化时间值
         */
        _reformTimeValue : function() {
            var splitNumber = this.option.splitNumber != null ? this.option.splitNumber : 5;

            // 最优解
            var curValue = ecDate.getAutoFormatter(this._min, this._max, splitNumber);
            // 目标
            var formatter = curValue.formatter;
            var gapValue = curValue.gapValue;

            this._valueList = [ecDate.getNewDate(this._min)];
            var startGap;
            switch (formatter) {
                case 'week' :
                    startGap = ecDate.nextMonday(this._min);
                    break;
                case 'month' :
                    startGap = ecDate.nextNthOnMonth(this._min, 1);
                    break;
                case 'quarter' :
                    startGap = ecDate.nextNthOnQuarterYear(this._min, 1);
                    break;
                case 'half-year' :
                    startGap = ecDate.nextNthOnHalfYear(this._min, 1);
                    break;
                case 'year' :
                    startGap = ecDate.nextNthOnYear(this._min, 1);
                    break;
                default :
                    // 大于2小时需要考虑时区不能直接取整
                    if (gapValue <= 3600000 * 2) {
                        startGap = (Math.floor(this._min / gapValue) + 1) * gapValue;
                    }
                    else {
                        startGap = ecDate.getNewDate(this._min - (-gapValue));
                        startGap.setHours(Math.round(startGap.getHours() / 6) * 6);
                        startGap.setMinutes(0);
                        startGap.setSeconds(0);
                    }
                    break;
            }

            if (startGap - this._min < gapValue / 2) {
                startGap -= -gapValue;
            }

            // console.log(startGap,gapValue,this._min, this._max,formatter)
            curValue = ecDate.getNewDate(startGap);
            splitNumber *= 1.5;
            while (splitNumber-- >= 0) {
                if (formatter == 'month'
                    || formatter == 'quarter'
                    || formatter == 'half-year'
                    || formatter == 'year'
                ) {
                    curValue.setDate(1);
                }
                if (this._max - curValue < gapValue / 2) {
                    break;
                }
                this._valueList.push(curValue);
                curValue = ecDate.getNewDate(curValue - (-gapValue));
            }
            this._valueList.push(ecDate.getNewDate(this._max));

            this._reformLabelData((function (formatterStr) {
                return function (value) {
                    return ecDate.format(formatterStr, value);
                };
            })(formatter));
        },

        _customerValue: function () {
            var accMath = require('../util/accMath');
            var splitNumber = this.option.splitNumber != null ? this.option.splitNumber : 5;
            var splitGap = (this._max - this._min) / splitNumber;

            this._valueList = [];
            for (var i = 0; i <= splitNumber; i++) {
                this._valueList.push(accMath.accAdd(this._min, accMath.accMul(splitGap, i)));
            }
            this._reformLabelData();
        },

        _reformLogValue: function() {
            // log数轴本质就是缩放，相当于默认this.option.scale === true，所以不修正_min和_max到0。
            var thisOption = this.option;
            var result = require('../util/smartLogSteps')({
                dataMin: this._min,
                dataMax: this._max,
                logPositive: thisOption.logPositive,
                logLabelBase: thisOption.logLabelBase,
                splitNumber: thisOption.splitNumber
            });

            this._min = result.dataMin;
            this._max = result.dataMax;
            this._valueList = result.tickList;
            // {value2Coord: {Function}, coord2Value: {Function}}
            this._dataMappingMethods = result.dataMappingMethods;

            this._reformLabelData(result.labelFormatter);
        },

        _reformLabelData: function (innerFormatter) {
            this._valueLabel = [];
            var formatter = this.option.axisLabel.formatter;
            if (formatter) {
                for (var i = 0, l = this._valueList.length; i < l; i++) {
                    if (typeof formatter === 'function') {
                        this._valueLabel.push(
                            innerFormatter
                                ? formatter.call(this.myChart, this._valueList[i], innerFormatter)
                                : formatter.call(this.myChart, this._valueList[i])
                        );
                    }
                    else if (typeof formatter === 'string') {
                        this._valueLabel.push(
                            innerFormatter
                                ? ecDate.format(formatter, this._valueList[i])
                                : formatter.replace('{value}',this._valueList[i])
                        );
                    }
                }
            }
            else {
                for (var i = 0, l = this._valueList.length; i < l; i++) {
                    this._valueLabel.push(
                        innerFormatter
                            ? innerFormatter(this._valueList[i])
                            : this.numAddCommas(this._valueList[i]) // 每三位默认加,格式化
                    );
                }
            }
        },

        getExtremum: function () {
            this._calculateValue();
            var dataMappingMethods = this._dataMappingMethods;
            return {
                min: this._min,
                max: this._max,
                dataMappingMethods: dataMappingMethods
                    ? zrUtil.merge({}, dataMappingMethods) : null
            };
        },

        /**
         * 刷新
         */
        refresh: function (newOption, newSeries) {
            if (newOption) {
                this.option = this.reformOption(newOption);
                // 通用字体设置
                this.option.axisLabel.textStyle = zrUtil.merge(
                    this.option.axisLabel.textStyle || {},
                    this.ecTheme.textStyle
                );
                this.series = newSeries;
            }
            if (this.zr) {   // 数值轴的另外一个功能只是用来计算极值
                this.clear();
                this._buildShape();
            }
        },

        // 根据值换算位置
        getCoord: function (value) {
            if (this._dataMappingMethods) {
                value = this._dataMappingMethods.value2Coord(value);
            }

            value = value < this._min ? this._min : value;
            value = value > this._max ? this._max : value;

            var result;
            if (!this.isHorizontal()) {
                // 纵向
                result = this.grid.getYend()
                         - (value - this._min)
                           / (this._max - this._min)
                           * this.grid.getHeight();
            }
            else {
                // 横向
                result = this.grid.getX()
                         + (value - this._min)
                           / (this._max - this._min)
                           * this.grid.getWidth();
            }

            return result;
            // Math.floor可能引起一些偏差，但性能会更好
            /* 准确更重要
            return (value === this._min || value === this._max)
                   ? result
                   : Math.floor(result);
            */
        },

        // 根据值换算绝对大小
        getCoordSize: function (value) {
            if (!this.isHorizontal()) {
                // 纵向
                return Math.abs(value / (this._max - this._min) * this.grid.getHeight());
            }
            else {
                // 横向
                return Math.abs(value / (this._max - this._min) * this.grid.getWidth());
            }
        },

        // 根据位置换算值
        getValueFromCoord: function(coord) {
            var result;

            if (!this.isHorizontal()) {
                // 纵向
                coord = coord < this.grid.getY() ? this.grid.getY() : coord;
                coord = coord > this.grid.getYend() ? this.grid.getYend() : coord;
                result = this._max
                         - (coord - this.grid.getY())
                           / this.grid.getHeight()
                           * (this._max - this._min);
            }
            else {
                // 横向
                coord = coord < this.grid.getX() ? this.grid.getX() : coord;
                coord = coord > this.grid.getXend() ? this.grid.getXend() : coord;
                result = this._min
                         + (coord - this.grid.getX())
                           / this.grid.getWidth()
                           * (this._max - this._min);
            }

            if (this._dataMappingMethods) {
                result = this._dataMappingMethods.coord2Value(result);
            }

            return result.toFixed(2) - 0;
        },

        isMaindAxis : function (value) {
            for (var i = 0, l = this._valueList.length; i < l; i++) {
                if (this._valueList[i] === value) {
                    return true;
                }
            }
            return false;
        }
    };

    zrUtil.inherits(ValueAxis, Base);

    require('../component').define('valueAxis', ValueAxis);

    return ValueAxis;
});

