src/pyams_skin/resources/js/ext/flot/jquery.flot.logaxis.js
changeset 566 a1707c607eec
parent 565 318533413200
child 567 bca1726b1d85
equal deleted inserted replaced
565:318533413200 566:a1707c607eec
     1 /* Pretty handling of log axes.
       
     2 
       
     3 Copyright (c) 2007-2014 IOLA and Ole Laursen.
       
     4 Copyright (c) 2015 Ciprian Ceteras cipix2000@gmail.com.
       
     5 Copyright (c) 2017 Raluca Portase
       
     6 Licensed under the MIT license.
       
     7 
       
     8 Set axis.mode to "log" to enable.
       
     9 */
       
    10 
       
    11 /* global jQuery*/
       
    12 
       
    13 /**
       
    14 ## jquery.flot.logaxis
       
    15 This plugin is used to create logarithmic axis. This includes tick generation,
       
    16 formatters and transformers to and from logarithmic representation.
       
    17 
       
    18 ### Methods and hooks
       
    19 */
       
    20 
       
    21 (function ($) {
       
    22     'use strict';
       
    23 
       
    24     var options = {
       
    25         xaxis: {}
       
    26     };
       
    27 
       
    28     /*tick generators and formatters*/
       
    29     var PREFERRED_LOG_TICK_VALUES = computePreferedLogTickValues(Number.MAX_VALUE, 10),
       
    30         EXTENDED_LOG_TICK_VALUES = computePreferedLogTickValues(Number.MAX_VALUE, 4);
       
    31 
       
    32     function computePreferedLogTickValues(endLimit, rangeStep) {
       
    33         var log10End = Math.floor(Math.log(endLimit) * Math.LOG10E) - 1,
       
    34             log10Start = -log10End,
       
    35             val, range, vals = [];
       
    36 
       
    37         for (var power = log10Start; power <= log10End; power++) {
       
    38             range = parseFloat('1e' + power);
       
    39             for (var mult = 1; mult < 9; mult += rangeStep) {
       
    40                 val = range * mult;
       
    41                 vals.push(val);
       
    42             }
       
    43         }
       
    44         return vals;
       
    45     }
       
    46 
       
    47     /**
       
    48     - logTickGenerator(plot, axis, noTicks)
       
    49 
       
    50     Generates logarithmic ticks, depending on axis range.
       
    51     In case the number of ticks that can be generated is less than the expected noTicks/4,
       
    52     a linear tick generation is used.
       
    53     */
       
    54     var logTickGenerator = function (plot, axis, noTicks) {
       
    55         var ticks = [],
       
    56             minIdx = -1,
       
    57             maxIdx = -1,
       
    58             surface = plot.getCanvas(),
       
    59             logTickValues = PREFERRED_LOG_TICK_VALUES,
       
    60             min = clampAxis(axis, plot),
       
    61             max = axis.max;
       
    62 
       
    63         if (!noTicks) {
       
    64             noTicks = 0.3 * Math.sqrt(axis.direction === "x" ? surface.width : surface.height);
       
    65         }
       
    66 
       
    67         PREFERRED_LOG_TICK_VALUES.some(function (val, i) {
       
    68             if (val >= min) {
       
    69                 minIdx = i;
       
    70                 return true;
       
    71             } else {
       
    72                 return false;
       
    73             }
       
    74         });
       
    75 
       
    76         PREFERRED_LOG_TICK_VALUES.some(function (val, i) {
       
    77             if (val >= max) {
       
    78                 maxIdx = i;
       
    79                 return true;
       
    80             } else {
       
    81                 return false;
       
    82             }
       
    83         });
       
    84 
       
    85         if (maxIdx === -1) {
       
    86             maxIdx = PREFERRED_LOG_TICK_VALUES.length - 1;
       
    87         }
       
    88 
       
    89         if (maxIdx - minIdx <= noTicks / 4 && logTickValues.length !== EXTENDED_LOG_TICK_VALUES.length) {
       
    90             //try with multiple of 5 for tick values
       
    91             logTickValues = EXTENDED_LOG_TICK_VALUES;
       
    92             minIdx *= 2;
       
    93             maxIdx *= 2;
       
    94         }
       
    95 
       
    96         var lastDisplayed = null,
       
    97             inverseNoTicks = 1 / noTicks,
       
    98             tickValue, pixelCoord, tick;
       
    99 
       
   100         // Count the number of tick values would appear, if we can get at least
       
   101         // nTicks / 4 accept them.
       
   102         if (maxIdx - minIdx >= noTicks / 4) {
       
   103             for (var idx = maxIdx; idx >= minIdx; idx--) {
       
   104                 tickValue = logTickValues[idx];
       
   105                 pixelCoord = (Math.log(tickValue) - Math.log(min)) / (Math.log(max) - Math.log(min));
       
   106                 tick = tickValue;
       
   107 
       
   108                 if (lastDisplayed === null) {
       
   109                     lastDisplayed = {
       
   110                         pixelCoord: pixelCoord,
       
   111                         idealPixelCoord: pixelCoord
       
   112                     };
       
   113                 } else {
       
   114                     if (Math.abs(pixelCoord - lastDisplayed.pixelCoord) >= inverseNoTicks) {
       
   115                         lastDisplayed = {
       
   116                             pixelCoord: pixelCoord,
       
   117                             idealPixelCoord: lastDisplayed.idealPixelCoord - inverseNoTicks
       
   118                         };
       
   119                     } else {
       
   120                         tick = null;
       
   121                     }
       
   122                 }
       
   123 
       
   124                 if (tick) {
       
   125                     ticks.push(tick);
       
   126                 }
       
   127             }
       
   128             // Since we went in backwards order.
       
   129             ticks.reverse();
       
   130         } else {
       
   131             var tickSize = plot.computeTickSize(min, max, noTicks),
       
   132                 customAxis = {min: min, max: max, tickSize: tickSize};
       
   133             ticks = $.plot.linearTickGenerator(customAxis);
       
   134         }
       
   135 
       
   136         return ticks;
       
   137     };
       
   138 
       
   139     var clampAxis = function (axis, plot) {
       
   140         var min = axis.min,
       
   141             max = axis.max;
       
   142 
       
   143         if (min <= 0) {
       
   144             //for empty graph if axis.min is not strictly positive make it 0.1
       
   145             if (axis.datamin === null) {
       
   146                 min = axis.min = 0.1;
       
   147             } else {
       
   148                 min = processAxisOffset(plot, axis);
       
   149             }
       
   150 
       
   151             if (max < min) {
       
   152                 axis.max = axis.datamax !== null ? axis.datamax : axis.options.max;
       
   153                 axis.options.offset.below = 0;
       
   154                 axis.options.offset.above = 0;
       
   155             }
       
   156         }
       
   157 
       
   158         return min;
       
   159     }
       
   160 
       
   161     /**
       
   162     - logTickFormatter(value, axis, precision)
       
   163 
       
   164     This is the corresponding tickFormatter of the logaxis.
       
   165     For a number greater that 10^6 or smaller than 10^(-3), this will be drawn
       
   166     with e representation
       
   167     */
       
   168     var logTickFormatter = function (value, axis, precision) {
       
   169         var tenExponent = value > 0 ? Math.floor(Math.log(value) / Math.LN10) : 0;
       
   170 
       
   171         if (precision) {
       
   172             if ((tenExponent >= -4) && (tenExponent <= 7)) {
       
   173                 return $.plot.defaultTickFormatter(value, axis, precision);
       
   174             } else {
       
   175                 return $.plot.expRepTickFormatter(value, axis, precision);
       
   176             }
       
   177         }
       
   178         if ((tenExponent >= -4) && (tenExponent <= 7)) {
       
   179             //if we have float numbers, return a limited length string(ex: 0.0009 is represented as 0.000900001)
       
   180             var formattedValue = tenExponent < 0 ? value.toFixed(-tenExponent) : value.toFixed(tenExponent + 2);
       
   181             if (formattedValue.indexOf('.') !== -1) {
       
   182                 var lastZero = formattedValue.lastIndexOf('0');
       
   183 
       
   184                 while (lastZero === formattedValue.length - 1) {
       
   185                     formattedValue = formattedValue.slice(0, -1);
       
   186                     lastZero = formattedValue.lastIndexOf('0');
       
   187                 }
       
   188 
       
   189                 //delete the dot if is last
       
   190                 if (formattedValue.indexOf('.') === formattedValue.length - 1) {
       
   191                     formattedValue = formattedValue.slice(0, -1);
       
   192                 }
       
   193             }
       
   194             return formattedValue;
       
   195         } else {
       
   196             return $.plot.expRepTickFormatter(value, axis);
       
   197         }
       
   198     };
       
   199 
       
   200     /*logaxis caracteristic functions*/
       
   201     var logTransform = function (v) {
       
   202         if (v < PREFERRED_LOG_TICK_VALUES[0]) {
       
   203             v = PREFERRED_LOG_TICK_VALUES[0];
       
   204         }
       
   205 
       
   206         return Math.log(v);
       
   207     };
       
   208 
       
   209     var logInverseTransform = function (v) {
       
   210         return Math.exp(v);
       
   211     };
       
   212 
       
   213     var invertedTransform = function (v) {
       
   214         return -v;
       
   215     }
       
   216 
       
   217     var invertedLogTransform = function (v) {
       
   218         return -logTransform(v);
       
   219     }
       
   220 
       
   221     var invertedLogInverseTransform = function (v) {
       
   222         return logInverseTransform(-v);
       
   223     }
       
   224 
       
   225     /**
       
   226     - setDataminRange(plot, axis)
       
   227 
       
   228     It is used for clamping the starting point of a logarithmic axis.
       
   229     This will set the axis datamin range to 0.1 or to the first datapoint greater then 0.
       
   230     The function is usefull since the logarithmic representation can not show
       
   231     values less than or equal to 0.
       
   232     */
       
   233     function setDataminRange(plot, axis) {
       
   234         if (axis.options.mode === 'log' && axis.datamin <= 0) {
       
   235             if (axis.datamin === null) {
       
   236                 axis.datamin = 0.1;
       
   237             } else {
       
   238                 axis.datamin = processAxisOffset(plot, axis);
       
   239             }
       
   240         }
       
   241     }
       
   242 
       
   243     function processAxisOffset(plot, axis) {
       
   244         var series = plot.getData(),
       
   245             range = series
       
   246                 .filter(function(series) {
       
   247                     return series.xaxis === axis || series.yaxis === axis;
       
   248                 })
       
   249                 .map(function(series) {
       
   250                     return plot.computeRangeForDataSeries(series, null, isValid);
       
   251                 }),
       
   252             min = axis.direction === 'x' 
       
   253             ? Math.min(0.1, range && range[0] ? range[0].xmin : 0.1) 
       
   254             : Math.min(0.1, range && range[0] ? range[0].ymin : 0.1);
       
   255 
       
   256         axis.min = min;
       
   257 
       
   258         return min;
       
   259     }
       
   260 
       
   261     function isValid(a) {
       
   262         return a > 0;
       
   263     }
       
   264 
       
   265     function init(plot) {
       
   266         plot.hooks.processOptions.push(function (plot) {
       
   267             $.each(plot.getAxes(), function (axisName, axis) {
       
   268                 var opts = axis.options;
       
   269                 if (opts.mode === 'log') {
       
   270                     axis.tickGenerator = function (axis) {
       
   271                         var noTicks = 11;
       
   272                         return logTickGenerator(plot, axis, noTicks);
       
   273                     };
       
   274                     if (typeof axis.options.tickFormatter !== 'function') {
       
   275                         axis.options.tickFormatter = logTickFormatter;
       
   276                     }
       
   277                     axis.options.transform = opts.inverted ? invertedLogTransform : logTransform;
       
   278                     axis.options.inverseTransform = opts.inverted ? invertedLogInverseTransform : logInverseTransform;
       
   279                     axis.options.autoScaleMargin = 0;
       
   280                     plot.hooks.setRange.push(setDataminRange);
       
   281                 } else if (opts.inverted) {
       
   282                     axis.options.transform = invertedTransform;
       
   283                     axis.options.inverseTransform = invertedTransform;
       
   284                 }
       
   285             });
       
   286         });
       
   287     }
       
   288 
       
   289     $.plot.plugins.push({
       
   290         init: init,
       
   291         options: options,
       
   292         name: 'log',
       
   293         version: '0.1'
       
   294     });
       
   295 
       
   296     $.plot.logTicksGenerator = logTickGenerator;
       
   297     $.plot.logTickFormatter = logTickFormatter;
       
   298 })(jQuery);