Hui’s blog

Today is not easy, tomorrow is more difficult, but the day after tomorrow will be wonderful.

nvd3中计算坐标轴的nice domain

最近用nvd3以及angularjs-nvd3-directives做chart遇到一个问题,如下图,y轴中的最大值是3.8。nvd3只会在坐标轴显示到数据最大值,但是有些情况下最大值并不是很好看,我们需要在这种情况下显示4.0。

最开始查了下d3的文档,发现有个nice()方法可能会做到,但是尝试了下,不生效。查了下,可能是nvd3的bug。要控制坐标轴的显示还可以通过xDomain(),yDomain()来实现,关键问题是如何计算domain的nice值。

计算数据中的最小值,最大值

var yAxisValues = [1,2.4,3.6,7.8,9.2];
var yAxisMax = d3.max(yAxisValues)
var yAxisMin= d3.min(yAxisValues)

我们可以通过d3中提供的max方法得到数据中的最小值,最大值

根据给定的最小值和最大值计算出nice值

app.factory('niceScale', [function () {
        var factory = {};

        /// <summary>
        ///  Returns a "nice" number approximately equal to range Rounds
        ///  the number if round = true Takes the ceiling if round = false.
        /// </summary>
        /// <param name="range">the minimum data point on the axis</param>
        /// <param name="round">the maximum data point on the axis</param>
        function niceNum(range, round) {
            // exponent of range
            var exponent;
            // fractional part of range
            var fraction;
            // nice, rounded fraction
            var niceFraction;
            exponent = Math.floor(Math.log10(range));
            fraction = range / Math.pow(10, exponent);

            if (round) {
                if (fraction < 1.5) niceFraction = 1;
                else if (fraction < 3) niceFraction = 2;
                else if (fraction < 7) niceFraction = 5;
                else niceFraction = 10;
            } else {
                if (fraction <= 1) niceFraction = 1;
                else if (fraction <= 2) niceFraction = 2;
                else if (fraction <= 5) niceFraction = 5;
                else niceFraction = 10;
            }
            return niceFraction * Math.pow(10, exponent);
        }

        factory.calculate = function (min, max, maxTicks) {
            maxTicks = maxTicks ? maxTicks : 10;
            var range = niceNum(max - min, false);
            var tickSpacing = niceNum(range / (maxTicks - 1), true);
            var niceMin = Math.floor(min / tickSpacing) * tickSpacing;
            var niceMax = Math.ceil(max / tickSpacing) * tickSpacing;
            return [niceMin, niceMax];
        }

        return factory;
    }]);

上面定义了一个angular中的service用来处理算法

设置chart的domain

    chart.yDomain([niceMin,niceMax]);