]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Fix the rounding issue of floating point numbers in category scale (#5880)
authorAkihiko Kusanagi <nagi@nagi-p.com>
Sun, 9 Dec 2018 10:34:34 +0000 (21:34 +1100)
committerSimon Brunel <simonbrunel@users.noreply.github.com>
Sun, 9 Dec 2018 10:34:34 +0000 (11:34 +0100)
- Remove `Math.round` in the category scale code
- Add `helpers._alignPixel` to align grid/tick/axis border lines
- Fix grid/tick/axis border line calculation
- Add a check of the width of the axis border
- Refactor core.scale code

16 files changed:
src/core/core.helpers.js
src/core/core.scale.js
src/core/core.tooltip.js
src/scales/scale.category.js
src/scales/scale.radialLinear.js
test/fixtures/controller.line/point-style.png
test/fixtures/controller.radar/point-style.png
test/fixtures/core.scale/tick-drawing.png
test/fixtures/core.tooltip/opacity.png
test/fixtures/scale.radialLinear/border-dash.png
test/fixtures/scale.radialLinear/indexable-gridlines.png
test/specs/core.scale.tests.js
test/specs/core.tooltip.tests.js
test/specs/global.deprecations.tests.js
test/specs/scale.category.tests.js
test/specs/scale.radialLinear.tests.js

index ca8a7d20c3860a45957a79b9816517eefeb610b2..a0b4b990b720230f9fcd5ba6575f0b90933c714f 100644 (file)
@@ -214,9 +214,31 @@ module.exports = function() {
        helpers.distanceBetweenPoints = function(pt1, pt2) {
                return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
        };
+
+       /**
+        * Provided for backward compatibility, not available anymore
+        * @function Chart.helpers.aliasPixel
+        * @deprecated since version 2.8.0
+        * @todo remove at version 3
+        */
        helpers.aliasPixel = function(pixelWidth) {
                return (pixelWidth % 2 === 0) ? 0 : 0.5;
        };
+
+       /**
+        * Returns the aligned pixel value to avoid anti-aliasing blur
+        * @param {Chart} chart - The chart instance.
+        * @param {Number} pixel - A pixel value.
+        * @param {Number} width - The width of the element.
+        * @returns {Number} The aligned pixel value.
+        * @private
+        */
+       helpers._alignPixel = function(chart, pixel, width) {
+               var devicePixelRatio = chart.currentDevicePixelRatio;
+               var halfWidth = width / 2;
+               return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth;
+       };
+
        helpers.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {
                // Props to Rob Spencer at scaled innovation for his post on splining between points
                // http://scaledinnovation.com/analytics/splines/aboutSplines.html
index 8f7df0021620c7057a2e836250a30466e15b2c2e..02e36d99051ba9d8191c4dcb3b6f8d133214ccbe 100644 (file)
@@ -586,7 +586,7 @@ module.exports = Element.extend({
                                pixel += tickWidth / 2;
                        }
 
-                       var finalVal = me.left + Math.round(pixel);
+                       var finalVal = me.left + pixel;
                        finalVal += me.isFullWidth() ? me.margins.left : 0;
                        return finalVal;
                }
@@ -604,7 +604,7 @@ module.exports = Element.extend({
                        var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
                        var valueOffset = (innerWidth * decimal) + me.paddingLeft;
 
-                       var finalVal = me.left + Math.round(valueOffset);
+                       var finalVal = me.left + valueOffset;
                        finalVal += me.isFullWidth() ? me.margins.left : 0;
                        return finalVal;
                }
@@ -689,14 +689,17 @@ module.exports = Element.extend({
                        return;
                }
 
+               var chart = me.chart;
                var context = me.ctx;
                var globalDefaults = defaults.global;
                var optionTicks = options.ticks.minor;
                var optionMajorTicks = options.ticks.major || optionTicks;
                var gridLines = options.gridLines;
                var scaleLabel = options.scaleLabel;
+               var position = options.position;
 
                var isRotated = me.labelRotation !== 0;
+               var isMirrored = optionTicks.mirror;
                var isHorizontal = me.isHorizontal();
 
                var ticks = optionTicks.autoSkip ? me._autoSkip(me.getTicks()) : me.getTicks();
@@ -704,6 +707,8 @@ module.exports = Element.extend({
                var tickFont = parseFontOptions(optionTicks);
                var majorTickFontColor = helpers.valueOrDefault(optionMajorTicks.fontColor, globalDefaults.defaultFontColor);
                var majorTickFont = parseFontOptions(optionMajorTicks);
+               var tickPadding = optionTicks.padding;
+               var labelOffset = optionTicks.labelOffset;
 
                var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0;
 
@@ -714,11 +719,27 @@ module.exports = Element.extend({
 
                var itemsToDraw = [];
 
-               var axisWidth = helpers.valueAtIndexOrDefault(me.options.gridLines.lineWidth, 0);
-               var xTickStart = options.position === 'right' ? me.left : me.right - axisWidth - tl;
-               var xTickEnd = options.position === 'right' ? me.left + tl : me.right;
-               var yTickStart = options.position === 'bottom' ? me.top + axisWidth : me.bottom - tl - axisWidth;
-               var yTickEnd = options.position === 'bottom' ? me.top + axisWidth + tl : me.bottom + axisWidth;
+               var axisWidth = gridLines.drawBorder ? helpers.valueAtIndexOrDefault(gridLines.lineWidth, 0, 0) : 0;
+               var alignPixel = helpers._alignPixel;
+               var borderValue, tickStart, tickEnd;
+
+               if (position === 'top') {
+                       borderValue = alignPixel(chart, me.bottom, axisWidth);
+                       tickStart = me.bottom - tl;
+                       tickEnd = borderValue - axisWidth / 2;
+               } else if (position === 'bottom') {
+                       borderValue = alignPixel(chart, me.top, axisWidth);
+                       tickStart = borderValue + axisWidth / 2;
+                       tickEnd = me.top + tl;
+               } else if (position === 'left') {
+                       borderValue = alignPixel(chart, me.right, axisWidth);
+                       tickStart = me.right - tl;
+                       tickEnd = borderValue - axisWidth / 2;
+               } else {
+                       borderValue = alignPixel(chart, me.left, axisWidth);
+                       tickStart = borderValue + axisWidth / 2;
+                       tickEnd = me.left + tl;
+               }
 
                var epsilon = 0.0000001; // 0.0000001 is margin in pixels for Accumulated error.
 
@@ -744,66 +765,58 @@ module.exports = Element.extend({
                        }
 
                        // Common properties
-                       var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY;
-                       var textAlign = 'middle';
+                       var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY, textAlign;
                        var textBaseline = 'middle';
-                       var tickPadding = optionTicks.padding;
+                       var lineValue = getPixelForGridLine(me, index, gridLines.offsetGridLines);
 
                        if (isHorizontal) {
                                var labelYOffset = tl + tickPadding;
 
-                               if (options.position === 'bottom') {
-                                       // bottom
-                                       textBaseline = !isRotated ? 'top' : 'middle';
-                                       textAlign = !isRotated ? 'center' : 'right';
-                                       labelY = me.top + labelYOffset;
-                               } else {
-                                       // top
-                                       textBaseline = !isRotated ? 'bottom' : 'middle';
-                                       textAlign = !isRotated ? 'center' : 'left';
-                                       labelY = me.bottom - labelYOffset;
-                               }
-
-                               var xLineValue = getPixelForGridLine(me, index, gridLines.offsetGridLines);
-                               if (xLineValue < me.left - epsilon) {
+                               if (lineValue < me.left - epsilon) {
                                        lineColor = 'rgba(0,0,0,0)';
                                }
-                               xLineValue += helpers.aliasPixel(lineWidth);
-
-                               labelX = me.getPixelForTick(index) + optionTicks.labelOffset; // x values for optionTicks (need to consider offsetLabel option)
 
-                               tx1 = tx2 = x1 = x2 = xLineValue;
-                               ty1 = yTickStart;
-                               ty2 = yTickEnd;
-                               y1 = chartArea.top;
-                               y2 = chartArea.bottom + axisWidth;
-                       } else {
-                               var isLeft = options.position === 'left';
-                               var labelXOffset;
+                               tx1 = tx2 = x1 = x2 = alignPixel(chart, lineValue, lineWidth);
+                               ty1 = tickStart;
+                               ty2 = tickEnd;
+                               labelX = me.getPixelForTick(index) + labelOffset; // x values for optionTicks (need to consider offsetLabel option)
 
-                               if (optionTicks.mirror) {
-                                       textAlign = isLeft ? 'left' : 'right';
-                                       labelXOffset = tickPadding;
+                               if (position === 'top') {
+                                       y1 = alignPixel(chart, chartArea.top, axisWidth) + axisWidth / 2;
+                                       y2 = chartArea.bottom;
+                                       textBaseline = !isRotated ? 'bottom' : 'middle';
+                                       textAlign = !isRotated ? 'center' : 'left';
+                                       labelY = me.bottom - labelYOffset;
                                } else {
-                                       textAlign = isLeft ? 'right' : 'left';
-                                       labelXOffset = tl + tickPadding;
+                                       y1 = chartArea.top;
+                                       y2 = alignPixel(chart, chartArea.bottom, axisWidth) - axisWidth / 2;
+                                       textBaseline = !isRotated ? 'top' : 'middle';
+                                       textAlign = !isRotated ? 'center' : 'right';
+                                       labelY = me.top + labelYOffset;
                                }
+                       } else {
+                               var labelXOffset = (isMirrored ? 0 : tl) + tickPadding;
 
-                               labelX = isLeft ? me.right - labelXOffset : me.left + labelXOffset;
-
-                               var yLineValue = getPixelForGridLine(me, index, gridLines.offsetGridLines);
-                               if (yLineValue < me.top - epsilon) {
+                               if (lineValue < me.top - epsilon) {
                                        lineColor = 'rgba(0,0,0,0)';
                                }
-                               yLineValue += helpers.aliasPixel(lineWidth);
 
-                               labelY = me.getPixelForTick(index) + optionTicks.labelOffset;
+                               tx1 = tickStart;
+                               tx2 = tickEnd;
+                               ty1 = ty2 = y1 = y2 = alignPixel(chart, lineValue, lineWidth);
+                               labelY = me.getPixelForTick(index) + labelOffset;
 
-                               tx1 = xTickStart;
-                               tx2 = xTickEnd;
-                               x1 = chartArea.left;
-                               x2 = chartArea.right + axisWidth;
-                               ty1 = ty2 = y1 = y2 = yLineValue;
+                               if (position === 'left') {
+                                       x1 = alignPixel(chart, chartArea.left, axisWidth) + axisWidth / 2;
+                                       x2 = chartArea.right;
+                                       textAlign = isMirrored ? 'left' : 'right';
+                                       labelX = me.right - labelXOffset;
+                               } else {
+                                       x1 = chartArea.left;
+                                       x2 = alignPixel(chart, chartArea.right, axisWidth) - axisWidth / 2;
+                                       textAlign = isMirrored ? 'right' : 'left';
+                                       labelX = me.left + labelXOffset;
+                               }
                        }
 
                        itemsToDraw.push({
@@ -873,7 +886,7 @@ module.exports = Element.extend({
                                if (helpers.isArray(label)) {
                                        var lineCount = label.length;
                                        var lineHeight = tickFont.size * 1.5;
-                                       var y = me.isHorizontal() ? 0 : -lineHeight * (lineCount - 1) / 2;
+                                       var y = isHorizontal ? 0 : -lineHeight * (lineCount - 1) / 2;
 
                                        for (var i = 0; i < lineCount; ++i) {
                                                // We just make sure the multiline element is a string here..
@@ -897,11 +910,11 @@ module.exports = Element.extend({
 
                        if (isHorizontal) {
                                scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
-                               scaleLabelY = options.position === 'bottom'
+                               scaleLabelY = position === 'bottom'
                                        ? me.bottom - halfLineHeight - scaleLabelPadding.bottom
                                        : me.top + halfLineHeight + scaleLabelPadding.top;
                        } else {
-                               var isLeft = options.position === 'left';
+                               var isLeft = position === 'left';
                                scaleLabelX = isLeft
                                        ? me.left + halfLineHeight + scaleLabelPadding.top
                                        : me.right - halfLineHeight - scaleLabelPadding.top;
@@ -920,26 +933,24 @@ module.exports = Element.extend({
                        context.restore();
                }
 
-               if (gridLines.drawBorder) {
+               if (axisWidth) {
                        // Draw the line at the edge of the axis
-                       context.lineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, 0);
-                       context.strokeStyle = helpers.valueAtIndexOrDefault(gridLines.color, 0);
-                       var x1 = me.left;
-                       var x2 = me.right + axisWidth;
-                       var y1 = me.top;
-                       var y2 = me.bottom + axisWidth;
+                       var firstLineWidth = axisWidth;
+                       var lastLineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, ticks.length - 1, 0);
+                       var x1, x2, y1, y2;
 
-                       var aliasPixel = helpers.aliasPixel(context.lineWidth);
                        if (isHorizontal) {
-                               y1 = y2 = options.position === 'top' ? me.bottom : me.top;
-                               y1 += aliasPixel;
-                               y2 += aliasPixel;
+                               x1 = alignPixel(chart, me.left, firstLineWidth) - firstLineWidth / 2;
+                               x2 = alignPixel(chart, me.right, lastLineWidth) + lastLineWidth / 2;
+                               y1 = y2 = borderValue;
                        } else {
-                               x1 = x2 = options.position === 'left' ? me.right : me.left;
-                               x1 += aliasPixel;
-                               x2 += aliasPixel;
+                               y1 = alignPixel(chart, me.top, firstLineWidth) - firstLineWidth / 2;
+                               y2 = alignPixel(chart, me.bottom, lastLineWidth) + lastLineWidth / 2;
+                               x1 = x2 = borderValue;
                        }
 
+                       context.lineWidth = axisWidth;
+                       context.strokeStyle = helpers.valueAtIndexOrDefault(gridLines.color, 0);
                        context.beginPath();
                        context.moveTo(x1, y1);
                        context.lineTo(x2, y2);
index c3245d9cf1eccf99cb0267cf4293d6e34a6a8fc2..b135bbc923a1c31e8449d39214fa838aea1afe8c 100644 (file)
@@ -124,8 +124,8 @@ var positioners = {
                }
 
                return {
-                       x: Math.round(x / count),
-                       y: Math.round(y / count)
+                       x: x / count,
+                       y: y / count
                };
        },
 
@@ -619,8 +619,8 @@ var exports = module.exports = Element.extend({
                        model.footer = me.getFooter(tooltipItems, data);
 
                        // Initial positioning and colors
-                       model.x = Math.round(tooltipPosition.x);
-                       model.y = Math.round(tooltipPosition.y);
+                       model.x = tooltipPosition.x;
+                       model.y = tooltipPosition.y;
                        model.caretPadding = opts.caretPadding;
                        model.labelColors = labelColors;
                        model.labelTextColors = labelTextColors;
index dd8b01783bfebf692e8283ad4465ccbbe33d4921..33a91f3a2c6da3d132c0e4ee2a3b2609efd685fb 100644 (file)
@@ -90,7 +90,7 @@ module.exports = function() {
                                        widthOffset += (valueWidth / 2);
                                }
 
-                               return me.left + Math.round(widthOffset);
+                               return me.left + widthOffset;
                        }
                        var valueHeight = me.height / offsetAmt;
                        var heightOffset = (valueHeight * (index - me.minIndex));
@@ -99,7 +99,7 @@ module.exports = function() {
                                heightOffset += (valueHeight / 2);
                        }
 
-                       return me.top + Math.round(heightOffset);
+                       return me.top + heightOffset;
                },
                getPixelForTick: function(index) {
                        return this.getPixelForValue(this.ticks[index], index + this.minIndex, null);
index 71e156e0f091cb4cc05a853c85c465922c9dfb00..4a76a773c40956d30d4cb3e7053b1be8079255a7 100644 (file)
@@ -477,8 +477,8 @@ module.exports = function(Chart) {
                        var me = this;
                        var thisAngle = me.getIndexAngle(index) - (Math.PI / 2);
                        return {
-                               x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + me.xCenter,
-                               y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + me.yCenter
+                               x: Math.cos(thisAngle) * distanceFromCenter + me.xCenter,
+                               y: Math.sin(thisAngle) * distanceFromCenter + me.yCenter
                        };
                },
                getPointPositionForValue: function(index, value) {
index d8b6ed6b47526a4e54662fda7781dadd67d9e4e4..8faa96e4ab2ab05f2d328e4cc35ec19f5d542c7c 100644 (file)
Binary files a/test/fixtures/controller.line/point-style.png and b/test/fixtures/controller.line/point-style.png differ
index c5437ed24affbc9078ab004a6d0db2c5f7fdf5a0..c64bf330755377abdca1aac7fc18d0c94a5269fa 100644 (file)
Binary files a/test/fixtures/controller.radar/point-style.png and b/test/fixtures/controller.radar/point-style.png differ
index fb80cd0123293cde8b79ec2b63b9f9c25c589573..b59f3a6f94776ea790e3cd7e7bc8780da4dbfa45 100644 (file)
Binary files a/test/fixtures/core.scale/tick-drawing.png and b/test/fixtures/core.scale/tick-drawing.png differ
index 142dcc05f60fb6f966594da191fb7c8b109c23ea..8571abc38eb96ab3c7dca05bc9bb99a26d7f10e2 100644 (file)
Binary files a/test/fixtures/core.tooltip/opacity.png and b/test/fixtures/core.tooltip/opacity.png differ
index eea0db5ff007aeccdbf4403974f9c10d0ce15747..b7bacfad7c42c8fcf903c3c6d1b0394cd41c776c 100644 (file)
Binary files a/test/fixtures/scale.radialLinear/border-dash.png and b/test/fixtures/scale.radialLinear/border-dash.png differ
index c6b9d87e89a9535cd6eee87e13bf0c6d9b123752..02c0268d879c8a50b7af8330175d6b45ba3f1643 100644 (file)
Binary files a/test/fixtures/scale.radialLinear/indexable-gridlines.png and b/test/fixtures/scale.radialLinear/indexable-gridlines.png differ
index 573c132ae0793c55c50237749db5f416ccdbd10d..20890bb77204d5afe85f9650436b5665b99926c2 100644 (file)
@@ -29,7 +29,7 @@ describe('Core.scale', function() {
                labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'],
                offsetGridLines: false,
                offset: true,
-               expected: [51.5, 154.5, 256.5, 358.5, 461.5]
+               expected: [51.5, 153.5, 256.5, 358.5, 460.5]
        }, {
                labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'],
                offsetGridLines: true,
@@ -39,7 +39,7 @@ describe('Core.scale', function() {
                labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'],
                offsetGridLines: true,
                offset: true,
-               expected: [0, 103, 205.5, 307.5, 410]
+               expected: [-0.5, 102.5, 204.5, 307.5, 409.5]
        }, {
                labels: ['tick1'],
                offsetGridLines: false,
@@ -146,7 +146,7 @@ describe('Core.scale', function() {
                        chart.draw();
 
                        expect(yScale.ctx.getCalls().filter(function(x) {
-                               return x.name === 'moveTo' && x.args[0] === 0;
+                               return x.name === 'moveTo' && x.args[0] === 1;
                        }).map(function(x) {
                                return x.args[1];
                        })).toEqual(test.expected);
index c342fe64618ae4ccda114016e3e32f2c9a4b20e5..5ed898a0386a8b4763b9a784937436f17bf1b08e 100755 (executable)
@@ -145,7 +145,7 @@ describe('Core.Tooltip', function() {
                                }]
                        }));
 
-                       expect(tooltip._view.x).toBeCloseToPixel(266);
+                       expect(tooltip._view.x).toBeCloseToPixel(267);
                        expect(tooltip._view.y).toBeCloseToPixel(155);
                });
 
@@ -343,7 +343,7 @@ describe('Core.Tooltip', function() {
                        }]
                }));
 
-               expect(tooltip._view.x).toBeCloseToPixel(266);
+               expect(tooltip._view.x).toBeCloseToPixel(267);
                expect(tooltip._view.y).toBeCloseToPixel(312);
        });
 
@@ -576,7 +576,7 @@ describe('Core.Tooltip', function() {
                        }]
                }));
 
-               expect(tooltip._view.x).toBeCloseToPixel(266);
+               expect(tooltip._view.x).toBeCloseToPixel(267);
                expect(tooltip._view.y).toBeCloseToPixel(155);
        });
 
index 6992f23cf1ee2ab4daeb60b99c94829d20d758a3..eeda99f4b0a6241e3c50fba065a4c1c0386ed1e0 100644 (file)
@@ -24,6 +24,13 @@ describe('Deprecations', function() {
                                });
                        });
                });
+
+               describe('Chart.helpers.aliasPixel', function() {
+                       it('should be defined and a function', function() {
+                               expect(Chart.helpers.aliasPixel).toBeDefined();
+                               expect(typeof Chart.helpers.aliasPixel).toBe('function');
+                       });
+               });
        });
 
        describe('Version 2.7.3', function() {
index b4e8b08d04492c20052b0ae2bd4d244d0b81625b..0ce39e5b33c3edac00467bca37a20cd493c250d1 100644 (file)
@@ -328,19 +328,19 @@ describe('Category scale tests', function() {
                });
 
                var yScale = chart.scales.yScale0;
-               expect(yScale.getPixelForValue(0, 0, 0)).toBe(32);
+               expect(yScale.getPixelForValue(0, 0, 0)).toBeCloseToPixel(32);
                expect(yScale.getValueForPixel(32)).toBe(0);
 
-               expect(yScale.getPixelForValue(0, 4, 0)).toBe(484);
+               expect(yScale.getPixelForValue(0, 4, 0)).toBeCloseToPixel(484);
                expect(yScale.getValueForPixel(484)).toBe(4);
 
                yScale.options.offset = true;
                chart.update();
 
-               expect(yScale.getPixelForValue(0, 0, 0)).toBe(77);
+               expect(yScale.getPixelForValue(0, 0, 0)).toBeCloseToPixel(77);
                expect(yScale.getValueForPixel(77)).toBe(0);
 
-               expect(yScale.getPixelForValue(0, 4, 0)).toBe(439);
+               expect(yScale.getPixelForValue(0, 4, 0)).toBeCloseToPixel(439);
                expect(yScale.getValueForPixel(439)).toBe(4);
        });
 
@@ -378,13 +378,13 @@ describe('Category scale tests', function() {
 
                var yScale = chart.scales.yScale0;
 
-               expect(yScale.getPixelForValue(0, 1, 0)).toBe(32);
-               expect(yScale.getPixelForValue(0, 3, 0)).toBe(484);
+               expect(yScale.getPixelForValue(0, 1, 0)).toBeCloseToPixel(32);
+               expect(yScale.getPixelForValue(0, 3, 0)).toBeCloseToPixel(484);
 
                yScale.options.offset = true;
                chart.update();
 
-               expect(yScale.getPixelForValue(0, 1, 0)).toBe(107);
-               expect(yScale.getPixelForValue(0, 3, 0)).toBe(409);
+               expect(yScale.getPixelForValue(0, 1, 0)).toBeCloseToPixel(107);
+               expect(yScale.getPixelForValue(0, 3, 0)).toBeCloseToPixel(409);
        });
 });
index da19f9e000d25dfa803c4835f56036dfb58a3d4a..5459eac311f24707d25c8b2fccb3bb64b414e8a8 100644 (file)
@@ -398,10 +398,10 @@ describe('Test the radial linear scale', function() {
 
                expect(chart.scale.getDistanceFromCenterForValue(chart.scale.min)).toBe(0);
                expect(chart.scale.getDistanceFromCenterForValue(chart.scale.max)).toBe(232);
-               expect(chart.scale.getPointPositionForValue(1, 5)).toEqual({
-                       x: 270,
-                       y: 275,
-               });
+
+               var position = chart.scale.getPointPositionForValue(1, 5);
+               expect(position.x).toBeCloseToPixel(270);
+               expect(position.y).toBeCloseToPixel(275);
 
                chart.scale.options.ticks.reverse = true;
                chart.update();