123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- /* Pretty handling of log axes.
- Copyright (c) 2007-2014 IOLA and Ole Laursen.
- Copyright (c) 2015 Ciprian Ceteras cipix2000@gmail.com.
- Copyright (c) 2017 Raluca Portase
- Licensed under the MIT license.
- Set axis.mode to "log" to enable.
- */
- /* global jQuery*/
- /**
- ## jquery.flot.logaxis
- This plugin is used to create logarithmic axis. This includes tick generation,
- formatters and transformers to and from logarithmic representation.
- ### Methods and hooks
- */
- (function ($) {
- 'use strict';
- var options = {
- xaxis: {}
- };
- /*tick generators and formatters*/
- var PREFERRED_LOG_TICK_VALUES = computePreferedLogTickValues(Number.MAX_VALUE, 10),
- EXTENDED_LOG_TICK_VALUES = computePreferedLogTickValues(Number.MAX_VALUE, 4);
- function computePreferedLogTickValues(endLimit, rangeStep) {
- var log10End = Math.floor(Math.log(endLimit) * Math.LOG10E) - 1,
- log10Start = -log10End,
- val, range, vals = [];
- for (var power = log10Start; power <= log10End; power++) {
- range = Math.pow(10, power);
- for (var mult = 1; mult < 9; mult += rangeStep) {
- val = range * mult;
- vals.push(val);
- }
- }
- return vals;
- }
- /**
- - logTickGenerator(plot, axis, noTicks)
- Generates logarithmic ticks, depending on axis range.
- In case the number of ticks that can be generated is less than the expected noTicks/4,
- a linear tick generation is used.
- */
- var logTickGenerator = function (plot, axis, noTicks) {
- var ticks = [],
- minIdx = -1,
- maxIdx = -1,
- surface = plot.getCanvas(),
- logTickValues = PREFERRED_LOG_TICK_VALUES,
- min = clampAxis(axis, plot),
- max = axis.max;
- if (!noTicks) {
- noTicks = 0.3 * Math.sqrt(axis.direction === "x" ? surface.width : surface.height);
- }
- PREFERRED_LOG_TICK_VALUES.some(function (val, i) {
- if (val >= min) {
- minIdx = i;
- return true;
- } else {
- return false;
- }
- });
- PREFERRED_LOG_TICK_VALUES.some(function (val, i) {
- if (val >= max) {
- maxIdx = i;
- return true;
- } else {
- return false;
- }
- });
- if (maxIdx === -1) {
- maxIdx = PREFERRED_LOG_TICK_VALUES.length - 1;
- }
- if (maxIdx - minIdx <= noTicks / 4 && logTickValues.length !== EXTENDED_LOG_TICK_VALUES.length) {
- //try with multiple of 5 for tick values
- logTickValues = EXTENDED_LOG_TICK_VALUES;
- minIdx *= 2;
- maxIdx *= 2;
- }
- var lastDisplayed = null,
- inverseNoTicks = 1 / noTicks,
- tickValue, pixelCoord, tick;
- // Count the number of tick values would appear, if we can get at least
- // nTicks / 4 accept them.
- if (maxIdx - minIdx >= noTicks / 4) {
- for (var idx = maxIdx; idx >= minIdx; idx--) {
- tickValue = logTickValues[idx];
- pixelCoord = (Math.log(tickValue) - Math.log(min)) / (Math.log(max) - Math.log(min));
- tick = tickValue;
- if (lastDisplayed === null) {
- lastDisplayed = {
- pixelCoord: pixelCoord,
- idealPixelCoord: pixelCoord
- };
- } else {
- if (Math.abs(pixelCoord - lastDisplayed.pixelCoord) >= inverseNoTicks) {
- lastDisplayed = {
- pixelCoord: pixelCoord,
- idealPixelCoord: lastDisplayed.idealPixelCoord - inverseNoTicks
- };
- } else {
- tick = null;
- }
- }
- if (tick) {
- ticks.push(tick);
- }
- }
- // Since we went in backwards order.
- ticks.reverse();
- } else {
- var tickSize = plot.computeTickSize(min, max, noTicks),
- customAxis = {min: min, max: max, tickSize: tickSize};
- ticks = $.plot.linearTickGenerator(customAxis);
- }
- return ticks;
- };
- var clampAxis = function (axis, plot) {
- var min = axis.min,
- max = axis.max;
- if (min <= 0) {
- //for empty graph if axis.min is not strictly positive make it 0.1
- if (axis.datamin === null) {
- min = axis.min = 0.1;
- } else {
- min = processAxisOffset(plot, axis);
- }
- if (max < min) {
- axis.max = axis.datamax !== null ? axis.datamax : axis.options.max;
- axis.options.offset.below = 0;
- axis.options.offset.above = 0;
- }
- }
- return min;
- }
- /**
- - logTickFormatter(value, axis, precision)
- This is the corresponding tickFormatter of the logaxis.
- For a number greater that 10^6 or smaller than 10^(-3), this will be drawn
- with e representation
- */
- var logTickFormatter = function (value, axis, precision) {
- var tenExponent = value > 0 ? Math.floor(Math.log(value) / Math.LN10) : 0;
- if (precision) {
- if ((tenExponent >= -4) && (tenExponent <= 7)) {
- return $.plot.defaultTickFormatter(value, axis, precision);
- } else {
- return $.plot.expRepTickFormatter(value, axis, precision);
- }
- }
- if ((tenExponent >= -4) && (tenExponent <= 7)) {
- //if we have float numbers, return a limited length string(ex: 0.0009 is represented as 0.000900001)
- var formattedValue = tenExponent < 0 ? value.toFixed(-tenExponent) : value.toFixed(tenExponent + 2);
- if (formattedValue.indexOf('.') !== -1) {
- var lastZero = formattedValue.lastIndexOf('0');
- while (lastZero === formattedValue.length - 1) {
- formattedValue = formattedValue.slice(0, -1);
- lastZero = formattedValue.lastIndexOf('0');
- }
- //delete the dot if is last
- if (formattedValue.indexOf('.') === formattedValue.length - 1) {
- formattedValue = formattedValue.slice(0, -1);
- }
- }
- return formattedValue;
- } else {
- return $.plot.expRepTickFormatter(value, axis);
- }
- };
- /*logaxis caracteristic functions*/
- var logTransform = function (v) {
- if (v < PREFERRED_LOG_TICK_VALUES[0]) {
- v = PREFERRED_LOG_TICK_VALUES[0];
- }
- return Math.log(v);
- };
- var logInverseTransform = function (v) {
- return Math.exp(v);
- };
- var invertedTransform = function (v) {
- return -v;
- }
- var invertedLogTransform = function (v) {
- return -logTransform(v);
- }
- var invertedLogInverseTransform = function (v) {
- return logInverseTransform(-v);
- }
- /**
- - setDataminRange(plot, axis)
- It is used for clamping the starting point of a logarithmic axis.
- This will set the axis datamin range to 0.1 or to the first datapoint greater then 0.
- The function is usefull since the logarithmic representation can not show
- values less than or equal to 0.
- */
- function setDataminRange(plot, axis) {
- if (axis.options.mode === 'log' && axis.datamin <= 0) {
- if (axis.datamin === null) {
- axis.datamin = 0.1;
- } else {
- axis.datamin = processAxisOffset(plot, axis);
- }
- }
- }
- function processAxisOffset(plot, axis) {
- var series = plot.getData(),
- range = series
- .filter(function(series) {
- return series.xaxis === axis || series.yaxis === axis;
- })
- .map(function(series) {
- return plot.computeRangeForDataSeries(series, null, isValid);
- }),
- min = axis.direction === 'x'
- ? Math.min(0.1, range && range[0] ? range[0].xmin : 0.1)
- : Math.min(0.1, range && range[0] ? range[0].ymin : 0.1);
- axis.min = min;
- return min;
- }
- function isValid(a) {
- return a > 0;
- }
- function init(plot) {
- plot.hooks.processOptions.push(function (plot) {
- $.each(plot.getAxes(), function (axisName, axis) {
- var opts = axis.options;
- if (opts.mode === 'log') {
- axis.tickGenerator = function (axis) {
- var noTicks = 11;
- return logTickGenerator(plot, axis, noTicks);
- };
- if (typeof axis.options.tickFormatter !== 'function') {
- axis.options.tickFormatter = logTickFormatter;
- }
- axis.options.transform = opts.inverted ? invertedLogTransform : logTransform;
- axis.options.inverseTransform = opts.inverted ? invertedLogInverseTransform : logInverseTransform;
- axis.options.autoScaleMargin = 0;
- plot.hooks.setRange.push(setDataminRange);
- } else if (opts.inverted) {
- axis.options.transform = invertedTransform;
- axis.options.inverseTransform = invertedTransform;
- }
- });
- });
- }
- $.plot.plugins.push({
- init: init,
- options: options,
- name: 'log',
- version: '0.1'
- });
- $.plot.logTicksGenerator = logTickGenerator;
- $.plot.logTickFormatter = logTickFormatter;
- })(jQuery);
|