]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Handle reverse support in core.scale (#6343)
authorJukka Kurkela <jukka.kurkela@gmail.com>
Mon, 15 Jul 2019 21:20:16 +0000 (00:20 +0300)
committerEvert Timberg <evert.timberg@gmail.com>
Mon, 15 Jul 2019 21:20:16 +0000 (17:20 -0400)
* Move log10 from core.helpers to helpers.math

* Refactor scales

16 files changed:
src/controllers/controller.bar.js
src/core/core.controller.js
src/core/core.helpers.js
src/core/core.scale.js
src/helpers/helpers.math.js
src/scales/scale.category.js
src/scales/scale.linear.js
src/scales/scale.linearbase.js
src/scales/scale.logarithmic.js
src/scales/scale.time.js
test/specs/core.helpers.tests.js
test/specs/core.scale.tests.js
test/specs/helpers.math.tests.js
test/specs/scale.linear.tests.js
test/specs/scale.logarithmic.tests.js
test/specs/scale.time.tests.js

index aa8b06a2cbc073efcaa549f1f6c31056ea3b5841..4c36c74a8200471b97301b80e60e897ade2e6825 100644 (file)
@@ -32,7 +32,7 @@ defaults._set('bar', {
  * @private
  */
 function computeMinSampleSize(scale, pixels) {
-       var min = scale.isHorizontal() ? scale.width : scale.height;
+       var min = scale._length;
        var ticks = scale.getTicks();
        var prev, curr, i, ilen;
 
@@ -42,7 +42,7 @@ function computeMinSampleSize(scale, pixels) {
 
        for (i = 0, ilen = ticks.length; i < ilen; ++i) {
                curr = scale.getPixelForTick(i);
-               min = i > 0 ? Math.min(min, curr - prev) : min;
+               min = i > 0 ? Math.min(min, Math.abs(curr - prev)) : min;
                prev = curr;
        }
 
@@ -262,9 +262,6 @@ module.exports = DatasetController.extend({
                var scale = me._getIndexScale();
                var stackCount = me.getStackCount();
                var datasetIndex = me.index;
-               var isHorizontal = scale.isHorizontal();
-               var start = isHorizontal ? scale.left : scale.top;
-               var end = start + (isHorizontal ? scale.width : scale.height);
                var pixels = [];
                var i, ilen, min;
 
@@ -279,8 +276,8 @@ module.exports = DatasetController.extend({
                return {
                        min: min,
                        pixels: pixels,
-                       start: start,
-                       end: end,
+                       start: scale._startPixel,
+                       end: scale._endPixel,
                        stackCount: stackCount,
                        scale: scale
                };
index 5349fb5f72de6166877710ccfc739799f8fb2c0f..694e776461117cecfa52feac026a91385e2d541e 100644 (file)
@@ -546,6 +546,11 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
 
                me._layers = [];
                helpers.each(me.boxes, function(box) {
+                       // _configure is called twice, once in core.scale.update and once here.
+                       // Here the boxes are fully updated and at their final positions.
+                       if (box._configure) {
+                               box._configure();
+                       }
                        me._layers.push.apply(me._layers, box._layers());
                }, me);
 
index 31748758090704ee661fe9143d21461cf35f6027..33c94799e155c70ac0315cfa9d973cf767320db3 100644 (file)
@@ -100,19 +100,6 @@ module.exports = function() {
                        }
                        return x > 0 ? 1 : -1;
                };
-       helpers.log10 = Math.log10 ?
-               function(x) {
-                       return Math.log10(x);
-               } :
-               function(x) {
-                       var exponent = Math.log(x) * Math.LOG10E; // Math.LOG10E = 1 / Math.LN10.
-                       // Check for whole powers of 10,
-                       // which due to floating point rounding error should be corrected.
-                       var powerOf10 = Math.round(exponent);
-                       var isPowerOf10 = x === Math.pow(10, powerOf10);
-
-                       return isPowerOf10 ? powerOf10 : exponent;
-               };
        helpers.toRadians = function(degrees) {
                return degrees * (Math.PI / 180);
        };
index 5eed97b9c7ba4661df163a298e8263e0823445be..4cfe0a064bd3133e7587fdfe1be8be6150c8eb19 100644 (file)
@@ -70,9 +70,7 @@ function getPixelForGridLine(scale, index, offsetGridLines) {
 
        if (offsetGridLines) {
                if (scale.getTicks().length === 1) {
-                       lineValue -= scale.isHorizontal() ?
-                               Math.max(lineValue - scale.left, scale.right - lineValue) :
-                               Math.max(lineValue - scale.top, scale.bottom - lineValue);
+                       lineValue -= Math.max(lineValue - scale._startPixel, scale._endPixel - lineValue);
                } else if (index === 0) {
                        lineValue -= (scale.getPixelForTick(1) - lineValue) / 2;
                } else {
@@ -318,6 +316,12 @@ var Scale = Element.extend({
 
                me._ticks = ticks;
 
+               // _configure is called twice, once here, once from core.controller.updateLayout.
+               // Here we haven't been positioned yet, but dimensions are correct.
+               // Variables set in _configure are needed for calculateTickRotation, and
+               // it's ok that coordinates are not correct there, only dimensions matter.
+               me._configure();
+
                // Tick Rotation
                me.beforeCalculateTickRotation();
                me.calculateTickRotation();
@@ -332,6 +336,30 @@ var Scale = Element.extend({
                return me.minSize;
 
        },
+
+       /**
+        * @private
+        */
+       _configure: function() {
+               var me = this;
+               var reversePixels = me.options.ticks.reverse;
+               var startPixel, endPixel;
+
+               if (me.isHorizontal()) {
+                       startPixel = me.left;
+                       endPixel = me.right;
+               } else {
+                       startPixel = me.top;
+                       endPixel = me.bottom;
+                       // by default vertical scales are from bottom to top, so pixels are reversed
+                       reversePixels = !reversePixels;
+               }
+               me._startPixel = startPixel;
+               me._endPixel = endPixel;
+               me._reversePixels = reversePixels;
+               me._length = endPixel - startPixel;
+       },
+
        afterUpdate: function() {
                helpers.callback(this.options.afterUpdate, [this]);
        },
@@ -576,10 +604,11 @@ var Scale = Element.extend({
 
        // Shared Methods
        isHorizontal: function() {
-               return this.options.position === 'top' || this.options.position === 'bottom';
+               var pos = this.options.position;
+               return pos === 'top' || pos === 'bottom';
        },
        isFullWidth: function() {
-               return (this.options.fullWidth);
+               return this.options.fullWidth;
        },
 
        // Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
@@ -693,20 +722,11 @@ var Scale = Element.extend({
                var me = this;
                var offset = me.options.offset;
                var numTicks = me._ticks.length;
-               if (index < 0 || index > numTicks - 1) {
-                       return null;
-               }
-               if (me.isHorizontal()) {
-                       var tickWidth = me.width / Math.max((numTicks - (offset ? 0 : 1)), 1);
-                       var pixel = (tickWidth * index);
+               var tickWidth = 1 / Math.max(numTicks - (offset ? 0 : 1), 1);
 
-                       if (offset) {
-                               pixel += tickWidth / 2;
-                       }
-
-                       return me.left + pixel;
-               }
-               return me.top + (index * (me.height / (numTicks - 1)));
+               return index < 0 || index > numTicks - 1
+                       ? null
+                       : me.getPixelForDecimal(index * tickWidth + (offset ? tickWidth / 2 : 0));
        },
 
        /**
@@ -715,9 +735,17 @@ var Scale = Element.extend({
         */
        getPixelForDecimal: function(decimal) {
                var me = this;
-               return me.isHorizontal()
-                       ? me.left + decimal * me.width
-                       : me.top + decimal * me.height;
+
+               if (me._reversePixels) {
+                       decimal = 1 - decimal;
+               }
+
+               return me._startPixel + decimal * me._length;
+       },
+
+       getDecimalForPixel: function(pixel) {
+               var decimal = (pixel - this._startPixel) / this._length;
+               return Math.min(1, Math.max(0, this._reversePixels ? 1 - decimal : decimal));
        },
 
        /**
@@ -745,7 +773,6 @@ var Scale = Element.extend({
         */
        _autoSkip: function(ticks) {
                var me = this;
-               var isHorizontal = me.isHorizontal();
                var optionTicks = me.options.ticks;
                var tickCount = ticks.length;
                var skipRatio = false;
@@ -755,9 +782,7 @@ var Scale = Element.extend({
                // drawn as their center at end of axis, so tickCount-1
                var ticksLength = me._tickSize() * (tickCount - 1);
 
-               // Axis length
-               var axisLength = isHorizontal ? me.width : me.height;
-
+               var axisLength = me._length;
                var result = [];
                var i, tick;
 
@@ -788,7 +813,6 @@ var Scale = Element.extend({
         */
        _tickSize: function() {
                var me = this;
-               var isHorizontal = me.isHorizontal();
                var optionTicks = me.options.ticks;
 
                // Calculate space needed by label in axis direction.
@@ -802,7 +826,7 @@ var Scale = Element.extend({
                var h = labelSizes ? labelSizes.highest.height + padding : 0;
 
                // Calculate space needed for 1 tick in axis direction.
-               return isHorizontal
+               return me.isHorizontal()
                        ? h * cos > w * sin ? w / cos : h / sin
                        : h * sin < w * cos ? h / cos : w / sin;
        },
@@ -1130,7 +1154,7 @@ var Scale = Element.extend({
                var scaleLabelX, scaleLabelY;
 
                if (me.isHorizontal()) {
-                       scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
+                       scaleLabelX = me.left + me.width / 2; // midpoint of the width
                        scaleLabelY = position === 'bottom'
                                ? me.bottom - halfLineHeight - scaleLabelPadding.bottom
                                : me.top + halfLineHeight + scaleLabelPadding.top;
@@ -1139,7 +1163,7 @@ var Scale = Element.extend({
                        scaleLabelX = isLeft
                                ? me.left + halfLineHeight + scaleLabelPadding.top
                                : me.right - halfLineHeight - scaleLabelPadding.top;
-                       scaleLabelY = me.top + ((me.bottom - me.top) / 2);
+                       scaleLabelY = me.top + me.height / 2;
                        rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
                }
 
index 9ed8114eab9af41faadae617716a8a8ced13579e..f2b2b6f014891c36a3d779a2e6481f460e6901ed 100644 (file)
@@ -1,5 +1,7 @@
 'use strict';
 
+var helpers = require('./helpers.core');
+
 /**
  * @alias Chart.helpers.math
  * @namespace
@@ -28,7 +30,28 @@ var exports = {
                        return a - b;
                }).pop();
                return result;
+       },
+
+       log10: Math.log10 || function(x) {
+               var exponent = Math.log(x) * Math.LOG10E; // Math.LOG10E = 1 / Math.LN10.
+               // Check for whole powers of 10,
+               // which due to floating point rounding error should be corrected.
+               var powerOf10 = Math.round(exponent);
+               var isPowerOf10 = x === Math.pow(10, powerOf10);
+
+               return isPowerOf10 ? powerOf10 : exponent;
        }
 };
 
 module.exports = exports;
+
+// DEPRECATIONS
+
+/**
+ * Provided for backward compatibility, use Chart.helpers.math.log10 instead.
+ * @namespace Chart.helpers.log10
+ * @deprecated since version 2.9.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers.log10 = exports.log10;
index 4cb9422230d130c464794afa6f22c047563ed722..bb74d40db3ae3c56a191984456bd09d98e9c36ff 100644 (file)
@@ -63,17 +63,30 @@ module.exports = Scale.extend({
                return me.ticks[index - me.minIndex];
        },
 
-       // Used to get data value locations.  Value can either be an index or a numerical value
-       getPixelForValue: function(value, index, datasetIndex) {
+       _configure: function() {
                var me = this;
                var offset = me.options.offset;
+               var ticks = me.ticks;
+
+               Scale.prototype._configure.call(me);
+
+               if (!me.isHorizontal()) {
+                       // For backward compatibility, vertical category scale reverse is inverted.
+                       me._reversePixels = !me._reversePixels;
+               }
+
+               if (!ticks) {
+                       return;
+               }
 
-               // 1 is added because we need the length but we have the indexes
-               var offsetAmt = Math.max(me.maxIndex + 1 - me.minIndex - (offset ? 0 : 1), 1);
+               me._startValue = me.minIndex - (offset ? 0.5 : 0);
+               me._valueRange = Math.max(ticks.length - (offset ? 0 : 1), 1);
+       },
 
-               var isHorizontal = me.isHorizontal();
-               var valueDimension = (isHorizontal ? me.width : me.height) / offsetAmt;
-               var valueCategory, labels, idx, pixel;
+       // Used to get data value locations.  Value can either be an index or a numerical value
+       getPixelForValue: function(value, index, datasetIndex) {
+               var me = this;
+               var valueCategory, labels, idx;
 
                if (!isNullOrUndef(index) && !isNullOrUndef(datasetIndex)) {
                        value = me.chart.data.datasets[datasetIndex].data[index];
@@ -82,53 +95,31 @@ module.exports = Scale.extend({
                // If value is a data object, then index is the index in the data array,
                // not the index of the scale. We need to change that.
                if (!isNullOrUndef(value)) {
-                       valueCategory = isHorizontal ? value.x : value.y;
+                       valueCategory = me.isHorizontal() ? value.x : value.y;
                }
                if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {
                        labels = me._getLabels();
                        value = helpers.valueOrDefault(valueCategory, value);
                        idx = labels.indexOf(value);
                        index = idx !== -1 ? idx : index;
+                       if (isNaN(index)) {
+                               index = value;
+                       }
                }
-
-               pixel = valueDimension * (index - me.minIndex);
-
-               if (offset) {
-                       pixel += valueDimension / 2;
-               }
-
-               return (isHorizontal ? me.left : me.top) + pixel;
+               return me.getPixelForDecimal((index - me._startValue) / me._valueRange);
        },
 
        getPixelForTick: function(index) {
                var ticks = this.ticks;
-               if (index < 0 || index > ticks.length - 1) {
-                       return null;
-               }
-               return this.getPixelForValue(ticks[index], index + this.minIndex);
+               return index < 0 || index > ticks.length - 1
+                       ? null
+                       : this.getPixelForValue(ticks[index], index + this.minIndex);
        },
 
        getValueForPixel: function(pixel) {
                var me = this;
-               var offset = me.options.offset;
-               var offsetAmt = Math.max(me._ticks.length - (offset ? 0 : 1), 1);
-               var isHorizontal = me.isHorizontal();
-               var valueDimension = (isHorizontal ? me.width : me.height) / offsetAmt;
-               var value;
-
-               pixel -= isHorizontal ? me.left : me.top;
-
-               if (offset) {
-                       pixel -= valueDimension / 2;
-               }
-
-               if (pixel <= 0) {
-                       value = 0;
-               } else {
-                       value = Math.round(pixel / valueDimension);
-               }
-
-               return value + me.minIndex;
+               var value = Math.round(me._startValue + me.getDecimalForPixel(pixel) * me._valueRange);
+               return Math.min(Math.max(value, 0), me.ticks.length - 1);
        },
 
        getBasePixel: function() {
index 7db13eb46cfa166a1b3028377700d10042c5bad7..004b7d8e6ea747c3962851bff5589001cff11264 100644 (file)
@@ -149,29 +149,12 @@ module.exports = LinearScaleBase.extend({
 
        // Utils
        getPixelForValue: function(value) {
-               // This must be called after fit has been run so that
-               // this.left, this.top, this.right, and this.bottom have been defined
                var me = this;
-               var start = me.start;
-
-               var rightValue = +me.getRightValue(value);
-               var pixel;
-               var range = me.end - start;
-
-               if (me.isHorizontal()) {
-                       pixel = me.left + (me.width / range * (rightValue - start));
-               } else {
-                       pixel = me.bottom - (me.height / range * (rightValue - start));
-               }
-               return pixel;
+               return me.getPixelForDecimal((+me.getRightValue(value) - me._startValue) / me._valueRange);
        },
 
        getValueForPixel: function(pixel) {
-               var me = this;
-               var isHorizontal = me.isHorizontal();
-               var innerDimension = isHorizontal ? me.width : me.height;
-               var offset = (isHorizontal ? pixel - me.left : me.bottom - pixel) / innerDimension;
-               return me.start + ((me.end - me.start) * offset);
+               return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange;
        },
 
        getPixelForTick: function(index) {
index 7f68279db6cc26a302cdf61ea2c3147544d331b9..95ba9bebe1f8476b6c4254b795c923b04839bb96 100644 (file)
@@ -231,5 +231,24 @@ module.exports = Scale.extend({
                me.zeroLineIndex = me.ticks.indexOf(0);
 
                Scale.prototype.convertTicksToLabels.call(me);
+       },
+
+       _configure: function() {
+               var me = this;
+               var ticks = me.getTicks();
+               var start = me.min;
+               var end = me.max;
+               var offset;
+
+               Scale.prototype._configure.call(me);
+
+               if (me.options.offset && ticks.length) {
+                       offset = (end - start) / Math.max(ticks.length - 1, 1) / 2;
+                       start -= offset;
+                       end += offset;
+               }
+               me._startValue = start;
+               me._endValue = end;
+               me._valueRange = end - start;
        }
 });
index 5def62aac554447a4b0c44be0ff333d22e9eed89..6a6553ab8a91ef1433c27328bea772a59db9504a 100644 (file)
@@ -6,6 +6,7 @@ var Scale = require('../core/core.scale');
 var Ticks = require('../core/core.ticks');
 
 var valueOrDefault = helpers.valueOrDefault;
+var log10 = helpers.math.log10;
 
 /**
  * Generate a set of logarithmic ticks
@@ -16,20 +17,20 @@ var valueOrDefault = helpers.valueOrDefault;
 function generateTicks(generationOptions, dataRange) {
        var ticks = [];
 
-       var tickVal = valueOrDefault(generationOptions.min, Math.pow(10, Math.floor(helpers.log10(dataRange.min))));
+       var tickVal = valueOrDefault(generationOptions.min, Math.pow(10, Math.floor(log10(dataRange.min))));
 
-       var endExp = Math.floor(helpers.log10(dataRange.max));
+       var endExp = Math.floor(log10(dataRange.max));
        var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
        var exp, significand;
 
        if (tickVal === 0) {
-               exp = Math.floor(helpers.log10(dataRange.minNotZero));
+               exp = Math.floor(log10(dataRange.minNotZero));
                significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp));
 
                ticks.push(tickVal);
                tickVal = significand * Math.pow(10, exp);
        } else {
-               exp = Math.floor(helpers.log10(tickVal));
+               exp = Math.floor(log10(tickVal));
                significand = Math.floor(tickVal / Math.pow(10, exp));
        }
        var precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;
@@ -178,26 +179,26 @@ module.exports = Scale.extend({
 
                if (me.min === me.max) {
                        if (me.min !== 0 && me.min !== null) {
-                               me.min = Math.pow(10, Math.floor(helpers.log10(me.min)) - 1);
-                               me.max = Math.pow(10, Math.floor(helpers.log10(me.max)) + 1);
+                               me.min = Math.pow(10, Math.floor(log10(me.min)) - 1);
+                               me.max = Math.pow(10, Math.floor(log10(me.max)) + 1);
                        } else {
                                me.min = DEFAULT_MIN;
                                me.max = DEFAULT_MAX;
                        }
                }
                if (me.min === null) {
-                       me.min = Math.pow(10, Math.floor(helpers.log10(me.max)) - 1);
+                       me.min = Math.pow(10, Math.floor(log10(me.max)) - 1);
                }
                if (me.max === null) {
                        me.max = me.min !== 0
-                               ? Math.pow(10, Math.floor(helpers.log10(me.min)) + 1)
+                               ? Math.pow(10, Math.floor(log10(me.min)) + 1)
                                : DEFAULT_MAX;
                }
                if (me.minNotZero === null) {
                        if (me.min > 0) {
                                me.minNotZero = me.min;
                        } else if (me.max < 1) {
-                               me.minNotZero = Math.pow(10, Math.floor(helpers.log10(me.max)));
+                               me.minNotZero = Math.pow(10, Math.floor(log10(me.max)));
                        } else {
                                me.minNotZero = DEFAULT_MIN;
                        }
@@ -259,87 +260,47 @@ module.exports = Scale.extend({
         * @private
         */
        _getFirstTickValue: function(value) {
-               var exp = Math.floor(helpers.log10(value));
+               var exp = Math.floor(log10(value));
                var significand = Math.floor(value / Math.pow(10, exp));
 
                return significand * Math.pow(10, exp);
        },
 
-       getPixelForValue: function(value) {
+       _configure: function() {
                var me = this;
-               var tickOpts = me.options.ticks;
-               var reverse = tickOpts.reverse;
-               var log10 = helpers.log10;
-               var firstTickValue = me._getFirstTickValue(me.minNotZero);
+               var start = me.min;
                var offset = 0;
-               var innerDimension, pixel, start, end, sign;
 
-               value = +me.getRightValue(value);
-               if (reverse) {
-                       start = me.end;
-                       end = me.start;
-                       sign = -1;
-               } else {
-                       start = me.start;
-                       end = me.end;
-                       sign = 1;
-               }
-               if (me.isHorizontal()) {
-                       innerDimension = me.width;
-                       pixel = reverse ? me.right : me.left;
-               } else {
-                       innerDimension = me.height;
-                       sign *= -1; // invert, since the upper-left corner of the canvas is at pixel (0, 0)
-                       pixel = reverse ? me.top : me.bottom;
-               }
-               if (value !== start) {
-                       if (start === 0) { // include zero tick
-                               offset = valueOrDefault(tickOpts.fontSize, defaults.global.defaultFontSize);
-                               innerDimension -= offset;
-                               start = firstTickValue;
-                       }
-                       if (value !== 0) {
-                               offset += innerDimension / (log10(end) - log10(start)) * (log10(value) - log10(start));
-                       }
-                       pixel += sign * offset;
+               Scale.prototype._configure.call(me);
+
+               if (start === 0) {
+                       start = me._getFirstTickValue(me.minNotZero);
+                       offset = valueOrDefault(me.options.ticks.fontSize, defaults.global.defaultFontSize) / me._length;
                }
-               return pixel;
+
+               me._startValue = log10(start);
+               me._valueOffset = offset;
+               me._valueRange = (log10(me.max) - log10(start)) / (1 - offset);
        },
 
-       getValueForPixel: function(pixel) {
+       getPixelForValue: function(value) {
                var me = this;
-               var tickOpts = me.options.ticks;
-               var reverse = tickOpts.reverse;
-               var log10 = helpers.log10;
-               var firstTickValue = me._getFirstTickValue(me.minNotZero);
-               var innerDimension, start, end, value;
+               var decimal = 0;
 
-               if (reverse) {
-                       start = me.end;
-                       end = me.start;
-               } else {
-                       start = me.start;
-                       end = me.end;
-               }
-               if (me.isHorizontal()) {
-                       innerDimension = me.width;
-                       value = reverse ? me.right - pixel : pixel - me.left;
-               } else {
-                       innerDimension = me.height;
-                       value = reverse ? pixel - me.top : me.bottom - pixel;
-               }
-               if (value !== start) {
-                       if (start === 0) { // include zero tick
-                               var offset = valueOrDefault(tickOpts.fontSize, defaults.global.defaultFontSize);
-                               value -= offset;
-                               innerDimension -= offset;
-                               start = firstTickValue;
-                       }
-                       value *= log10(end) - log10(start);
-                       value /= innerDimension;
-                       value = Math.pow(10, log10(start) + value);
+               value = +me.getRightValue(value);
+
+               if (value > me.min && value > 0) {
+                       decimal = (log10(value) - me._startValue) / me._valueRange + me._valueOffset;
                }
-               return value;
+               return me.getPixelForDecimal(decimal);
+       },
+
+       getValueForPixel: function(pixel) {
+               var me = this;
+               var decimal = me.getDecimalForPixel(pixel);
+               return decimal === 0 && me.min === 0
+                       ? 0
+                       : Math.pow(10, me._startValue + (decimal - me._valueOffset) * me._valueRange);
        }
 });
 
index 88ccdf7a271291f5fdb93b801f978dcd31510c2e..b766a16829d5015dc88fd01b770af064af14310c 100644 (file)
@@ -596,7 +596,6 @@ module.exports = Scale.extend({
                me.max = Math.max(min + 1, max);
 
                // PRIVATE
-               me._horizontal = me.isHorizontal();
                me._table = [];
                me._timestamps = {
                        data: timestamps,
@@ -611,16 +610,16 @@ module.exports = Scale.extend({
                var max = me.max;
                var options = me.options;
                var timeOpts = options.time;
-               var timestamps = [];
+               var timestamps = me._timestamps;
                var ticks = [];
                var i, ilen, timestamp;
 
                switch (options.ticks.source) {
                case 'data':
-                       timestamps = me._timestamps.data;
+                       timestamps = timestamps.data;
                        break;
                case 'labels':
-                       timestamps = me._timestamps.labels;
+                       timestamps = timestamps.labels;
                        break;
                case 'auto':
                default:
@@ -725,13 +724,8 @@ module.exports = Scale.extend({
        getPixelForOffset: function(time) {
                var me = this;
                var offsets = me._offsets;
-               var size = me._horizontal ? me.width : me.height;
                var pos = interpolate(me._table, 'time', time, 'pos');
-               var offset = size * (offsets.start + pos) * offsets.factor;
-
-               return me.options.ticks.reverse ?
-                       (me._horizontal ? me.right : me.bottom) - offset :
-                       (me._horizontal ? me.left : me.top) + offset;
+               return me.getPixelForDecimal((offsets.start + pos) * offsets.factor);
        },
 
        getPixelForValue: function(value, index, datasetIndex) {
@@ -761,11 +755,7 @@ module.exports = Scale.extend({
        getValueForPixel: function(pixel) {
                var me = this;
                var offsets = me._offsets;
-               var size = me._horizontal ? me.width : me.height;
-               var offset = me.options.ticks.reverse ?
-                       (me._horizontal ? me.right : me.bottom) - pixel :
-                       pixel - (me._horizontal ? me.left : me.top);
-               var pos = offset / size / offsets.factor - offsets.start;
+               var pos = me.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
                var time = interpolate(me._table, 'pos', pos, 'time');
 
                // DEPRECATION, we should return time directly
index 1f2bc29d5a16a7824d76b01625cb49815bc8f5ad..e6ade2bd76a5cd5e8b50b6fa71c9a7311621b68d 100644 (file)
@@ -26,16 +26,6 @@ describe('Core helper tests', function() {
                expect(helpers.sign(-5)).toBe(-1);
        });
 
-       it('should do a log10 operation', function() {
-               expect(helpers.log10(0)).toBe(-Infinity);
-
-               // Check all allowed powers of 10, which should return integer values
-               var maxPowerOf10 = Math.floor(helpers.log10(Number.MAX_VALUE));
-               for (var i = 0; i < maxPowerOf10; i += 1) {
-                       expect(helpers.log10(Math.pow(10, i))).toBe(i);
-               }
-       });
-
        it('should correctly determine if two numbers are essentially equal', function() {
                expect(helpers.almostEquals(0, Number.EPSILON, 2 * Number.EPSILON)).toBe(true);
                expect(helpers.almostEquals(1, 1.1, 0.0001)).toBe(false);
index 605707eb3c170fa992dafa6d6c77153b4d18b6dc..f293eb2aaa3e8a4b9d77a321995e8c5557ee1c69 100644 (file)
@@ -94,7 +94,7 @@ describe('Core.scale', function() {
                labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'],
                offsetGridLines: true,
                offset: true,
-               expected: [-0.5, 102.5, 204.5, 307.5, 409.5]
+               expected: [0.5, 102.5, 204.5, 307.5, 409.5]
        }, {
                labels: ['tick1'],
                offsetGridLines: false,
index c26435f65a1501b23f61d2cd991e811f2c20aaa2..0006a3dd16432cd7e8f498d827f87971ca0b0a0b 100644 (file)
@@ -1,7 +1,9 @@
 'use strict';
 
+
 describe('Chart.helpers.math', function() {
-       var factorize = Chart.helpers.math._factorize;
+       var math = Chart.helpers.math;
+       var factorize = math._factorize;
 
        it('should factorize', function() {
                expect(factorize(1000)).toEqual([1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500]);
@@ -13,4 +15,14 @@ describe('Chart.helpers.math', function() {
                expect(factorize(-1)).toEqual([]);
                expect(factorize(2.76)).toEqual([]);
        });
+
+       it('should do a log10 operation', function() {
+               expect(math.log10(0)).toBe(-Infinity);
+
+               // Check all allowed powers of 10, which should return integer values
+               var maxPowerOf10 = Math.floor(math.log10(Number.MAX_VALUE));
+               for (var i = 0; i < maxPowerOf10; i += 1) {
+                       expect(math.log10(Math.pow(10, i))).toBe(i);
+               }
+       });
 });
index 9af5c9cb950d350e6b333b52a00ae56a9b7f9f69..30f35cbaf98fdaa35f8c42b02cf1518cec270259 100644 (file)
@@ -1196,4 +1196,86 @@ describe('Linear Scale', function() {
                expect(chart.scales.yScale0).not.toEqual(undefined); // must construct
                expect(chart.scales.yScale0.max).toBeGreaterThan(chart.scales.yScale0.min);
        });
+
+       it('Should get correct pixel values when horizontal', function() {
+               var chart = window.acquireChart({
+                       type: 'horizontalBar',
+                       data: {
+                               datasets: [{
+                                       data: [0.05, -25, 10, 15, 20, 25, 30, 35]
+                               }]
+                       },
+                       options: {
+                               scales: {
+                                       xAxes: [{
+                                               id: 'x',
+                                               type: 'linear',
+                                       }]
+                               }
+                       }
+               });
+
+               var start = chart.chartArea.left;
+               var end = chart.chartArea.right;
+               var min = -30;
+               var max = 40;
+               var scale = chart.scales.x;
+
+               expect(scale.getPixelForValue(max)).toBeCloseToPixel(end);
+               expect(scale.getPixelForValue(min)).toBeCloseToPixel(start);
+               expect(scale.getValueForPixel(end)).toBeCloseTo(max, 4);
+               expect(scale.getValueForPixel(start)).toBeCloseTo(min, 4);
+
+               scale.options.ticks.reverse = true;
+               chart.update();
+
+               start = chart.chartArea.left;
+               end = chart.chartArea.right;
+
+               expect(scale.getPixelForValue(max)).toBeCloseToPixel(start);
+               expect(scale.getPixelForValue(min)).toBeCloseToPixel(end);
+               expect(scale.getValueForPixel(end)).toBeCloseTo(min, 4);
+               expect(scale.getValueForPixel(start)).toBeCloseTo(max, 4);
+       });
+
+       it('Should get correct pixel values when vertical', function() {
+               var chart = window.acquireChart({
+                       type: 'bar',
+                       data: {
+                               datasets: [{
+                                       data: [0.05, -25, 10, 15, 20, 25, 30, 35]
+                               }]
+                       },
+                       options: {
+                               scales: {
+                                       yAxes: [{
+                                               id: 'y',
+                                               type: 'linear',
+                                       }]
+                               }
+                       }
+               });
+
+               var start = chart.chartArea.bottom;
+               var end = chart.chartArea.top;
+               var min = -30;
+               var max = 40;
+               var scale = chart.scales.y;
+
+               expect(scale.getPixelForValue(max)).toBeCloseToPixel(end);
+               expect(scale.getPixelForValue(min)).toBeCloseToPixel(start);
+               expect(scale.getValueForPixel(end)).toBeCloseTo(max, 4);
+               expect(scale.getValueForPixel(start)).toBeCloseTo(min, 4);
+
+               scale.options.ticks.reverse = true;
+               chart.update();
+
+               start = chart.chartArea.bottom;
+               end = chart.chartArea.top;
+
+               expect(scale.getPixelForValue(max)).toBeCloseToPixel(start);
+               expect(scale.getPixelForValue(min)).toBeCloseToPixel(end);
+               expect(scale.getValueForPixel(end)).toBeCloseTo(min, 4);
+               expect(scale.getValueForPixel(start)).toBeCloseTo(max, 4);
+       });
 });
index dd7c7cce94a6b117304fe7530db0c0d7a8fe18dc..c1c048c7c0150921ba4efddc4ce33318f3027176 100644 (file)
@@ -862,6 +862,8 @@ describe('Logarithmic Scale tests', function() {
                                type: 'logarithmic'
                        }];
                        Chart.helpers.extend(scaleConfig, setup.scale);
+                       scaleConfig[setup.axis + 'Axes'][0].type = 'logarithmic';
+
                        var description = 'dataset has stack option and ' + setup.describe
                                + ' and axis is "' + setup.axis + '";';
                        describe(description, function() {
index 38b838726f1aec38ddf763af3836062b97f64942..6b8514ae4ac6c0c538d512099a1a0f55b10253a4 100755 (executable)
@@ -1551,11 +1551,11 @@ describe('Time scale tests', function() {
                                var firstTickInterval = scale.getPixelForTick(1) - scale.getPixelForTick(0);
                                var lastTickInterval = scale.getPixelForTick(numTicks - 1) - scale.getPixelForTick(numTicks - 2);
 
-                               expect(scale.getValueForPixel(scale.left + firstTickInterval / 2)).toBeCloseToTime({
+                               expect(scale.getValueForPixel(scale.left + lastTickInterval / 2)).toBeCloseToTime({
                                        value: moment('2042-01-01T00:00:00'),
                                        unit: 'hour',
                                });
-                               expect(scale.getValueForPixel(scale.left + scale.width - lastTickInterval / 2)).toBeCloseToTime({
+                               expect(scale.getValueForPixel(scale.left + scale.width - firstTickInterval / 2)).toBeCloseToTime({
                                        value: moment('2017-01-01T00:00:00'),
                                        unit: 'hour',
                                });