API Docs for: 3.8.0
Show:

File: charts/js/NumericAxis.js

  1. /**
  2.  * NumericAxis manages numeric data on an axis.
  3.  *
  4.  * @module charts
  5.  * @submodule charts-base
  6.  * @class NumericAxis
  7.  * @constructor
  8.  * @param {Object} config (optional) Configuration parameters for the Chart.
  9.  * @extends AxisType
  10.  */
  11. function NumericAxis(config)
  12. {
  13.         NumericAxis.superclass.constructor.apply(this, arguments);
  14. }

  15. NumericAxis.NAME = "numericAxis";

  16. NumericAxis.ATTRS = {
  17.     /**
  18.      * Indicates whether 0 should always be displayed.
  19.      *
  20.      * @attribute alwaysShowZero
  21.      * @type Boolean
  22.      */
  23.         alwaysShowZero: {
  24.             value: true
  25.         },

  26.     /**
  27.      * Method used for formatting a label. This attribute allows for the default label formatting method to overridden.
  28.      * The method use would need to implement the arguments below and return a `String` or an `HTMLElement`. The default
  29.      * implementation of the method returns a `String`. The output of this method will be rendered to the DOM using
  30.      * `appendChild`. If you override the `labelFunction` method and return an html string, you will also need to override
  31.      * the Axis' `appendLabelFunction` to accept html as a `String`.
  32.      * <dl>
  33.      *      <dt>val</dt><dd>Label to be formatted. (`String`)</dd>
  34.      *      <dt>format</dt><dd>Object containing properties used to format the label. (optional)</dd>
  35.      * </dl>
  36.      *
  37.      * @attribute labelFunction
  38.      * @type Function
  39.      */
  40.     labelFunction: {
  41.         value: function(val, format)
  42.         {
  43.             if(format)
  44.             {
  45.                 return Y.DataType.Number.format(val, format);
  46.             }
  47.             return val;
  48.         }
  49.     },

  50.     /**
  51.      * Object containing properties used by the `labelFunction` to format a
  52.      * label.
  53.      *
  54.      * @attribute labelFormat
  55.      * @type Object
  56.      */
  57.     labelFormat: {
  58.         value: {
  59.             prefix: "",
  60.             thousandsSeparator: "",
  61.             decimalSeparator: "",
  62.             decimalPlaces: "0",
  63.             suffix: ""
  64.         }
  65.     }
  66. };

  67. Y.extend(NumericAxis, Y.AxisType,
  68. {
  69.     /**
  70.      * Formats a label based on the axis type and optionally specified format.
  71.      *
  72.      * @method formatLabel
  73.      * @param {Object} value
  74.      * @param {Object} format Pattern used to format the value.
  75.      * @return String
  76.      */
  77.     formatLabel: function(val, format)
  78.     {
  79.         if(format)
  80.         {
  81.             return Y.DataType.Number.format(val, format);
  82.         }
  83.         return val;
  84.     },

  85.     /**
  86.      * Returns the sum of all values per key.
  87.      *
  88.      * @method getTotalByKey
  89.      * @param {String} key The identifier for the array whose values will be calculated.
  90.      * @return Number
  91.      */
  92.     getTotalByKey: function(key)
  93.     {
  94.         var total = 0,
  95.             values = this.getDataByKey(key),
  96.             i = 0,
  97.             val,
  98.             len = values ? values.length : 0;
  99.         for(; i < len; ++i)
  100.         {
  101.            val = parseFloat(values[i]);
  102.            if(!isNaN(val))
  103.            {
  104.                 total += val;
  105.            }
  106.         }
  107.         return total;
  108.     },

  109.     /**
  110.      * Type of data used in `Axis`.
  111.      *
  112.      * @property _type
  113.      * @readOnly
  114.      * @private
  115.      */
  116.     _type: "numeric",

  117.     /**
  118.      * Helper method for getting a `roundingUnit` when calculating the minimum and maximum values.
  119.      *
  120.      * @method _getMinimumUnit
  121.      * @param {Number} max Maximum number
  122.      * @param {Number} min Minimum number
  123.      * @param {Number} units Number of units on the axis
  124.      * @return Number
  125.      * @private
  126.      */
  127.     _getMinimumUnit:function(max, min, units)
  128.     {
  129.         return this._getNiceNumber(Math.ceil((max - min)/units));
  130.     },

  131.     /**
  132.      * Calculates a nice rounding unit based on the range.
  133.      *
  134.      * @method _getNiceNumber
  135.      * @param {Number} roundingUnit The calculated rounding unit.
  136.      * @return Number
  137.      * @private
  138.      */
  139.     _getNiceNumber: function(roundingUnit)
  140.     {
  141.         var tempMajorUnit = roundingUnit,
  142.             order = Math.ceil(Math.log(tempMajorUnit) * 0.4342944819032518),
  143.             roundedMajorUnit = Math.pow(10, order),
  144.             roundedDiff;

  145.         if (roundedMajorUnit / 2 >= tempMajorUnit)
  146.         {
  147.             roundedDiff = Math.floor((roundedMajorUnit / 2 - tempMajorUnit) / (Math.pow(10,order-1)/2));
  148.             tempMajorUnit = roundedMajorUnit/2 - roundedDiff*Math.pow(10,order-1)/2;
  149.         }
  150.         else
  151.         {
  152.             tempMajorUnit = roundedMajorUnit;
  153.         }
  154.         if(!isNaN(tempMajorUnit))
  155.         {
  156.             return tempMajorUnit;
  157.         }
  158.         return roundingUnit;

  159.     },

  160.     /**
  161.      * Calculates the maximum and minimum values for the `Axis`.
  162.      *
  163.      * @method _updateMinAndMax
  164.      * @private
  165.      */
  166.     _updateMinAndMax: function()
  167.     {
  168.         var data = this.get("data"),
  169.             max,
  170.             min,
  171.             len,
  172.             num,
  173.             i = 0,
  174.             key,
  175.             setMax = this.get("setMax"),
  176.             setMin = this.get("setMin");
  177.         if(!setMax || !setMin)
  178.         {
  179.             if(data && data.length && data.length > 0)
  180.             {
  181.                 len = data.length;
  182.                 for(; i < len; i++)
  183.                 {
  184.                     num = data[i];
  185.                     if(isNaN(num))
  186.                     {
  187.                         if(Y_Lang.isObject(num))
  188.                         {
  189.                             min = max = 0;
  190.                             //hloc values
  191.                             for(key in num)
  192.                             {
  193.                                if(num.hasOwnProperty(key))
  194.                                {
  195.                                     max = Math.max(num[key], max);
  196.                                     min = Math.min(num[key], min);
  197.                                }
  198.                             }
  199.                         }
  200.                         max = setMax ? this._setMaximum : max;
  201.                         min = setMin ? this._setMinimum : min;
  202.                         continue;
  203.                     }

  204.                     if(setMin)
  205.                     {
  206.                         min = this._setMinimum;
  207.                     }
  208.                     else if(min === undefined)
  209.                     {
  210.                         min = num;
  211.                     }
  212.                     else
  213.                     {
  214.                         min = Math.min(num, min);
  215.                     }
  216.                     if(setMax)
  217.                     {
  218.                         max = this._setMaximum;
  219.                     }
  220.                     else if(max === undefined)
  221.                     {
  222.                         max = num;
  223.                     }
  224.                     else
  225.                     {
  226.                         max = Math.max(num, max);
  227.                     }

  228.                     this._actualMaximum = max;
  229.                     this._actualMinimum = min;
  230.                 }
  231.             }
  232.             this._roundMinAndMax(min, max, setMin, setMax);
  233.         }
  234.     },

  235.     /**
  236.      * Rounds the mimimum and maximum values based on the `roundingUnit` attribute.
  237.      *
  238.      * @method _roundMinAndMax
  239.      * @param {Number} min Minimum value
  240.      * @param {Number} max Maximum value
  241.      * @private
  242.      */
  243.     _roundMinAndMax: function(min, max, setMin, setMax)
  244.     {
  245.         var roundingUnit,
  246.             minimumRange,
  247.             minGreaterThanZero = min >= 0,
  248.             maxGreaterThanZero = max > 0,
  249.             dataRangeGreater,
  250.             maxRound,
  251.             minRound,
  252.             topTicks,
  253.             botTicks,
  254.             tempMax,
  255.             tempMin,
  256.             units = this.getTotalMajorUnits() - 1,
  257.             alwaysShowZero = this.get("alwaysShowZero"),
  258.             roundingMethod = this.get("roundingMethod"),
  259.             useIntegers = (max - min)/units >= 1;
  260.         if(roundingMethod)
  261.         {
  262.             if(roundingMethod == "niceNumber")
  263.             {
  264.                 roundingUnit = this._getMinimumUnit(max, min, units);
  265.                 if(minGreaterThanZero && maxGreaterThanZero)
  266.                 {
  267.                     if((alwaysShowZero || min < roundingUnit) && !setMin)
  268.                     {
  269.                         min = 0;
  270.                         roundingUnit = this._getMinimumUnit(max, min, units);
  271.                     }
  272.                     else
  273.                     {
  274.                        min = this._roundDownToNearest(min, roundingUnit);
  275.                     }
  276.                     if(setMax)
  277.                     {
  278.                         if(!alwaysShowZero)
  279.                         {
  280.                             min = max - (roundingUnit * units);
  281.                         }
  282.                     }
  283.                     else if(setMin)
  284.                     {
  285.                         max = min + (roundingUnit * units);
  286.                     }
  287.                     else
  288.                     {
  289.                         max = this._roundUpToNearest(max, roundingUnit);
  290.                     }
  291.                 }
  292.                 else if(maxGreaterThanZero && !minGreaterThanZero)
  293.                 {
  294.                     if(alwaysShowZero)
  295.                     {
  296.                         topTicks = Math.round(units/((-1 * min)/max + 1));
  297.                         topTicks = Math.max(Math.min(topTicks, units - 1), 1);
  298.                         botTicks = units - topTicks;
  299.                         tempMax = Math.ceil( max/topTicks );
  300.                         tempMin = Math.floor( min/botTicks ) * -1;

  301.                         if(setMin)
  302.                         {
  303.                             while(tempMin < tempMax && botTicks >= 0)
  304.                             {
  305.                                 botTicks--;
  306.                                 topTicks++;
  307.                                 tempMax = Math.ceil( max/topTicks );
  308.                                 tempMin = Math.floor( min/botTicks ) * -1;
  309.                             }
  310.                             //if there are any bottom ticks left calcualate the maximum by multiplying by the tempMin value
  311.                             //if not, it's impossible to ensure that a zero is shown. skip it
  312.                             if(botTicks > 0)
  313.                             {
  314.                                 max = tempMin * topTicks;
  315.                             }
  316.                             else
  317.                             {
  318.                                 max = min + (roundingUnit * units);
  319.                             }
  320.                         }
  321.                         else if(setMax)
  322.                         {
  323.                             while(tempMax < tempMin && topTicks >= 0)
  324.                             {
  325.                                 botTicks++;
  326.                                 topTicks--;
  327.                                 tempMin = Math.floor( min/botTicks ) * -1;
  328.                                 tempMax = Math.ceil( max/topTicks );
  329.                             }
  330.                             //if there are any top ticks left calcualate the minimum by multiplying by the tempMax value
  331.                             //if not, it's impossible to ensure that a zero is shown. skip it
  332.                             if(topTicks > 0)
  333.                             {
  334.                                 min = tempMax * botTicks * -1;
  335.                             }
  336.                             else
  337.                             {
  338.                                 min = max - (roundingUnit * units);
  339.                             }
  340.                         }
  341.                         else
  342.                         {
  343.                             roundingUnit = Math.max(tempMax, tempMin);
  344.                             roundingUnit = this._getNiceNumber(roundingUnit);
  345.                             max = roundingUnit * topTicks;
  346.                             min = roundingUnit * botTicks * -1;
  347.                         }
  348.                     }
  349.                     else
  350.                     {
  351.                         if(setMax)
  352.                         {
  353.                             min = max - (roundingUnit * units);
  354.                         }
  355.                         else if(setMin)
  356.                         {
  357.                             max = min + (roundingUnit * units);
  358.                         }
  359.                         else
  360.                         {
  361.                             min = this._roundDownToNearest(min, roundingUnit);
  362.                             max = this._roundUpToNearest(max, roundingUnit);
  363.                         }
  364.                     }
  365.                 }
  366.                 else
  367.                 {
  368.                     if(setMin)
  369.                     {
  370.                         if(alwaysShowZero)
  371.                         {
  372.                             max = 0;
  373.                         }
  374.                         else
  375.                         {
  376.                             max = min + (roundingUnit * units);
  377.                         }
  378.                     }
  379.                     else if(!setMax)
  380.                     {
  381.                         if(alwaysShowZero || max === 0 || max + roundingUnit > 0)
  382.                         {
  383.                             max = 0;
  384.                             roundingUnit = this._getMinimumUnit(max, min, units);
  385.                             min = max - (roundingUnit * units);
  386.                         }
  387.                         else
  388.                         {
  389.                             min = this._roundDownToNearest(min, roundingUnit);
  390.                             max = this._roundUpToNearest(max, roundingUnit);
  391.                         }
  392.                     }
  393.                     else
  394.                     {
  395.                         min = max - (roundingUnit * units);
  396.                     }
  397.                 }
  398.             }
  399.             else if(roundingMethod == "auto")
  400.             {
  401.                 if(minGreaterThanZero && maxGreaterThanZero)
  402.                 {
  403.                     if((alwaysShowZero || min < (max-min)/units) && !setMin)
  404.                     {
  405.                         min = 0;
  406.                     }

  407.                     roundingUnit = (max - min)/units;
  408.                     if(useIntegers)
  409.                     {
  410.                         roundingUnit = Math.ceil(roundingUnit);
  411.                     }
  412.                     max = min + (roundingUnit * units);
  413.                 }
  414.                 else if(maxGreaterThanZero && !minGreaterThanZero)
  415.                 {
  416.                     if(alwaysShowZero)
  417.                     {
  418.                         topTicks = Math.round( units / ( (-1 * min) /max + 1) );
  419.                         topTicks = Math.max(Math.min(topTicks, units - 1), 1);
  420.                         botTicks = units - topTicks;

  421.                         if(useIntegers)
  422.                         {
  423.                             tempMax = Math.ceil( max/topTicks );
  424.                             tempMin = Math.floor( min/botTicks ) * -1;
  425.                         }
  426.                         else
  427.                         {
  428.                             tempMax = max/topTicks;
  429.                             tempMin = min/botTicks * -1;
  430.                         }
  431.                         roundingUnit = Math.max(tempMax, tempMin);
  432.                         max = roundingUnit * topTicks;
  433.                         min = roundingUnit * botTicks * -1;
  434.                     }
  435.                     else
  436.                     {
  437.                         roundingUnit = (max - min)/units;
  438.                         if(useIntegers)
  439.                         {
  440.                             roundingUnit = Math.ceil(roundingUnit);
  441.                         }
  442.                         min = this._roundDownToNearest(min, roundingUnit);
  443.                         max = this._roundUpToNearest(max, roundingUnit);
  444.                     }
  445.                 }
  446.                 else
  447.                 {
  448.                     roundingUnit = (max - min)/units;
  449.                     if(useIntegers)
  450.                     {
  451.                         roundingUnit = Math.ceil(roundingUnit);
  452.                     }
  453.                     if(alwaysShowZero || max === 0 || max + roundingUnit > 0)
  454.                     {
  455.                         max = 0;
  456.                         roundingUnit = (max - min)/units;
  457.                         if(useIntegers)
  458.                         {
  459.                             Math.ceil(roundingUnit);
  460.                         }
  461.                         min = max - (roundingUnit * units);
  462.                     }
  463.                     else
  464.                     {
  465.                         min = this._roundDownToNearest(min, roundingUnit);
  466.                         max = this._roundUpToNearest(max, roundingUnit);
  467.                     }

  468.                 }
  469.             }
  470.             else if(!isNaN(roundingMethod) && isFinite(roundingMethod))
  471.             {
  472.                 roundingUnit = roundingMethod;
  473.                 minimumRange = roundingUnit * units;
  474.                 dataRangeGreater = (max - min) > minimumRange;
  475.                 minRound = this._roundDownToNearest(min, roundingUnit);
  476.                 maxRound = this._roundUpToNearest(max, roundingUnit);
  477.                 if(setMax)
  478.                 {
  479.                     min = max - minimumRange;
  480.                 }
  481.                 else if(setMin)
  482.                 {
  483.                     max = min + minimumRange;
  484.                 }
  485.                 else if(minGreaterThanZero && maxGreaterThanZero)
  486.                 {
  487.                     if(alwaysShowZero || minRound <= 0)
  488.                     {
  489.                         min = 0;
  490.                     }
  491.                     else
  492.                     {
  493.                         min = minRound;
  494.                     }
  495.                     max = min + minimumRange;
  496.                 }
  497.                 else if(maxGreaterThanZero && !minGreaterThanZero)
  498.                 {
  499.                     min = minRound;
  500.                     max = maxRound;
  501.                 }
  502.                 else
  503.                 {
  504.                     if(alwaysShowZero || maxRound >= 0)
  505.                     {
  506.                         max = 0;
  507.                     }
  508.                     else
  509.                     {
  510.                         max = maxRound;
  511.                     }
  512.                     min = max - minimumRange;
  513.                 }
  514.             }
  515.         }
  516.         this._dataMaximum = max;
  517.         this._dataMinimum = min;
  518.     },

  519.     /**
  520.      * Calculates and returns a value based on the number of labels and the index of
  521.      * the current label.
  522.      *
  523.      * @method getLabelByIndex
  524.      * @param {Number} i Index of the label.
  525.      * @param {Number} l Total number of labels.
  526.      * @return String
  527.      */
  528.     getLabelByIndex: function(i, l)
  529.     {
  530.         var min = this.get("minimum"),
  531.             max = this.get("maximum"),
  532.             increm = (max - min)/(l-1),
  533.             label,
  534.             roundingMethod = this.get("roundingMethod");
  535.             l -= 1;
  536.         //respect the min and max. calculate all other labels.
  537.         if(i === 0)
  538.         {
  539.             label = min;
  540.         }
  541.         else if(i === l)
  542.         {
  543.             label = max;
  544.         }
  545.         else
  546.         {
  547.             label = (i * increm);
  548.             if(roundingMethod == "niceNumber")
  549.             {
  550.                 label = this._roundToNearest(label, increm);
  551.             }
  552.             label += min;
  553.         }
  554.         return parseFloat(label);
  555.     },

  556.     /**
  557.      * Rounds a Number to the nearest multiple of an input. For example, by rounding
  558.      * 16 to the nearest 10, you will receive 20. Similar to the built-in function Math.round().
  559.      *
  560.      * @method _roundToNearest
  561.      * @param {Number} number Number to round
  562.      * @param {Number} nearest Multiple to round towards.
  563.      * @return Number
  564.      * @private
  565.      */
  566.     _roundToNearest: function(number, nearest)
  567.     {
  568.         nearest = nearest || 1;
  569.         if(nearest === 0)
  570.         {
  571.             return number;
  572.         }
  573.         var roundedNumber = Math.round(this._roundToPrecision(number / nearest, 10)) * nearest;
  574.         return this._roundToPrecision(roundedNumber, 10);
  575.     },

  576.     /**
  577.      * Rounds a Number up to the nearest multiple of an input. For example, by rounding
  578.      * 16 up to the nearest 10, you will receive 20. Similar to the built-in function Math.ceil().
  579.      *
  580.      * @method _roundUpToNearest
  581.      * @param {Number} number Number to round
  582.      * @param {Number} nearest Multiple to round towards.
  583.      * @return Number
  584.      * @private
  585.      */
  586.     _roundUpToNearest: function(number, nearest)
  587.     {
  588.         nearest = nearest || 1;
  589.         if(nearest === 0)
  590.         {
  591.             return number;
  592.         }
  593.         return Math.ceil(this._roundToPrecision(number / nearest, 10)) * nearest;
  594.     },

  595.     /**
  596.      * Rounds a Number down to the nearest multiple of an input. For example, by rounding
  597.      * 16 down to the nearest 10, you will receive 10. Similar to the built-in function Math.floor().
  598.      *
  599.      * @method _roundDownToNearest
  600.      * @param {Number} number Number to round
  601.      * @param {Number} nearest Multiple to round towards.
  602.      * @return Number
  603.      * @private
  604.      */
  605.     _roundDownToNearest: function(number, nearest)
  606.     {
  607.         nearest = nearest || 1;
  608.         if(nearest === 0)
  609.         {
  610.             return number;
  611.         }
  612.         return Math.floor(this._roundToPrecision(number / nearest, 10)) * nearest;
  613.     },

  614.     /**
  615.      * Rounds a number to a certain level of precision. Useful for limiting the number of
  616.      * decimal places on a fractional number.
  617.      *
  618.      * @method _roundToPrecision
  619.      * @param {Number} number Number to round
  620.      * @param {Number} precision Multiple to round towards.
  621.      * @return Number
  622.      * @private
  623.      */
  624.     _roundToPrecision: function(number, precision)
  625.     {
  626.         precision = precision || 0;
  627.         var decimalPlaces = Math.pow(10, precision);
  628.         return Math.round(decimalPlaces * number) / decimalPlaces;
  629.     },

  630.     /**
  631.      * Checks to see if data extends beyond the range of the axis. If so,
  632.      * that data will need to be hidden. This method is internal, temporary and subject
  633.      * to removal in the future.
  634.      *
  635.      * @method _hasDataOverflow
  636.      * @protected
  637.      * @return Boolean
  638.      */
  639.     _hasDataOverflow: function()
  640.     {
  641.         var roundingMethod,
  642.             min,
  643.             max;
  644.         if(this.get("setMin") || this.get("setMax"))
  645.         {
  646.             return true;
  647.         }
  648.         roundingMethod = this.get("roundingMethod");
  649.         min = this._actualMinimum;
  650.         max = this._actualMaximum;
  651.         if(Y_Lang.isNumber(roundingMethod) && ((Y_Lang.isNumber(max) && max > this._dataMaximum) || (Y_Lang.isNumber(min) && min < this._dataMinimum)))
  652.         {
  653.             return true;
  654.         }
  655.         return false;
  656.     }
  657. });

  658. Y.NumericAxis = NumericAxis;


  659.