Skip to content

Commit 637c217

Browse files
nagixsimonbrunel
authored andcommitted
Support decimal stepSize (#5786)
1 parent 7e62913 commit 637c217

File tree

4 files changed

+84
-23
lines changed

4 files changed

+84
-23
lines changed

src/core/core.helpers.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,26 @@ module.exports = function() {
174174
helpers.toDegrees = function(radians) {
175175
return radians * (180 / Math.PI);
176176
};
177+
178+
/**
179+
* Returns the number of decimal places
180+
* i.e. the number of digits after the decimal point, of the value of this Number.
181+
* @param {Number} x - A number.
182+
* @returns {Number} The number of decimal places.
183+
*/
184+
helpers.decimalPlaces = function(x) {
185+
if (!helpers.isFinite(x)) {
186+
return;
187+
}
188+
var e = 1;
189+
var p = 0;
190+
while (Math.round(x * e) / e !== x) {
191+
e *= 10;
192+
p++;
193+
}
194+
return p;
195+
};
196+
177197
// Gets the angle from vertical upright to the point about a centre.
178198
helpers.getAngleFromPoint = function(centrePoint, anglePoint) {
179199
var distanceFromXCenter = anglePoint.x - centrePoint.x;

src/scales/scale.linearbase.js

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,54 +15,55 @@ function generateTicks(generationOptions, dataRange) {
1515
// "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
1616
// for details.
1717

18-
var factor;
19-
var precision;
20-
var spacing;
18+
var stepSize = generationOptions.stepSize;
19+
var min = generationOptions.min;
20+
var max = generationOptions.max;
21+
var spacing, precision, factor, niceRange, niceMin, niceMax, numSpaces;
2122

22-
if (generationOptions.stepSize && generationOptions.stepSize > 0) {
23-
spacing = generationOptions.stepSize;
23+
if (stepSize && stepSize > 0) {
24+
spacing = stepSize;
2425
} else {
25-
var niceRange = helpers.niceNum(dataRange.max - dataRange.min, false);
26+
niceRange = helpers.niceNum(dataRange.max - dataRange.min, false);
2627
spacing = helpers.niceNum(niceRange / (generationOptions.maxTicks - 1), true);
2728

2829
precision = generationOptions.precision;
29-
if (precision !== undefined) {
30+
if (!helpers.isNullOrUndef(precision)) {
3031
// If the user specified a precision, round to that number of decimal places
3132
factor = Math.pow(10, precision);
3233
spacing = Math.ceil(spacing * factor) / factor;
3334
}
3435
}
35-
var niceMin = Math.floor(dataRange.min / spacing) * spacing;
36-
var niceMax = Math.ceil(dataRange.max / spacing) * spacing;
36+
// If a precision is not specified, calculate factor based on spacing
37+
if (!factor) {
38+
factor = Math.pow(10, helpers.decimalPlaces(spacing));
39+
}
40+
niceMin = Math.floor(dataRange.min / spacing) * spacing;
41+
niceMax = Math.ceil(dataRange.max / spacing) * spacing;
3742

3843
// If min, max and stepSize is set and they make an evenly spaced scale use it.
39-
if (!helpers.isNullOrUndef(generationOptions.min) && !helpers.isNullOrUndef(generationOptions.max) && generationOptions.stepSize) {
44+
if (!helpers.isNullOrUndef(min) && !helpers.isNullOrUndef(max) && stepSize) {
4045
// If very close to our whole number, use it.
41-
if (helpers.almostWhole((generationOptions.max - generationOptions.min) / generationOptions.stepSize, spacing / 1000)) {
42-
niceMin = generationOptions.min;
43-
niceMax = generationOptions.max;
46+
if (helpers.almostWhole((max - min) / stepSize, spacing / 1000)) {
47+
niceMin = min;
48+
niceMax = max;
4449
}
4550
}
4651

47-
var numSpaces = (niceMax - niceMin) / spacing;
52+
numSpaces = (niceMax - niceMin) / spacing;
4853
// If very close to our rounded value, use it.
4954
if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
5055
numSpaces = Math.round(numSpaces);
5156
} else {
5257
numSpaces = Math.ceil(numSpaces);
5358
}
5459

55-
precision = 1;
56-
if (spacing < 1) {
57-
precision = Math.pow(10, 1 - Math.floor(helpers.log10(spacing)));
58-
niceMin = Math.round(niceMin * precision) / precision;
59-
niceMax = Math.round(niceMax * precision) / precision;
60-
}
61-
ticks.push(generationOptions.min !== undefined ? generationOptions.min : niceMin);
60+
niceMin = Math.round(niceMin * factor) / factor;
61+
niceMax = Math.round(niceMax * factor) / factor;
62+
ticks.push(helpers.isNullOrUndef(min) ? niceMin : min);
6263
for (var j = 1; j < numSpaces; ++j) {
63-
ticks.push(Math.round((niceMin + j * spacing) * precision) / precision);
64+
ticks.push(Math.round((niceMin + j * spacing) * factor) / factor);
6465
}
65-
ticks.push(generationOptions.max !== undefined ? generationOptions.max : niceMax);
66+
ticks.push(helpers.isNullOrUndef(max) ? niceMax : max);
6667

6768
return ticks;
6869
}

test/specs/core.helpers.tests.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,17 @@ describe('Core helper tests', function() {
238238
expect(helpers.toDegrees(Math.PI * 3 / 2)).toBe(270);
239239
});
240240

241+
it('should get the correct number of decimal places', function() {
242+
expect(helpers.decimalPlaces(100)).toBe(0);
243+
expect(helpers.decimalPlaces(1)).toBe(0);
244+
expect(helpers.decimalPlaces(0)).toBe(0);
245+
expect(helpers.decimalPlaces(0.01)).toBe(2);
246+
expect(helpers.decimalPlaces(-0.01)).toBe(2);
247+
expect(helpers.decimalPlaces('1')).toBe(undefined);
248+
expect(helpers.decimalPlaces('')).toBe(undefined);
249+
expect(helpers.decimalPlaces(undefined)).toBe(undefined);
250+
});
251+
241252
it('should get an angle from a point', function() {
242253
var center = {
243254
x: 0,

test/specs/scale.linear.tests.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,35 @@ describe('Linear Scale', function() {
573573
expect(chart.scales.yScale0.ticks).toEqual(['11', '9', '7', '5', '3', '1']);
574574
});
575575

576+
it('Should create decimal steps if stepSize is a decimal number', function() {
577+
var chart = window.acquireChart({
578+
type: 'bar',
579+
data: {
580+
datasets: [{
581+
yAxisID: 'yScale0',
582+
data: [10, 3, 6, 8, 3, 1]
583+
}],
584+
labels: ['a', 'b', 'c', 'd', 'e', 'f']
585+
},
586+
options: {
587+
scales: {
588+
yAxes: [{
589+
id: 'yScale0',
590+
type: 'linear',
591+
ticks: {
592+
stepSize: 2.5
593+
}
594+
}]
595+
}
596+
}
597+
});
598+
599+
expect(chart.scales.yScale0).not.toEqual(undefined); // must construct
600+
expect(chart.scales.yScale0.min).toBe(0);
601+
expect(chart.scales.yScale0.max).toBe(10);
602+
expect(chart.scales.yScale0.ticks).toEqual(['10', '7.5', '5', '2.5', '0']);
603+
});
604+
576605
describe('precision', function() {
577606
it('Should create integer steps if precision is 0', function() {
578607
var chart = window.acquireChart({

0 commit comments

Comments
 (0)